Last active
August 6, 2019 19:29
-
-
Save WhereIsX/96ae80ffd4679619ffb5803186a442f0 to your computer and use it in GitHub Desktop.
Yana's OO TicTacToe: first attempt, a bit wet in some places, but in working order.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Game_Master | |
attr_accessor :player1, :player2, :board, :winner, :whose_turn | |
def initialize | |
@player1 = nil | |
@player2 = nil | |
@board = Board.new(3,3) | |
@winner = nil | |
@whose_turn = nil | |
end | |
def start_game | |
self.prompt_start | |
self.prompt_new_players | |
until @winner | |
self.play_game | |
end | |
@board.display | |
puts "Congrats #{winner.name}! You won!" | |
end | |
def prompt_start | |
puts "Welcome to Yana's Tic Tac Toe!" | |
# TODO: add sleep for dramatic effect | |
end | |
def prompt_new_players | |
# TODO: players can choose own tokens, validate tokens, whos first | |
puts "Now who wants to be 'X'?" | |
player1_name = gets.strip | |
puts "is X a computer?" | |
is_computer = gets.strip | |
if is_computer == "true" | |
@player1 = Player.new(name: player1_name, token: 'X', is_computer: true) | |
else | |
@player1 = Player.new(name: player1_name, token: 'X') | |
end | |
p @player1.is_computer | |
puts "And who's stuck with 'O'?" | |
@player2 = Player.new(name: gets.strip, token: 'O') | |
@whose_turn = player1 | |
puts "Remember to enter your response in x- y- coordinates separated by a space. For example, if you'd like to place your piece in the upper right corner of a 3x3 board, please enter 'x3 y1'. " | |
end | |
def play_game | |
@board.display | |
puts "Ok, #{@whose_turn.name}, you're up!\nWhere would you like to place your #{@whose_turn.token}?" | |
@board.add_a_move(@whose_turn, gets.strip) | |
if @board.winning_move? | |
@winner = @whose_turn | |
else | |
@whose_turn = @whose_turn == @player1 ? @player2 : @player1 | |
end | |
end | |
end | |
class Board | |
attr_accessor :state, :current_move | |
attr_reader :row_size, :column_size | |
def initialize(row_size, column_size) | |
@row_size = row_size | |
@column_size = column_size | |
@state = generate_positions(row_size, column_size) | |
@current_move = nil | |
end | |
def display | |
rows = [] | |
horizontal_separator_line = '-' * (@row_size * 3) + "\n" | |
@column_size.times do |column_index| | |
single_row = [] | |
@row_size.times do |row_index| | |
single_row << @state["x#{row_index + 1} y#{column_index + 1}"] | |
end | |
rows.push( single_row.join(' | ') + "\n" ) | |
end | |
displayed_board = rows.join(horizontal_separator_line) | |
puts displayed_board | |
end | |
def add_a_move(player, move) | |
@current_move = move | |
if valid_move? | |
@state[@current_move] = player.token | |
else | |
puts "Sorry, that's not a valid move, try again" | |
display | |
add_a_move(player, gets.strip) | |
end | |
end | |
def winning_move? | |
current_move_token = @state[@current_move] | |
vertical = generate_vertical_keys() | |
horizontal = generate_horizontal_keys() | |
forward = generate_forward_slant_keys() | |
backward = generate_backward_slant_keys() | |
all_possible_winning_paths = [vertical, horizontal, forward, backward] | |
p "forward" | |
p forward | |
all_possible_winning_paths.each do |path| | |
tokens_in_a_row_so_far = 0 | |
path.each do |position| | |
if @state[position] == current_move_token | |
tokens_in_a_row_so_far += 1 | |
if tokens_in_a_row_so_far == 3 | |
return true | |
end | |
else | |
tokens_in_a_row_so_far = 0 | |
end | |
end | |
end | |
return false | |
end | |
# TODO | |
# dry up key gen... | |
# vertical: -X, ^Y | |
# horizontal: ^X, -Y | |
# backward slant: ^X, ^Y | |
# forward slant: ^X, vY | |
def generate_vertical_keys | |
x, y = current_move_as_array_of_integers() | |
y_start = y - 2 | |
y_end = y + 2 | |
y_range = *y_start..y_end | |
return y_range.collect { |y_value| "x#{x} y#{y_value}"} | |
end | |
def generate_horizontal_keys | |
x, y = current_move_as_array_of_integers() | |
x_start = x - 2 | |
x_end = x + 2 | |
x_range = *x_start..x_end | |
return x_range.collect { |x_value| "x#{x_value} y#{y}"} | |
end | |
def generate_backward_slant_keys | |
x, y = current_move_as_array_of_integers() | |
x_start = x - 2 | |
x_end = x + 2 | |
x_range = *x_start..x_end | |
y_start = y - 2 | |
y_end = y + 2 | |
y_range = *y_start..y_end | |
coordinates = x_range.collect.with_index do |x_value, index| | |
"x#{x_value} y#{y_range[index]}" | |
end | |
return coordinates | |
end | |
def generate_forward_slant_keys | |
x, y = current_move_as_array_of_integers() | |
x_start = x - 2 | |
x_end = x + 2 | |
x_range = *x_start..x_end | |
y_start = y + 2 | |
y_end = y - 2 | |
y_range = *y_end..y_start | |
# the above is because splatting a range in decreasing order yields empty array | |
y_range.reverse! | |
coordinates = x_range.collect.with_index do |x_value, index| | |
"x#{x_value} y#{y_range[index]}" | |
end | |
return coordinates | |
end | |
def current_move_as_array_of_integers | |
return @current_move.split(' ').collect { |axis_and_num| axis_and_num[1..-1].to_i } | |
end | |
def generate_positions(row_size, column_size) | |
all_positions = {} | |
column_size.times do |column_index| | |
row_size.times do |row_index| | |
all_positions["x#{row_index+1} y#{column_index+1}"] = ' ' | |
end | |
end | |
return all_positions | |
end | |
def valid_move? | |
return @state[@current_move] == ' ' | |
end | |
end | |
class Player | |
attr_reader :name, :token, :is_computer | |
def initialize(name:, token:, is_computer: false) | |
@name = name | |
@token = token | |
@is_computer = is_computer | |
end | |
end | |
Game_Master.new.start_game |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment