我用 Ruby 制作了一個井字游戲。我對 Ruby OOP 很陌生。我檢查行、列和對角線的獲勝條件真的很重,它們占用了太多的代碼行,看起來很糟糕。我的代碼也總是重復。
所以我的問題是如何在我的代碼中實作以下獲勝條件?
WIN_COMBINATIONS = [
[0,1,2], # top_row
[3,4,5], # middle_row
[6,7,8], # bottom_row
[0,3,6], # left_column
[1,4,7], # center_column
[2,5,8], # right_column
[0,4,8], # left_diagonal
[6,4,2] # right_diagonal
]
這是我的獲勝條件:
module CheckWinner
def check_horizontal(player1, player2)
player1_win = false
player2_win = false
@board.each do |row|
player1_win = row.all?(player1)
player2_win = row.all?(player2)
break if player1_win || player2_win
end
puts "#{player1} won!" if player1_win
puts "#{player2} won!" if player2_win
player1_win || player2_win
end
def check_vertical(player1, player2)
player1_win = false
player2_win = false
@board.transpose.each do |row|
player1_win = row.all?(player1)
player2_win = row.all?(player2)
break if player1_win || player2_win
end
puts "#{player1} won!" if player1_win
puts "#{player2} won!" if player2_win
player1_win || player2_win
end
def check_diagonal(player1, player2)
if @board[0][0] == player1 && board[1][1] == player1 && board[2][2] == player1 ||
@board[0][2] == player1 && board[1][1] == player1 && board[2][0] == player1
puts "#{@player1} won!"
true
elsif @board[0][0] == player2 && board[1][1] == player2 && board[2][2] == player2 ||
@board[0][2] == player2 && board[1][1] == player2 && board[2][0] == player2
puts "#{@player2} won!"
true
end
end
end
我從這行代碼呼叫這些條件:
def game
choosing_player
loop do
player1(@player1)
break if check_vertical(@player1,@player2) == true || check_diagonal(@player1,@player2) == true || check_horizontal(@player1,@player2) == true || full?
player2(@player2)
break if check_vertical(@player1,@player2) == true || check_diagonal(@player1,@player2) == true || check_horizontal(@player1,@player2) == true || full?
end
end
end
這是我的完整專案,它作業正常。
module CheckWinner
def check_horizontal(player1, player2)
player1_win = false
player2_win = false
@board.each do |row|
player1_win = row.all?(player1)
player2_win = row.all?(player2)
break if player1_win || player2_win
end
puts "#{player1} won!" if player1_win
puts "#{player2} won!" if player2_win
player1_win || player2_win
end
def check_vertical(player1, player2)
player1_win = false
player2_win = false
@board.transpose.each do |row|
player1_win = row.all?(player1)
player2_win = row.all?(player2)
break if player1_win || player2_win
end
puts "#{player1} won!" if player1_win
puts "#{player2} won!" if player2_win
player1_win || player2_win
end
def check_diagonal(player1, player2)
if @board[0][0] == player1 && board[1][1] == player1 && board[2][2] == player1 ||
@board[0][2] == player1 && board[1][1] == player1 && board[2][0] == player1
puts "#{@player1} won!"
true
elsif @board[0][0] == player2 && board[1][1] == player2 && board[2][2] == player2 ||
@board[0][2] == player2 && board[1][1] == player2 && board[2][0] == player2
puts "#{@player2} won!"
true
end
end
end
# TicTacToe Board
class Board
include CheckWinner
attr_accessor :board
def initialize
@board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
end
def print_board
puts '-------------'
@board.each do |row|
print '|'
row.each do |col|
print " #{col}"
print ' | '
end
puts
end
puts '-------------'
end
def twodimentional_board
@board = @board.each_slice(3).map { |el| el }
end
def occupied_error(value)
puts 'There is a value or wrong place! Try Again!'
twodimentional_board
print_board
value == @player1 ? player2(@player1) : player1(@player2) # Stay same player
end
def move_if_possible(place, value)
@board.flatten!
if @board[place - 1] == 'X' || @board[place - 1] == 'O' || !place.between?(1, 9)
occupied_error(value)
else
@board[place - 1] = value
twodimentional_board
@board
end
end
def full?
if @board.flatten.all?(String)
puts 'Draw!'
true
end
end
def choosing_player
puts 'Choose for Player1(X or O)'
loop do
@player1 = gets.chomp!
break if @player1 == 'X' || @player1 == 'O'
puts 'Try Again!(X or O)'
end
puts "Player 1 is: #{@player1}"
@player1 == 'X' ? @player2 = 'O' : @player2 = 'X'
puts "Player 2 is: #{@player2}"
print_board
end
def player1(player1)
puts "Choice #{player1} Place on a board(1 to 10)"
@place = gets.chomp!.to_i
move_if_possible(@place, player1)
print_board
end
def player2(player2)
puts "Choice #{player2} Place on a board(1 to 10)"
@place = gets.chomp!.to_i
move_if_possible(@place, player2)
print_board
end
def game
choosing_player
loop do
player1(@player1)
break if check_vertical(@player1,@player2) == true || check_diagonal(@player1,@player2) == true || check_horizontal(@player1,@player2) == true || full?
player2(@player2)
break if check_vertical(@player1,@player2) == true || check_diagonal(@player1,@player2) == true || check_horizontal(@player1,@player2) == true || full?
end
end
end
board = Board.new
board.game
如果你想在這里實時預覽是repl鏈接
uj5u.com熱心網友回復:
我不確定這是否正是您所追求的,但這里有一些事情。
- 你
@board是一個 3 行的陣列,但你可能的勝利只是一個點陣列。flatten設定您的@board 意味著您可以按原樣使用索引。 - 您已經有一系列獲勝條件,然后忽略此陣列并手動處理所有選項
定義
# example winning board for 'O'
@board = [['O','X','O'], ['X','O','X'], ['X','O','O']]
player1 = 'X'
player2 = 'O'
首先,遍歷 中的可能組合,并為每個組合從單獨的陣列中WIN_COMBINATIONS獲取這些單元格,以供以后檢查。@board將陣列陣列存盤為另一個陣列(使用#map)。該*字符是ruby splat運算子,它將陣列轉換為被呼叫程序的引數。
速記:
winmap = WIN_COMBINATIONS.map {|w| @board.flatten.values_at(*w)}
速記:
flat_board = @board.flatten
winmap = WIN_COMBINATIONS.map do |win|
flat_board.values_at(*win)
end
它設定了一個陣列,如下所示:
winmap = [
["O", "X", "O"], # top_row
["X", "O", "X"], # middle_row
["X", "O", "O"], # bottom_row
["O", "X", "X"], # left_column
["X", "O", "O"], # center_column
["O", "X", "O"], # right_column
["O", "O", "O"], # left_diagonal
["X", "O", "O"] # right_diagonal
]
一旦您獲得了板上所有可能獲勝單元的串列,您就可以使用現有的row搜索代碼,除了回圈遍歷每個陣列,我們使用陣列操作#any?來識別匹配項
player1_win = winmap.any?{|m| m.all?(player1)}
player2_win = winmap.any?{|m| m.all?(player2)}
這應該消除所有單獨的子程式,并給你一個真/假的答案,如果有人贏了。
uj5u.com熱心網友回復:
這是一種不同的方法來確定董事會是否表示獲勝,如果是,誰獲勝。
設board是一個由三個元素組成的陣列,每個陣列由三個元素組成,每個元素是或'X',最后一個表示該單元格尚未被標記。'O''_'
讓我們創建一些方法。
def row_win?(board)
board.each { |row| return row.first if row_uniq.size == 1 }
nil
end
'X'如果'X'連續獲勝,'O'如果'O'連續獲勝并且nil沒有玩家連續獲勝,則此方法回傳。
def column_win?(board)
row_win?(board.transpose)
end
此方法類似地回傳'X','O'或nil,指示列中是否有贏,如果有,誰贏。
def diagonal_win?(board)
row_win? [[board[0][0], board[1][1], board[2][2]],
[board[0][2], board[1][1], board[2][0]]]
end
此方法對兩條對角線執行相同的操作。
最后,
def win?(board)
row_win?(board) || column_win?(board) || diagonal_win?(board)
end
nil如果沒有獲勝者則回傳。
讓我們試試看。
win? [['X', '_', 'X'],
['_', 'X', 'O'],
['X', 'O', 'O']]
#=> 'X'
win? [['X', 'O', 'X'],
['_', 'O', 'X'],
['X', 'O', 'O']]
#=> 'O'
win? [['X', 'O', 'X'],
['O', 'O', 'X'],
['X', 'X', 'O']]
#=> nil
uj5u.com熱心網友回復:
為什么不跟蹤狀態以幫助您在標記新動作時確定獲勝條件?這樣你就不必重新計算你已經知道的所有東西。
例如,如果我告訴你我的棋盤大小是,第一行3已經有2 X s,現在X在該行下了一個新的棋子,導致3 X s,你知道 X 立即贏了對嗎?您甚至不需要了解有關董事會狀態的任何其他資訊。
您可以在此處應用相同的邏輯,只需跟蹤每行的X和O計數、列和診斷,因為標記被記錄,您甚至不必回圈檢查誰贏了。
上述方法易于實作并且需要O(1)時間復雜度來檢查獲勝條件。你用一點記憶體 ( O(n)) 換取計算速度。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/426763.html
上一篇:在Ruby中決議回傳鍵而不是值
