use std::io::{self, Write};
use crossterm::{
    event::{self, Event, KeyCode, KeyEventKind},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Alignment, Constraint, Direction, Layout},
    style::{Color, Modifier, Style},
    text::{Span, Spans},
    widgets::{Block, Borders, Paragraph, Wrap},
    Terminal,
};
use std::time::{Duration, Instant};

// 游戏主类
struct ChoiceGame {
    current_screen: ScreenType,
    main_menu_selected: usize,
    adventure_selected: usize,
    quiz_selected: usize,
    random_event_selected: usize,
    game_state: GameState,
}

// 屏幕类型枚举
enum ScreenType {
    MainMenu,
    Adventure,
    Quiz,
    RandomEvent,
    Result(String),
}

// 游戏状态
struct GameState {
    score: i32,
    health: i32,
    steps: i32,
}

impl ChoiceGame {
    // 初始化游戏
    fn new() -> Self {
        Self {
            current_screen: ScreenType::MainMenu,
            main_menu_selected: 0,
            adventure_selected: 0,
            quiz_selected: 0,
            random_event_selected: 0,
            game_state: GameState {
                score: 0,
                health: 100,
                steps: 0,
            },
        }
    }

    // 运行游戏主循环
    fn run(&mut self) -> io::Result<()> {
        // 初始化终端
        enable_raw_mode()?;
        let mut stdout = io::stdout();
        execute!(stdout, EnterAlternateScreen)?;
        let backend = CrosstermBackend::new(stdout);
        let mut terminal = Terminal::new(backend)?;
        terminal.clear()?;

        // 游戏主循环
        let mut last_update = Instant::now();
        loop {
            // 绘制界面
            terminal.draw(|f| self.draw(f))?;

            // 处理输入
            if event::poll(Duration::from_millis(50))? {
                if let Event::Key(event) = event::read()? {
                    if event.kind == KeyEventKind::Press {
                        match event.code {
                            KeyCode::Up => self.handle_up(),
                            KeyCode::Down => self.handle_down(),
                            KeyCode::Enter => self.handle_enter(),
                            KeyCode::Esc => break,
                            _ => {}
                        }
                    }
                }
            }

            // 随机事件定时触发
            if let ScreenType::Adventure | ScreenType::RandomEvent = self.current_screen {
                if last_update.elapsed() > Duration::from_secs(30) {
                    self.game_state.steps += 1;
                    if self.game_state.steps % 5 == 0 {
                        self.current_screen = ScreenType::Result(
                            format!("时间过去了很久,你的体力下降了!健康值: {}", 
                                {self.game_state.health -= 10; self.game_state.health})
                        );
                    }
                    last_update = Instant::now();
                }
            }
        }

        // 恢复终端状态
        disable_raw_mode()?;
        execute!(
            terminal.backend_mut(),
            LeaveAlternateScreen
        )?;
        terminal.show_cursor()?;

        Ok(())
    }

    // 处理上方向键
    fn handle_up(&mut self) {
        match self.current_screen {
            ScreenType::MainMenu => {
                self.main_menu_selected = if self.main_menu_selected == 0 {
                    self.get_main_menu_options().len() - 1
                } else {
                    self.main_menu_selected - 1
                };
            }
            ScreenType::Adventure => {
                self.adventure_selected = if self.adventure_selected == 0 {
                    self.get_adventure_options().len() - 1
                } else {
                    self.adventure_selected - 1
                };
            }
            ScreenType::Quiz => {
                self.quiz_selected = if self.quiz_selected == 0 {
                    self.get_quiz_options().len() - 1
                } else {
                    self.quiz_selected - 1
                };
            }
            ScreenType::RandomEvent => {
                self.random_event_selected = if self.random_event_selected == 0 {
                    self.get_random_event_options().len() - 1
                } else {
                    self.random_event_selected - 1
                };
            }
            ScreenType::Result(_) => {
                self.current_screen = ScreenType::MainMenu;
            }
        }
    }

    // 处理下方向键
    fn handle_down(&mut self) {
        match self.current_screen {
            ScreenType::MainMenu => {
                self.main_menu_selected = (self.main_menu_selected + 1) % self.get_main_menu_options().len();
            }
            ScreenType::Adventure => {
                self.adventure_selected = (self.adventure_selected + 1) % self.get_adventure_options().len();
            }
            ScreenType::Quiz => {
                self.quiz_selected = (self.quiz_selected + 1) % self.get_quiz_options().len();
            }
            ScreenType::RandomEvent => {
                self.random_event_selected = (self.random_event_selected + 1) % self.get_random_event_options().len();
            }
            ScreenType::Result(_) => {
                self.current_screen = ScreenType::MainMenu;
            }
        }
    }

    // 处理回车键
    fn handle_enter(&mut self) {
        match self.current_screen {
            ScreenType::MainMenu => {
                match self.main_menu_selected {
                    0 => self.current_screen = ScreenType::Adventure,
                    1 => self.current_screen = ScreenType::Quiz,
                    2 => self.current_screen = ScreenType::RandomEvent,
                    3 => {
                        // 退出游戏
                        std::process::exit(0);
                    }
                    _ => {}
                }
            }
            ScreenType::Adventure => {
                let result = match self.adventure_selected {
                    0 => {
                        self.game_state.score += 50;
                        "你选择了穿越森林,发现了宝藏!获得50分!".to_string()
                    }
                    1 => {
                        self.game_state.health -= 20;
                        format!("你选择了翻越高山,路途艰险,健康值减少20。当前健康值: {}", self.game_state.health)
                    }
                    2 => {
                        self.game_state.score += 30;
                        "你选择了沿着河流前进,找到了食物!获得30分!".to_string()
                    }
                    3 => {
                        self.current_screen = ScreenType::MainMenu;
                        return;
                    }
                    _ => "未知选择".to_string()
                };
                self.current_screen = ScreenType::Result(result);
            }
            ScreenType::Quiz => {
                let result = match self.quiz_selected {
                    0 => {
                        self.game_state.score += 100;
                        "正确!Rust是由Mozilla开发的。获得100分!".to_string()
                    }
                    1 => {
                        self.game_state.score -= 20;
                        "错误!Rust不是由Google开发的。扣20分!".to_string()
                    }
                    2 => {
                        self.game_state.score -= 20;
                        "错误!Rust不是由Microsoft开发的。扣20分!".to_string()
                    }
                    3 => {
                        self.current_screen = ScreenType::MainMenu;
                        return;
                    }
                    _ => "未知选择".to_string()
                };
                self.current_screen = ScreenType::Result(result);
            }
            ScreenType::RandomEvent => {
                let result = match self.random_event_selected {
                    0 => {
                        self.game_state.score += 70;
                        "你帮助了陌生人,获得了奖励!获得70分!".to_string()
                    }
                    1 => {
                        self.game_state.health -= 30;
                        format!("你选择无视,遭遇了不幸!健康值减少30。当前健康值: {}", self.game_state.health)
                    }
                    2 => {
                        self.game_state.score += 20;
                        "你谨慎观察后离开,发现了一些金币!获得20分!".to_string()
                    }
                    3 => {
                        self.current_screen = ScreenType::MainMenu;
                        return;
                    }
                    _ => "未知选择".to_string()
                };
                self.current_screen = ScreenType::Result(result);
            }
            ScreenType::Result(_) => {
                self.current_screen = ScreenType::MainMenu;
            }
        }
    }

    // 获取主菜单选项
    fn get_main_menu_options(&self) -> Vec<&str> {
        vec!["冒险模式", "答题挑战", "随机事件", "退出游戏"]
    }

    // 获取冒险模式选项
    fn get_adventure_options(&self) -> Vec<&str> {
        vec!["穿越森林", "翻越高山", "沿着河流前进", "返回主菜单"]
    }

    // 获取答题挑战选项
    fn get_quiz_options(&self) -> Vec<&str> {
        vec!["Mozilla", "Google", "Microsoft", "返回主菜单"]
    }

    // 获取随机事件选项
    fn get_random_event_options(&self) -> Vec<&str> {
        vec!["提供帮助", "视而不见", "谨慎观察", "返回主菜单"]
    }

    // 绘制界面
    fn draw<B: Backend>(&self, f: &mut tui::Frame<B>) {
        let size = f.size();
        
        // 创建主布局
        let main_layout = Layout::default()
            .direction(Direction::Vertical)
            .margin(1)
            .constraints(
                [
                    Constraint::Length(3),  // 标题区域
                    Constraint::Min(10),    // 内容区域
                    Constraint::Length(3),  // 状态区域
                ]
                .as_ref(),
            )
            .split(size);

        // 绘制标题
        let title = match self.current_screen {
            ScreenType::MainMenu => "选择对话框小游戏 - 主菜单",
            ScreenType::Adventure => "冒险模式",
            ScreenType::Quiz => "答题挑战 - Rust是由哪家公司开发的?",
            ScreenType::RandomEvent => "随机事件 - 你遇到了一个陌生人需要帮助",
            ScreenType::Result(_) => "结果反馈",
        };
        
        let title_block = Paragraph::new(title)
            .style(Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD))
            .alignment(Alignment::Center)
            .block(Block::default().borders(Borders::ALL).title("标题"));
        f.render_widget(title_block, main_layout[0]);

