1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
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
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.