Skip to content

Instantly share code, notes, and snippets.

@bokmann
Last active January 1, 2016 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bokmann/8186504 to your computer and use it in GitHub Desktop.
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 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