Created
September 7, 2013 00:46
-
-
Save steven-ferguson/6471797 to your computer and use it in GitHub Desktop.
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 Board | |
attr_reader :columns, :height, :width | |
def initialize(width, height) | |
@columns = [] | |
@height = height | |
@width = width | |
width.times do |position| | |
column = Column.new(position, height) | |
columns << column | |
end | |
end | |
def winner?(token, win_length) | |
winning_conditions = [get_vertical_matches(token) + 1, | |
get_left_matches(token) + get_right_matches(token) + 1, | |
get_negative_slope_left_diagonal_matches(token) + get_negative_slope_right_diagonal_matches(token) + 1, get_positive_slope_left_diagonal_matches(token) + get_positive_slope_right_diagonal_matches(token) + 1] | |
winning_conditions.any? do |condition| | |
condition >= win_length | |
end | |
end | |
private | |
def get_vertical_matches(token) | |
consecutive_matches = 0 | |
token.row_number.times do |difference| | |
if @columns[token.column_number].slots[token.row_number - difference - 1].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
end | |
def get_left_matches(token) | |
consecutive_matches = 0 | |
token.column_number.times do |index| | |
if @columns[token.column_number - index - 1].slots[token.row_number].nil? || @columns[token.column_number - index - 1].slots[token.row_number].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
end | |
def get_right_matches(token) | |
columns_right = @columns.length - (token.column_number + 1) | |
# puts "columns right: #{columns_right}" | |
consecutive_matches = 0 | |
columns_right.times do |difference| | |
# puts "column val: #{@columns[token.column_number + difference + 1].slots[token.row_number].nil?}" | |
if @columns[token.column_number + difference + 1].slots[token.row_number].nil? || @columns[token.column_number + difference + 1].slots[token.row_number].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
# puts "right matches: #{consecutive_matches}" | |
consecutive_matches | |
end | |
def get_negative_slope_left_diagonal_matches(token) | |
columns_to_zero = token.column_number | |
consecutive_matches = 0 | |
rows_to_top = @height - token.row_number - 1 | |
if columns_to_zero < rows_to_top | |
diagonals_to_get = columns_to_zero | |
else | |
diagonals_to_get = rows_to_top | |
end | |
diagonals_to_get.times do |difference| | |
if @columns[token.column_number - difference - 1].slots[token.row_number + difference + 1].nil? || @columns[token.column_number - difference - 1].slots[token.row_number + difference + 1].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
end | |
def get_negative_slope_right_diagonal_matches(token) | |
consecutive_matches = 0 | |
columns_to_max = @width - token.column_number - 1 | |
rows_to_bottom = token.row_number | |
diagonals_to_get = columns_to_max < rows_to_bottom ? columns_to_max : rows_to_bottom | |
diagonals_to_get.times do |difference| | |
if @columns[token.column_number + difference + 1].slots[token.row_number - difference - 1].nil? || @columns[token.column_number + difference + 1].slots[token.row_number - difference - 1].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
end | |
def get_positive_slope_left_diagonal_matches(token) | |
consecutive_matches = 0 | |
columns_to_zero = token.column_number | |
rows_to_bottom = token.row_number | |
if columns_to_zero < rows_to_bottom | |
diagonals_to_get = columns_to_zero | |
else | |
diagonals_to_get = rows_to_bottom | |
end | |
diagonals_to_get.times do |difference| | |
if @columns[token.column_number - difference - 1].slots[token.row_number - difference - 1].nil? || @columns[token.column_number - difference - 1].slots[token.row_number - difference - 1].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
end | |
def get_positive_slope_right_diagonal_matches(token) | |
consecutive_matches = 0 | |
columns_to_max = @width - token.column_number - 1 | |
rows_to_top = @height - token.row_number - 1 | |
diagonals_to_get = columns_to_max < rows_to_top ? columns_to_max : rows_to_top | |
diagonals_to_get.times do |difference| | |
if @columns[token.column_number + difference + 1].slots[token.row_number + difference + 1].nil? || @columns[token.column_number + difference + 1].slots[token.row_number + difference + 1].symbol != token.symbol | |
break | |
else | |
consecutive_matches += 1 | |
end | |
end | |
consecutive_matches | |
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 'rspec' | |
require 'player' | |
require 'token' | |
require 'column' | |
require 'board' | |
describe Board do | |
it 'is initialized with a height and width' do | |
board = Board.new(1, 1) | |
board.should be_an_instance_of Board | |
end | |
it 'has columns' do | |
board = Board.new(2, 1) | |
board.columns.length.should eq 2 | |
end | |
describe 'winner?' do | |
it 'returns false if the token does not create a winning condition' do | |
board = Board.new(9, 7) | |
board.columns[2].add_token("&") | |
board.winner?(board.columns[2].slots.last, 4).should be_false | |
end | |
it 'returns true if a vertical winning condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.winner?(board.columns[0].slots.last, 4).should be_true | |
end | |
it 'returns true if a left horizontal winning condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[2].add_token("&") | |
board.columns[3].add_token("&") | |
board.winner?(board.columns[3].slots.last, 4).should be_true | |
end | |
it 'returns true if a right horizontal winning condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[2].add_token("&") | |
board.columns[3].add_token("&") | |
board.winner?(board.columns[0].slots.last, 4).should be_true | |
end | |
it 'returns true if a middle horizontal winning condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[2].add_token("&") | |
board.columns[3].add_token("&") | |
board.winner?(board.columns[2].slots.last, 4).should be_true | |
end | |
it 'returns false if a horizontal winning condition does not exist' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("#") | |
board.columns[1].add_token("&") | |
board.winner?(board.columns[1].slots.last, 4).should be_false | |
end | |
it 'returns false if there is not a horizontal winning condition' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[2].add_token("$") | |
board.columns[3].add_token("&") | |
board.winner?(board.columns[3].slots.last, 4).should be_false | |
end | |
it 'handles empty spaces in a horizontal row' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[3].add_token("&") | |
board.columns[4].add_token("&") | |
board.winner?(board.columns[3].slots.last, 4).should be_false | |
end | |
it 'returns true if negative slope condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("^") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("^") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("^") | |
board.columns[3].add_token("^") | |
board.winner?(board.columns[3].slots.last, 4).should be_true | |
end | |
it 'returns true if negative slope condition exists' do | |
board = Board.new(9, 7) | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("&") | |
board.columns[0].add_token("^") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("^") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("^") | |
board.columns[3].add_token("^") | |
board.winner?(board.columns[0].slots.last, 4).should be_true | |
end | |
it 'returns true if positive slope condition exists' do | |
board = Board.new(9, 7) | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("^") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("^") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("^") | |
board.columns[0].add_token("^") | |
board.winner?(board.columns[3].slots.last, 4).should be_true | |
end | |
it 'returns true if positive slope condition exists' do | |
board = Board.new(9, 7) | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("&") | |
board.columns[3].add_token("^") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("&") | |
board.columns[2].add_token("^") | |
board.columns[1].add_token("&") | |
board.columns[1].add_token("^") | |
board.columns[0].add_token("^") | |
board.winner?(board.columns[0].slots.last, 4).should be_true | |
end | |
end | |
# describe 'get_vertical_neighbors' do | |
# it 'gets all the neighbors of a token that are in the same column and within three spaces' do | |
# board = Board.new(9, 7) | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.get_vertical_neighbors(board.columns[0].slots.last).should eq board.columns[0].slots | |
# end | |
# end | |
# describe 'connect_winner?' do | |
# it 'is false if the array does not have enough matching tokens' do | |
# board = Board.new(9, 7) | |
# board.columns[0].add_token("$") | |
# board.connect_winner?(4, board.get_vertical_neighbors(board.columns[0].slots.last)).should eq false | |
# end | |
# it 'is true if the array has enough consecutive matching tokens' do | |
# board = Board.new(9, 7) | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.columns[0].add_token("&") | |
# board.connect_winner?(board.columns[0].slots.last, board.get_vertical_neighbors(board.columns[0].slots.last)).should eq true | |
# end | |
# 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
class Column | |
attr_reader :position, :max_height, :slots | |
def initialize(position, max_height) | |
@position = position | |
@max_height = max_height | |
@slots = [] | |
end | |
def add_token(symbol) | |
token = Token.new(@position, @slots.length, symbol) | |
slots << token | |
end | |
def full? | |
@slots.length == max_height | |
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 'rspec' | |
require 'token' | |
require 'player' | |
require 'column' | |
describe Column do | |
it "is initialized with a position argument and a max height argument" do | |
column = Column.new(1, 7) | |
column.should be_an_instance_of Column | |
end | |
it "has a position" do | |
column = Column.new(7, 7) | |
column.position.should eq 7 | |
end | |
it "has a max height" do | |
column = Column.new(7, 6) | |
column.max_height.should eq 6 | |
end | |
it "has a a collection of slots" do | |
column = Column.new(2, 5) | |
column.slots.should eq [] | |
end | |
describe 'add_token' do | |
it "adds a token to slots" do | |
column = Column.new(2, 5) | |
column.add_token("&") | |
column.slots.first.should be_an_instance_of Token | |
end | |
it "adds a token to the end of slots" do | |
column = Column.new(2, 5) | |
column.add_token("&") | |
column.add_token("$") | |
column.slots.last.symbol.should eq "$" | |
end | |
end | |
describe 'full?' do | |
it 'is false if slots has not reached the max height' do | |
column = Column.new(2, 5) | |
column.full?.should eq false | |
end | |
it 'is true if the slots has reached the maximum' do | |
column = Column.new(2, 2) | |
column.add_token("&") | |
column.add_token("$") | |
column.full?.should eq true | |
end | |
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 './lib/game' | |
require './lib/board' | |
require './lib/player' | |
require './lib/column' | |
require './lib/token' | |
def init | |
puts "Welcome to Connect Four! How many people are playing?" | |
players = gets.chomp.to_i | |
@game = Game.new(players, 9, 7) | |
end | |
def main | |
draw_board | |
puts "\nSelect a column you would like to drop a token into" | |
column_choice = player_choice | |
if @game.board.winner?(@game.board.columns[column_choice - 1].slots.last, 4) | |
draw_board | |
puts "#{@game.current_player.symbol} has won!!!" | |
else | |
@game.switch_player | |
main | |
end | |
end | |
def player_choice | |
column_choice = gets.to_i | |
if !([email protected]).include?(column_choice) || @game.board.columns[column_choice - 1].full? | |
puts "\nPlease select a different column." | |
player_choice | |
else | |
@game.board.columns[column_choice - 1].add_token(@game.current_player.symbol) | |
end | |
column_choice | |
end | |
def draw_board | |
@game.board.height.times do |row_diff| | |
print "|" | |
@game.board.columns.each do |column| | |
if column.slots[@game.board.height - row_diff - 1].nil? | |
print " " | |
else | |
print column.slots[@game.board.height - row_diff - 1].symbol | |
end | |
print " | " | |
end | |
puts "" | |
puts "====" * @game.board.width | |
end | |
@game.board.width.times do |time| | |
print " #{time + 1} " | |
end | |
puts "" | |
end | |
init | |
main |
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 | |
attr_reader :players, :board, :current_player | |
def initialize(players, width, height) | |
@possible_symbols = ["$", "*", "%", "&"] | |
@players = [] | |
players.times do | |
player = Player.new(@possible_symbols.pop) | |
@players << player | |
end | |
@current_player = @players.first | |
@board = Board.new(width, height) | |
end | |
def switch_player | |
@players.rotate! | |
@current_player = @players.first | |
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 'rspec' | |
require 'game' | |
require 'board' | |
require 'player' | |
require 'column' | |
require 'token' | |
describe Game do | |
it 'initializes with a number of players, board height and width' do | |
game = Game.new(2, 9, 7) | |
game.should be_an_instance_of Game | |
end | |
it 'has players' do | |
game = Game.new(2, 9, 7) | |
game.players.length.should eq 2 | |
end | |
it 'has a board' do | |
game = Game.new(2, 9, 7) | |
game.board.should be_an_instance_of Board | |
end | |
it 'has a current player' do | |
game = Game.new(2, 9, 7) | |
game.current_player.should eq game.players[0] | |
end | |
describe 'switch_player' do | |
it 'switches the current player' do | |
game = Game.new(2, 9, 7) | |
game.switch_player | |
game.current_player.symbol.should eq "%" | |
end | |
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
class Player | |
attr_reader :symbol, :name | |
def initialize(symbol) | |
@symbol = symbol | |
end | |
def set_name(name) | |
@name = name | |
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 'rspec' | |
require 'token' | |
require 'player' | |
require 'column' | |
describe Player do | |
it "is initialized with a symbol argument" do | |
player = Player.new("$") | |
player.should be_an_instance_of Player | |
end | |
it "has a symbol" do | |
player = Player.new("~") | |
player.symbol.should eq "~" | |
end | |
describe "set_name" do | |
it "sets the name of the player" do | |
player = Player.new("&") | |
player.set_name("Frank") | |
player.name.should eq "Frank" | |
end | |
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
class Token | |
attr_reader :column_number, :row_number, :symbol | |
def initialize(column_number=nil, row_number=nil, symbol=nil) | |
@column_number = column_number | |
@row_number = row_number | |
@symbol = symbol | |
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 'rspec' | |
require 'token' | |
require 'column' | |
require 'player' | |
describe Token do | |
it 'is an instance of the Token class' do | |
token = Token.new | |
token.should be_an_instance_of Token | |
end | |
it 'has an x coordinate' do | |
token = Token.new(2) | |
token.column_number.should eq 2 | |
end | |
it 'has a row number' do | |
token = Token.new(2, 1) | |
token.row_number.should eq 1 | |
end | |
it 'has a symbol' do | |
token = Token.new(1, 1, "&") | |
token.symbol.should eq "&" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment