-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtic_tac_toe.rb
164 lines (145 loc) · 3.65 KB
/
tic_tac_toe.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# frozen_string_literal: false
# Contains piece, name and score for the given player
class Player
attr_reader :piece, :name
attr_accessor :score
def initialize(name, piece)
@score = 0
@name = name
@piece = piece
@random = Random.new
end
def submit_coordinates(board)
case @name
when 'Computer'
computer_input(board)
else
player_input_val(board)
end
end
def computer_input(board)
puts "Computer's turn:"
x = @random.rand(0..2)
y = @random.rand(0..2)
until board[y][x] == ''
x = @random.rand(0..2)
y = @random.rand(0..2)
end
[x, y]
end
def player_input_val(board)
x, y = player_input_get
until (x.between?(0, 2) && y.between?(0, 2)) && board[y][x] == ''
puts "Invalid coordinates X: #{x + 1}, Y: #{y + 1}"
x, y = player_input_get
end
[x, y]
end
def player_input_get
puts 'Enter X coordinate (1-3)'
x = gets.chomp.to_i - 1
puts 'Enter Y coordinate (1-3)'
y = gets.chomp.to_i - 1
[x, y]
end
def check_score(other)
if @score > other.score
puts "#{@name} is winning with #{@score} points, versus #{other.name} with #{other.score} points"
elsif @score < other.score
puts "#{other.name} is winning with #{other.score} points, versus #{@name} with #{score} points"
else
puts "#{@name} and #{other.name} are drawing at #{@score} points"
end
end
end
# Each instance represents a separate round of tic-tac-toe
class Round
attr_reader :current_player
def initialize(player1, player2, first_player)
@player1 = player1
@player2 = player2
@board = Array.new(3) { Array.new(3, '') }
@current_player = first_player
@diagonals = {
ul_dr: [[0, 0], [1, 1], [2, 2]],
ur_dl: [[0, 2], [1, 1], [2, 0]]
}
end
def display
@board.each { |row| puts row.inspect }
puts
end
def play_round(player)
x, y = player.submit_coordinates(@board)
@board[y][x] = player.piece
display
if check_victory == 'Draw'
puts 'The game is a draw!'
return true
elsif check_victory == true
puts "#{@current_player.name} wins!"
@current_player.score += 1
return true
end
@current_player = @current_player == @player1 ? @player2 : @player1
false
end
# Checks various victory conditions (or for a draw) and returns true if it encounters them
def check_victory
if row?
true
elsif vertical?
true
elsif diagonal?
true
elsif draw?
'Draw'
else
false
end
end
def row?
@board.each { |row| return true if row[0] != '' && (row[0] == row[1] && row[1] == row[2]) }
false
end
def draw?
[email protected]?('')
end
def vertical?
3.times { |x| return true if @board[0][x] != '' && (@board[0][x] == @board[1][x] && @board[1][x] == @board[2][x]) }
false
end
def diagonal?
@diagonals.each do |_, arr|
if @board[arr[0][0]][arr[0][1]] != '' &&
(@board[arr[1][0]][arr[1][1]] == @board[arr[0][0]][arr[0][1]] &&
@board[arr[1][0]][arr[1][1]] == @board[arr[2][0]][arr[2][1]])
return true
end
end
false
end
end
puts 'Please enter your name:'
player_name = gets.chomp
human = Player.new(player_name, 'X')
computer = Player.new('Computer', 'O')
loop do
game = Round.new(human, computer, human)
until game.play_round(game.current_player)
end
human.check_score(computer)
puts 'Do you want to play another game? Y/N'
input = gets.chomp.downcase
until ['y', 'n'].include?(input)
case input
when 'y'
next
when 'n'
break
else
puts 'Please enter Y or N'
input = gets.chomp.lower
end
end
end