如何将双人版Connect 4游戏改为玩家vs电脑模式?
实现Connect 4玩家vs电脑模式的解决方案
看起来你已经把玩家vs玩家的逻辑跑通了,卡在电脑自动落子的触发上——核心问题是你生成了随机数,但没在回合判断里跳过玩家输入的环节,直接让电脑执行选择。下面给你一步步修改的方案:
1. 给Board类添加游戏模式区分
首先在初始化方法里加一个模式参数,用来标记当前是玩家vs玩家(PVP)还是玩家vs电脑(PVE):
class Board attr_accessor :board attr_reader :turn, :identifier, :game_mode def initialize(game_mode = :pvp) @board = Array.new(6) { Array.new(7, nil) } # 标准Connect4是6行7列,你可以根据自己的棋盘调整 @turn = 1 @identifier = { 1: 'X', 2: 'O' } @game_mode = game_mode # 新增模式属性,:pvp或:pve end
2. 新增辅助方法:获取可用列
电脑不能选已经满了的列,所以先写个方法找出当前还能落子的列:
def available_columns # 检查每一列是否还有空位(第一行对应位置为空,说明列还没满) @board.first.each_index.select { |col| @board.first[col].nil? } end
3. 修改回合处理逻辑,触发电脑自动落子
原来的回合方法应该是在等待玩家输入,现在要加判断:如果是PVE模式且轮到电脑(玩家2),就自动选可用列中的随机一个,跳过玩家输入:
def take_turn(col = nil) if @game_mode == :pve && @turn == 2 # 电脑随机选一个可用列 col = available_columns.sample puts "电脑选择了第#{col + 1}列" # 给玩家反馈选了哪一列 else # 保留原来的玩家输入逻辑,只在玩家回合执行 until col && available_columns.include?(col) puts "玩家#{@turn},请选择列(1-7):" col = gets.chomp.to_i - 1 # 转成数组索引(因为用户输入1-7,对应0-6) end end # 通用落子逻辑:找到当前列最底部的空位 row = @board.rindex { |r| r[col].nil? } @board[row][col] = @identifier[@turn] # 切换回合 @turn = @turn == 1 ? 2 : 1 end
4. 启动游戏时让用户选择模式
在游戏的入口代码里,加个模式选择的逻辑,让玩家选PVP还是PVE:
puts "请选择游戏模式:" puts "1. 玩家vs玩家" puts "2. 玩家vs电脑" choice = gets.chomp.to_i game_mode = choice == 2 ? :pve : :pvp # 初始化棋盘并开始游戏循环 board = Board.new(game_mode) until board.winner? || board.full? # 假设你已经有判断赢家和平局的方法 board.render # 渲染棋盘的方法,你原来的代码里应该有实现 board.take_turn end # 游戏结束后的提示 if board.winner? winner = board.game_mode == :pve && board.winner == 2 ? "电脑" : "玩家#{board.winner}" puts "#{winner}获胜!" else puts "平局!" end
小优化:进阶电脑AI(可选)
如果觉得随机选列太简单,你可以给电脑加基础的智能:
- 优先选择能让自己直接赢的列
- 其次选择能阻止玩家赢的列
- 最后再随机选列
比如可以加这样的方法:
def best_column # 先检查电脑能不能一步赢 available_columns.each do |col| temp_board = Marshal.load(Marshal.dump(@board)) # 复制棋盘模拟落子 row = temp_board.rindex { |r| r[col].nil? } temp_board[row][col] = @identifier[2] return col if winner?(temp_board, 2) end # 再检查要不要阻止玩家赢 available_columns.each do |col| temp_board = Marshal.load(Marshal.dump(@board)) row = temp_board.rindex { |r| r[col].nil? } temp_board[row][col] = @identifier[1] return col if winner?(temp_board, 1) end # 都没有就随机选 available_columns.sample end
然后在take_turn里把available_columns.sample换成best_column就行。
内容的提问来源于stack exchange,提问作者Max Slatter
相关产品推荐
相关产品推荐

