-
Notifications
You must be signed in to change notification settings - Fork 0
/
tictactoe.rb
111 lines (95 loc) · 2.6 KB
/
tictactoe.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
class TicTacToe
attr_reader :action_size
def initialize(size = 3)
@rows = size
@cols = size
@action_size = @rows * @cols
end
def get_initial_state
Array.new(@rows) { Array.new(@cols) { 0 } }
end
def get_next_state(state, action, player)
row, col = get_row_col(action)
state[row][col] = player
state
end
def get_legal_moves(state)
state.flatten.map { |s| s === 0 }
end
def get_diagonals(state, indices)
state.flatten.reject.with_index { !indices.include? _2 }
end
def is_diag_connected(state, player)
left_diag = []
right_diag = []
i = 0
j = @cols - 1
@cols.times do
left_diag.push(i)
right_diag.push(j)
i += @cols + 1
j += @cols - 1
end
is_rdiag_connected = get_diagonals(state, right_diag).sum === player * @cols
is_ldiag_connected = get_diagonals(state, left_diag).sum === player * @cols
is_ldiag_connected || is_rdiag_connected
end
def get_row_col(action)
[action / @cols, action % @cols]
end
def check_win(state, action)
return false if action.nil?
row, col = get_row_col(action)
player = state[row][col]
is_row_connected = state[row].sum === player * @rows
is_col_connected = state.transpose[col].sum === player * @cols
is_row_connected || is_col_connected || is_diag_connected(state, player)
end
def get_winner(state, action)
row, col = get_row_col(action)
state[row][col]
end
def check_gameover(state, action)
return 1, true if check_win(state, action)
# Draw if no legal move
return 0, true unless get_legal_moves(state).any?
[0, false]
end
def get_opponent(player)
-player
end
def clone_state(state)
state.map { |r| r.map(&:clone) }
end
def change_perspective(state, player)
state_ = state.map { |r| r.map(&:clone) }
state_.each_with_index do |row, r|
state_[r] = row.map { |i| i * player }
end
end
def print_board(state, p1, p2, p1_score, p2_score, match_no)
board_width = 9 * @cols
title = "#{p1} : #{p1_score} | [#{match_no}] | #{p2_score} : #{p2} "
puts
state.each_with_index do |row, r|
if r === 0
puts title.upcase.center(board_width)
puts '=' * board_width
end
row.each_with_index do |val, c|
print ' | '
if val === 1
print p1.center(4)
elsif val === -1
print p2.center(4)
else
print (c + (@cols * r) + 1).to_s.center(5)
end
print ' |' if c === @cols - 1
end
puts
print r === @rows - 1 ? '=' * board_width : '-' * board_width
puts
end
end
end