        // 绘制内容区域
        let content_block = Block::default().borders(Borders::ALL).title("内容");
        f.render_widget(content_block, main_layout[1]);
        
        // 内容区域内部布局
        let content_layout = Layout::default()
            .direction(Direction::Vertical)
            .margin(1)
            .constraints(
                std::iter::repeat(Constraint::Length(1))
                    .take(match self.current_screen {
                        ScreenType::MainMenu => self.get_main_menu_options().len(),
                        ScreenType::Adventure => self.get_adventure_options().len(),
                        ScreenType::Quiz => self.get_quiz_options().len(),
                        ScreenType::RandomEvent => self.get_random_event_options().len(),
                        ScreenType::Result(_) => 1,
                    })
                    .chain(std::iter::once(Constraint::Min(0)))
                    .collect::<Vec<_>>()
            )
            .split(main_layout[1]);

        // 根据当前屏幕类型绘制不同内容
        match self.current_screen {
            ScreenType::MainMenu => {
                self.get_main_menu_options().iter().enumerate().for_each(|(i, option)| {
                    let style = if i == self.main_menu_selected {
                        Style::default().fg(Color::Black).bg(Color::White).add_modifier(Modifier::BOLD)
                    } else {
                        Style::default().fg(Color::White)
                    };
                    let text = Spans::from(Span::styled(format!("  {}", option), style));
                    let paragraph = Paragraph::new(text).alignment(Alignment::Center);
                    f.render_widget(paragraph, content_layout[i]);
                });
            }
            ScreenType::Adventure => {
                self.get_adventure_options().iter().enumerate().for_each(|(i, option)| {
                    let style = if i == self.adventure_selected {
                        Style::default().fg(Color::Black).bg(Color::White).add_modifier(Modifier::BOLD)
                    } else {
                        Style::default().fg(Color::White)
                    };
                    let text = Spans::from(Span::styled(format!("  {}", option), style));
                    let paragraph = Paragraph::new(text).alignment(Alignment::Center);
                    f.render_widget(paragraph, content_layout[i]);
                });
            }
            ScreenType::Quiz => {
                self.get_quiz_options().iter().enumerate().for_each(|(i, option)| {
                    let style = if i == self.quiz_selected {
                        Style::default().fg(Color::Black).bg(Color::White).add_modifier(Modifier::BOLD)
                    } else {
                        Style::default().fg(Color::White)
                    };
                    let text = Spans::from(Span::styled(format!("  {}", option), style));
                    let paragraph = Paragraph::new(text).alignment(Alignment::Center);
                    f.render_widget(paragraph, content_layout[i]);
                });
            }
            ScreenType::RandomEvent => {
                self.get_random_event_options().iter().enumerate().for_each(|(i, option)| {
                    let style = if i == self.random_event_selected {
                        Style::default().fg(Color::Black).bg(Color::White).add_modifier(Modifier::BOLD)
                    } else {
                        Style::default().fg(Color::White)
                    };
                    let text = Spans::from(Span::styled(format!("  {}", option), style));
                    let paragraph = Paragraph::new(text).alignment(Alignment::Center);
                    f.render_widget(paragraph, content_layout[i]);
                });
            }
            ScreenType::Result(message) => {
                let text = Spans::from(Span::styled(message, Style::default().fg(Color::Green)));
                let paragraph = Paragraph::new(text)
                    .alignment(Alignment::Center)
                    .wrap(Wrap { trim: true });
                f.render_widget(paragraph, content_layout[0]);
                
                let hint = Spans::from(Span::styled("按上/下方向键返回主菜单", Style::default().fg(Color::Yellow)));
                let hint_paragraph = Paragraph::new(hint)
                    .alignment(Alignment::Center);
                f.render_widget(hint_paragraph, content_layout[1]);
            }
        }

        // 绘制状态区域
        let status_text = format!(
            " 分数: {} | 健康值: {} | 操作提示: 上下方向键选择,Enter确认,Esc退出 ",
            self.game_state.score, self.game_state.health
        );
        let status_block = Paragraph::new(status_text)
            .style(Style::default().fg(Color::Black).bg(Color::Cyan))
            .alignment(Alignment::Center)
            .block(Block::default().borders(Borders::ALL).title("状态"));
        f.render_widget(status_block, main_layout[2]);
    }
}

// 程序入口
fn main() -> io::Result<()> {
    let mut game = ChoiceGame::new();
    game.run()
}

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