Last active
April 20, 2019 13:35
-
-
Save louije/606b9950e16992bbe491ceab47de3770 to your computer and use it in GitHub Desktop.
Tic Tac Toe
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
# Represents a tic-tac-toe board, composed over a 9-values array | |
# that contains the moves as strings (empty is " "). | |
class Board | |
VALUES = %I( | |
a1 a2 a3 | |
b1 b2 b3 | |
c1 c2 c3 | |
) | |
def initialize | |
@values = Array.new(9, " ") | |
end | |
def play(move, player) | |
return false if self[move] != " " | |
self[move] = player | |
end | |
def won? | |
# rows | |
same?(a1, a2, a3) or | |
same?(b1, b2, b3) or | |
same?(c1, c2, c3) or | |
# columns | |
same?(a1, b1, c1) or | |
same?(a2, b2, c2) or | |
same?(a3, b3, c3) or | |
# diagonals | |
same?(a1, b2, c3) or | |
same?(a3, b2, c1) | |
end | |
def draw? | |
[email protected]?(" ") && !won? | |
end | |
def to_s | |
%{ | |
1 2 3 | |
┌─────┬─────┬─────┐ | |
A │ #{a1} │ #{a2} │ #{a3} │ | |
├─────┼─────┼─────┤ | |
B │ #{b1} │ #{b2} │ #{b3} │ | |
├─────┼─────┼─────┤ | |
C │ #{c1} │ #{c2} │ #{c3} │ | |
└─────┴─────┴─────┘ | |
} | |
end | |
private | |
# Define a convenience getter for each board position | |
VALUES.each do |v| | |
define_method v do | |
self[v] | |
end | |
end | |
# Access the @values array | |
def [](sym) | |
@values[spreadsheet_notation(sym)] | |
end | |
def []=(sym, val) | |
@values[spreadsheet_notation(sym)] = val | |
end | |
def same?(*args) | |
args.all? { |v| v == args[0] } && args[0] != " " | |
end | |
# Takes a symbol in spreadsheet form (a1, b2, etc.) | |
# and returns the correct value from @values. | |
def spreadsheet_notation(sym) | |
%w(a b c).index(sym.to_s[0].downcase) * 3 + (sym.to_s[1].to_i - 1) | |
end | |
end |
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
require "./board" | |
# Contains the tic-tac-toe game loop and CLI user interaction | |
class Game | |
def initialize | |
@board = Board.new | |
next_player | |
tick | |
end | |
private | |
# Mark - Game loop | |
def tick | |
puts @board | |
puts | |
print "Your turn, #{@current_player}: " | |
input = gets.chomp | |
play input | |
end | |
def play(move) | |
sym = validate_position(move) | |
return wrong_move(move) if not sym | |
@board.play(sym, @current_player) || taken(move) | |
if @board.won? | |
winner | |
elsif @board.draw? | |
draw | |
else | |
next_player | |
tick | |
end | |
end | |
def next_player | |
# By default, the first player is ×. | |
@current_player = (@current_player == "×" ? "○" : "×") | |
end | |
# Mark - Invalid moves | |
def taken(move) | |
puts | |
puts "“#{move}” is already occupied." | |
tick | |
end | |
def wrong_move move | |
puts "“#{move}” wasn’t recognized as a valid board position." | |
puts "Type a combination of rows and columns, such as “b2” or “1C”." | |
tick | |
end | |
# MARK - End messages | |
def winner | |
puts @board | |
puts "#{@current_player} has won the game. Congratulations!" | |
end | |
def draw | |
puts @board | |
puts "Game over. It's a draw." | |
end | |
# Mark - Validate input | |
def validate_position(move) | |
# ensure the letter comes before the number | |
chars = move.split('').sort.reverse | |
# apply the constraints for a board position: | |
# a letter within A..C and a number within 1..3. | |
return false unless %w(a b c).include?(chars[0].downcase) and [1,2,3].include?(chars[1].to_i) and chars.count == 2 | |
chars.join.to_sym | |
end | |
end |
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
#!/usr/bin/env ruby | |
require "./game" | |
t = Game.new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment