您可以考虑创建两个类,Board 和 Player。以后者为先,将有两个Player 实例,一个是标记'X' 的玩家,另一个是标记'O' 的玩家。 Player 类有一个 initialize 方法,其功能是保存玩家(实例)将制作的标记('X' 或 'O')。
由于只有一个板,我们可以创建 Board 的单个实例,就像 @tadman 所做的那样。另一种选择——我选择的那个——是用三个类方法和一个 class 实例变量 (@cells) 构造类 Board,而不打算创建唯一的实例类的。
我认为Board 类的任何一种方法都不是首选;我只想指出,当一个类表示单个对象时,该对象可以是类本身,而不是类的实例。
你可以如下构造这两个类。
WINNERS = 3.times.with_object([]) do |i,a|
a << [[i,0], [i,1], [i,2]] << [[0,i], [1,i], [2,i]]
end << [[0,0], [1,1], [2,2]] << [[0,2], [1,1], c[2,0]]
#=> [[[0, 0], [0, 1], [0, 2]], [[0, 0], [1, 0], [2, 0]],
# [[1, 0], [1, 1], [1, 2]], [[0, 1], [1, 1], [2, 1]],
# [[2, 0], [2, 1], [2, 2]], [[0, 2], [1, 2], [2, 2]],
# [[0, 0], [1, 1], [2, 2]], [[0, 2], [1, 1], [2, 0]]]
class Board
@cells = Array.new(3) { Array.new(3, ' ') }
def self.record_move(r,c,side)
@cells[r][c] = side
end
def self.win?(side)
WINNERS.any? { |a| a.all? { |r,c| @cells[r][c] == side } }
end
def self.show
3.times do |i|
puts "%s|%s|%s" % @cells[i]
puts "_____" unless i == 2
end
end
end
请参阅Array::new、Enumerable#any? 和 Enumerable#all?。
class Player
def initialize(side)
@side = side
end
def move(r,c)
Board.record_move(r,c,@side)
end
def win?
Board.win?(@side)
end
end
x = Player.new('X')
#=> #<Player:0x000057c0e95c4430 @side="X">
o = Player.new('O')
#=> #<Player:0x000057c0e95e3100 @side="O">
Board.show
| |
_____
| |
_____
| |
x.move 0,2
Board.show
| |X
_____
| |
_____
| |
o.move 0,0
Board.show
O| |X
_____
| |
_____
| |
x.move 2,0
Board.show
O| |X
_____
| |
_____
X| |
x.win? #=> false
o.move 2,2
Board.show
O| |X
_____
| |
_____
X| |O
o.win? #=> false
x.move 1,1
Board.show
O| |X
_____
|X|
_____
X| |O
x.win? #=> true