周日下午一口气刷了4集《最强大脑》,很久不看综艺,发现这个节目还挺有意思的,清北这些大佬确实有过人之处。在看视频过程中印象最深的一幕莫过于北大王心冉对阵清华张洗月,她们比的题目是盲拧一个二维的魔方,要求记住一个5x5的棋盘,然后凭闭眼凭感觉复原。这道题很难,一般人睁着眼都很难完成,闭着眼难度可想而知。
我自问是没有这能力闭眼复原棋盘的,但是我也想玩这个游戏,为此今天晚上花了几个小时给自己写了个简单版的游戏,边玩看能不能训练出她们这样的能力。
游戏界面很简陋,大致长下面这样吧
5x5的棋盘,每一行都是一个颜色,游戏开始时会随机打乱局面,选手要根据对每一行或每一列进行移动,如果能把棋盘复原就胜利了
简单打乱之后局面变成这样了
好晕,我不会玩了,完全没思路应该怎么走,认输吧,明棋我也不会。
接下来讲讲代码,代码很简单,总共200多行吧,以下是关键部分
fn main() -> Result>> { // Terminal initialization let stdout = io::stdout().into_raw_mode()?; let stdout = MouseTerminal::from(stdout); let stdout = AlternateScreen::from(stdout); let backend = TermionBackend::new(stdout); let mut terminal = Terminal::new(backend)?; terminal.hide_cursor()?; // Setup event handlers let events = Events::new(); let mofang_size = 5_usize; let colors: Vec = vec![ Color::Red, Color::Yellow, Color::Blue, Color::Green, Color::Cyan, ]; let mut color_matrix: Vec>> = vec![]; for i in 0..mofang_size { color_matrix.push(vec![colors[i]; mofang_size]); } let mut constraints = vec![]; for _i in 0..mofang_size { constraints.push(Constraint::Ratio(1, mofang_size as u32)); } let mut cur_row = 0; let mut cur_col = 0; let start_time = Instant::now(); loop { terminal.draw(|mut f| { let size = f.size(); let block = Block::default() .borders(Borders::ALL) .title("2D Mofang game") .border_type(BorderType::Rounded); f.render_widget(block, size); let chunks = Layout::default() .direction(Direction::Vertical) .constraints( [ Constraint::Percentage(10), Constraint::Percentage(80), Constraint::Percentage(10), ] .as_ref(), ) .split(f.size()); // render header { let chunks = Layout::default() .direction(Direction::Horizontal) .constraints( [ Constraint::Percentage(10), Constraint::Percentage(80), Constraint::Percentage(10), ] .as_ref(), ) .split(chunks[0]); let cur_time = Instant::now(); let time_passed = cur_time.duration_since(start_time).as_secs(); let time_str = format!("{} seconds passed!", time_passed); let s1 = &time_str; let t1 = [Text::raw(s1)]; let title = Paragraph::new(t1.iter()) .block(Block::default()) .alignment(Alignment::Center); f.render_widget(title, chunks[1]); } { let chunks = Layout::default() .direction(Direction::Horizontal) .constraints( [ Constraint::Percentage(10), Constraint::Percentage(80), Constraint::Percentage(10), ] .as_ref(), ) .split(chunks[1]); { let row_chunks = Layout::default() .direction(Direction::Vertical) .constraints(constraints.as_ref()) .split(chunks[1]); for (i, row_chunk) in row_chunks.into_iter().enumerate() { let col_chunks = Layout::default() .direction(Direction::Horizontal) .constraints(constraints.as_ref()) .split(row_chunk); for (j, col_chunk) in col_chunks.into_iter().enumerate() { let mut block = Block::default() .borders(Borders::ALL) .style(Style::default().bg(color_matrix[i][j])); if cur_row == i && cur_col == j { block = block.title("|--"); } else if cur_row == i { block = block.title("--"); } else if cur_col == j { block = block.title("|"); } f.render_widget(block, col_chunk); } } } } })?; if let Event::Input(key) = events.next()? { if key == Key::Char('q') { break; } else if key == Key::Down { if cur_row < mofang_size - 1 { cur_row += 1; } } else if key == Key::Up { if cur_row > 0 { cur_row -= 1; } } else if key == Key::Right { if cur_col < mofang_size - 1 { cur_col += 1; } } else if key == Key::Left { if cur_col > 0 { cur_col -= 1; } } else if key == Key::Char('a') { row_cycle(&mut color_matrix, cur_row); } else if key == Key::Char('s') { col_cycle(&mut color_matrix, cur_col); } } } Ok(())}fn row_cycle(color_matrix: &mut Vec>>, // 按行轮换一次颜色(左右轮换) let mut row = color_matrix[row_idx].clone(); let l = row.len(); let first = row[0]; for i in 0..l - 1 { row[i] = row[i + 1]; } row[l - 1] = first; color_matrix[row_idx] = row;}fn col_cycle(color_matrix: &mut Vec>>, // 按列轮换一次颜色(上下轮换) let l = color_matrix[0].len(); let first = color_matrix[0][col_idx]; for i in 0..l - 1 { color_matrix[i][col_idx] = color_matrix[i + 1][col_idx]; } color_matrix[l - 1][col_idx] = first;}
梳理一下思路:
初始化界面布局,也就是安排哪些地方放标题,哪些地方摆放棋盘
在该摆放棋盘的位置初始化一个5x5的棋盘
加上事件监听程序,也就是监听按键,当按下上下左右方向键的时候要移动目标行或列,当按下A或者S键的时候对行/列做一次轮换
编写轮换算法,这个其实是最简单的了,就是变换一个颜色矩阵
玩游戏很难做游戏是不是很简单?不过这种棋盘复原的问题用计算机解应该也可以,我搜索了一下相关算法,发现要用到MCTS算法,但是没找到现成的例子,感兴趣的小伙伴可以留言我们交流一下