class ConnectFourBoard
AIM = 4 # number of neighbouring tokens to obtain
def initialize(rows,columns)
@rows = rows # number of rows
@columns = columns # number of columns
@board = Array.new(@columns)
end
# A player drop a token in the board at a certain position
def drop_token(player,column)
if @board[column] == nil
@board[column] = Array.new
end
if @board[column].length == @rows
raise RuntimeException
end
@board[column].push(Token.new(player))
end
# check the presencd of a token at a certain position in the board
def position(row,column)
col = @board[column]
if !col.nil?
position = col[row];
else
return nil
end
end
# empty board
def reset
@board.each do |column|
column = nil
end
@board = nil
initialize(@rows,@columns)
end
# check if a player has won
def check_winner(player)
win = vertical_count(player) || horizontal_count(player) ||
diagonal_count(player) || back_diagonal_count(player)
end
private
# check if there was a victory in vertical direction of board
def vertical_count(player)
win = false
@board.each do |column|
counter = 0
if column.nil?
next
end
column.each do |position|
counter = increment(position,player,counter)
win = win || win(counter) #if won it stays won
end
end
win # return if won
end
# check if there was a victory in the horizontal direction of board
def horizontal_count(player)
win = false
(0..@rows-1).each do |row|
counter = 0
@board.each_with_index do |column,column_index|
if column.nil?
counter = 0
end
position = position(row,column_index)
counter = increment(position,player,counter)
win = win || win(counter) # if won it stays won
end
end
win # return if won
end
# back_diagonal_count counts the tokens from a same player in diagonal line
# the "back" stands for \ (backslash) as in the direction of the diagonal
def back_diagonal_count(player)
win = false
(AIM-1..@columns-1).each do |i|
counter = 0
rowlimit = @rows-1 > i ? i : @rows-1
(0..rowlimit).each do |j|
position = position (j,i-j)
counter = increment(position,player,counter)
win = win || win(counter)
end
end
win # return if won
end
# diagonal_count counts the tokens from a same player in diagonal line
# the counting happens in the / direction (slash) = direction of the diagonal
def diagonal_count(player)
win = false
(0..@columns-AIM).each do |i|
counter = 0
rowlimit = @rows-1-i
(0..rowlimit).each do |j|
position = position(j,i+j)
counter = increment(position,player,counter)
win = win || win(counter)
end
end
win
end
def increment(position,player,counter)
if position && position.player == player
return counter.next
else
return 0
end
end
def win(counter)
if counter >= AIM
return true
else
return false
end
end
# for debugging purposes: to display the board as 0 and 1
def board_debug
(0..@rows-1).each do |row|
@board.each_with_index do |column,index|
position = position(@rows-1-row,index)
if position
printf("#{position.player.to_i}")
else
printf(" ")
end
end
printf("\n")
end
end
end
# class token in board
class Token
def initialize(player)
@player = player
end
def player
@player
end
end
Refactorings
No refactoring yet !
Jeremy Weiskotten
January 2, 2008, January 02, 2008 00:48, permalink
Some minor changes... original algorithm is pretty much intact but you could simplify if a bit. The changes I made were mostly to use common Ruby conventions and idioms, like ||= and question marks in the names of methods that return a Boolean.
class ConnectFourBoard
AIM = 4 # number of neighbouring tokens to obtain
def initialize(rows, columns)
@rows = rows # number of rows
@columns = columns # number of columns
end
# A player drop a token in the board at a certain position
def drop_token(player, column)
col = get_column(column)
raise RuntimeException if col.length == @rows
col << Token.new(player)
end
# check the presence of a token at a certain position in the board
def position(row, column)
col = get_column(column)
return col[row] unless col.nil?
end
# empty board
def reset
@board = nil
end
# check if a player has won
def check_winner?(player)
vertical_count?(player) ||
horizontal_count?(player) ||
diagonal_count?(player) ||
back_diagonal_count?(player)
end
private
def board
# lazy initialize the game board
@board ||= Array.new(@columns)
end
def get_column(c)
# lazy initialize the column
board[c] ||= []
end
def max_row_index
@rows - 1
end
# check if there was a victory in vertical direction of board
def vertical_count?(player)
win = false
board.each do |column|
unless column.nil?
counter = 0
column.each do |position|
counter = increment(position, player, counter)
win ||= win?(counter) #if won it stays won
end
end
end
win # return if won
end
# check if there was a victory in the horizontal direction of board
def horizontal_count?(player)
win = false
(0...@rows).each do |row|
counter = 0
board.each_with_index do |column, column_index|
counter = 0 if column.nil?
position = position(row, column_index)
counter = increment(position, player, counter)
win ||= win?(counter) # if won it stays won
end
end
win # return if won
end
# back_diagonal_count counts the tokens from a same player in diagonal line
# the "back" stands for \ (backslash) as in the direction of the diagonal
def back_diagonal_count?(player)
win = false
(AIM-1...@columns).each do |i|
counter = 0
rowlimit = max_row_index > i ? i : max_row_index
(0..rowlimit).each do |j|
position = position (j,i-j)
counter = increment(position, player, counter)
win ||= win?(counter)
end
end
win # return if won
end
# diagonal_count counts the tokens from a same player in diagonal line
# the counting happens in the / direction (slash) = direction of the diagonal
def diagonal_count?(player)
win = false
(0..@columns-AIM).each do |i|
counter = 0
rowlimit = max_row_index-i
(0..rowlimit).each do |j|
position = position(j,i+j)
counter = increment(position, player, counter)
win ||= win?(counter)
end
end
win
end
def increment(position, player, counter)
if position && position.player == player
return counter.next
else
return 0
end
end
def win?(counter)
counter >= AIM
end
# for debugging purposes: to display the board as 0 and 1
def board_debug
(0...@rows).each do |row|
board.each_with_index do |column, index|
position = position(max_row_index-row, index)
if position
printf("#{position.player.to_i}")
else
printf(" ")
end
end
printf("\n")
end
end
end
# class token in board
class Token
def initialize(player); @player = player; end
def player; @player; end
end
lionkakronkel
December 23, 2009, December 23, 2009 21:41, permalink
Hi,
I am delighted to land here. It is a great forum
<a href=http://www.assfuckdolls.com>ass fuck</a>
You probably know the game of connect-four. 2 player alternatively drop a token in a grid (which i called board). I wrote the following ruby classes for the game. The board is organized in columns (in which you drop the tokens).
All suggestions are welcome, i'll enjoy seeing any suggestions or variations !
I'm an experienced developer, but not in Ruby.