Last active
January 1, 2016 18:49
-
-
Save bokmann/8186504 to your computer and use it in GitHub Desktop.
A Connect Four Coding Challenge form my talk series, "What Computer Scientists Know"
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
# This is an example Connect Four board. It is a data structure | |
# that represents the current state of the board game; the colors | |
# of pieces already in position, the current player to move, and | |
# also supplies a 'move(x)' method, where you just specify the | |
# column to drop a piece in; the board will automatically 'drop' | |
# the piece to the next available position, set the player to | |
# the opponent, and return a brans new instance of the board. | |
# | |
# This may seem strange to those of you who have not written | |
# board game playing apps before, but it is common practice to make | |
# any one 'board' an immutable representation of the board state. | |
# You can start a game by asking the class for a 'starting_board', | |
# then you can call '.move(x)' on that board to get a brand new | |
# board with that move in play. for instance: | |
# | |
# b = C4Board.starting_board | |
# b = b.move(3) | |
# b = b.move(4) | |
# | |
# would now have the variable 'b' set to a board where black | |
# has played a piece into column #3, and red has played a | |
# piece into column #4. | |
# | |
# YOUR JOB is to write the 'won?' method on the board. See the | |
# comments within that method for more details. | |
# | |
# The 'moves' method is irrelevant to this problem, but it won't | |
# be for the player we will eventually create. This method returns | |
# every possible move that could be made with the current state | |
# of the board. | |
# | |
# This board makes use of the deep_clone gem: | |
# | |
# gem 'deep_clone' | |
# | |
# in order to make copies of the board positions for children | |
# of this board. | |
class C4Board | |
attr_reader :cells | |
attr_reader :player | |
attr_reader :history | |
HEIGHT = 6 | |
WIDTH = 7 | |
BLACK = :black | |
RED = :red | |
EMPTY = nil | |
def self.opponent_of(player) | |
player == BLACK ? RED : BLACK | |
end | |
def self.starting_board | |
C4Board.new(Array.new(7) {Array.new(6) { C4Board::EMPTY }}, C4Board::BLACK, []) | |
end | |
def initialize(cells, player, history) | |
@cells = cells | |
@player = player | |
@history = history | |
end | |
def moves | |
m = [] | |
return m if won? | |
@cells.each_with_index do |row, x| | |
m << x if row.index(EMPTY) | |
end | |
m | |
end | |
def move(x) | |
return self if x.nil? | |
new_cells = @cells.__deep_clone__ | |
y = new_cells[x].index { |c| c == EMPTY } | |
new_cells[x][y] = @player | |
C4Board.new(new_cells, @player == BLACK ? RED : BLACK, history + [x]) | |
end | |
def won? | |
# should return nil if there is no winner. | |
# if there is a winner, the choice of what to return is up to you... | |
# You might want to return 'true', indicating the game has been won... | |
# You might want to return :red or :black, indicating which player | |
# is the winner... | |
# or you might want to return a data structure that indicates the | |
# winning places on the board - for instance: | |
# [[3,0],[4,0],[5,0],[6,0]] | |
end | |
def draw? | |
won?.nil? && moves.empty? | |
end | |
def last_cell | |
return nil if @history.empty? | |
[@history.last, @history.count(@history.last) - 1] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment