Created
August 12, 2022 11:50
-
-
Save everylittlefox/33e0e2ab96337b0fb456c02a4f379262 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| # game has two players who take turns placing either an X or an O on the board. | |
| # game's solved if either the grid fills up or a player wins. | |
| # a player wins if they're able to align their character (X or O) along a vertical, | |
| # horizontal, or diagonal set of cells. | |
| class Player | |
| attr_accessor :character | |
| attr_reader :name | |
| def initialize(name) | |
| @name = name | |
| end | |
| # #play takes a view of the game's grid and returns a number in range 1..9 | |
| # number represents the position of the intended cell. | |
| def play(game_state) | |
| gets.to_i | |
| end | |
| def to_s | |
| name | |
| end | |
| end | |
| class TicTacToe | |
| SIZE = 3 | |
| attr_accessor :player_one, :player_two, :winner, :next_player, :board, :state | |
| def initialize | |
| @board = Array.new(SIZE) { |i| Array.new(SIZE) { |j| (SIZE * i) + j + 1 } } | |
| end | |
| def start | |
| self.state = :started | |
| loop do | |
| puts "Welcome to TicTacToe. Enter a name for player one." | |
| while (player_one_name = gets.strip).empty? | |
| puts "Name must be a none-empty string." | |
| end | |
| puts "\nEnter a name for player two. Player Two's name cannot be '#{player_one_name}'" | |
| while (player_two_name = gets.strip).empty? || player_two_name == player_one_name | |
| puts "Player Two, pick a (non-empty) name different from player one." | |
| end | |
| self.player_one = Player.new(player_one_name) | |
| self.player_two = Player.new(player_two_name) | |
| puts "\nWho get's to play first will be determined by a coin toss. Ready? LFG!" | |
| if rand > 0.5 | |
| self.player_one.character = :x | |
| self.player_two.character = :o | |
| self.next_player = player_one | |
| else | |
| self.player_one.character = :o | |
| self.player_two.character = :x | |
| self.next_player = player_two | |
| end | |
| puts "\n#{self.next_player} goes first." | |
| while self.state == :started | |
| print_game_board | |
| puts "\n#{self.next_player}, enter a number (1-9) for an available cell to place an '#{self.next_player.character}'" | |
| until self.empty_cells.include?(chosen_cell = self.next_player.play(self.board)) | |
| puts "\nSorry, you can't play at #{chosen_cell}. Pick another." | |
| end | |
| update_board(chosen_cell) | |
| update_game_state | |
| update_next_player | |
| end | |
| print_game_board | |
| case self.state | |
| when :has_winner | |
| puts "\nGame over! #{self.winner}, playing as '#{self.winner.character}', wins." | |
| when :no_winner | |
| puts "\nGame over! Too bad, nobody wins :(" | |
| end | |
| puts "\nWould you like to play a new game? Press 'y' for yes or 'n' for no." | |
| break if gets.strip.downcase[0] == 'n' | |
| end | |
| end | |
| private | |
| def empty_cells | |
| self.board.flatten.select { |c| c.to_s.to_i.between?(1,9) } | |
| end | |
| def print_game_board | |
| row_strs = board.map { |row| row.map { |cell| cell.to_s.center(3) }.join("|") } | |
| puts "\n" + row_strs.join("\n---+---+---\n") | |
| end | |
| def col_from_cell(chosen_cell) | |
| (chosen_cell - 1) % SIZE | |
| end | |
| def row_from_cell(chosen_cell) | |
| (chosen_cell - 1 - col_from_cell(chosen_cell)) / SIZE | |
| end | |
| def update_next_player | |
| if next_player.name == player_one.name | |
| self.next_player = player_two | |
| else | |
| self.next_player = player_one | |
| end | |
| end | |
| def update_board(chosen_cell) | |
| self.board[row_from_cell(chosen_cell)][col_from_cell(chosen_cell)] = next_player.character | |
| end | |
| def update_game_state | |
| if board.none? { |row| row.any? { |c| c.to_s.to_i.between?(1, 9) } } | |
| self.state = :no_winner | |
| return | |
| end | |
| cells_to_check = [ | |
| [1,2,3], | |
| [4,5,6], | |
| [7,8,9], | |
| [1,4,7], | |
| [2,5,8], | |
| [3,6,9], | |
| [1,5,9], | |
| [3,5,7] | |
| ] | |
| cells_to_check.each do |cells| | |
| first = board[row_from_cell(cells[0])][col_from_cell(cells[0])] | |
| if cells.all? { |cell| board[row_from_cell(cell)][col_from_cell(cell)] == first } | |
| self.state = :has_winner | |
| self.winner = self.next_player | |
| return | |
| end | |
| end | |
| end | |
| end | |
| game = TicTacToe.new | |
| game.start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment