# rubocop:disable Metrics/ClassLength module Model class TileCollection attr_reader :dimensions def initialize(tiles, dimensions) raise ArgumentError, 'empty tiles array' if tiles.empty? raise ArgumentError, 'dimensions do not match tiles length' if tiles.length != dimensions**2 @dimensions = dimensions @tiles = tiles.each_with_index do |tile, i| tile.col = col_index(i) tile.row = row_index(i) end end def id @tiles.each_with_object('') do |tile, str| str << tile.piece_name str end end def each(&block) @tiles.each(&block) end def rows return @rows unless @rows.nil? i = 0 @rows = [] while i < @tiles.count j = i + 3 @rows << @tiles[i...j] i = j end @rows end def available_tiles @tiles.find_all(&:available?) end def available_tiles? available_tiles.count.positive? end def find_tile(row, col) @tiles[index(row.to_i, col.to_i)] end # Any given TicTacToe board has 8 equivalent boards, which are generated by flipping and rotating a board. def equivalents next_tile_collections = [] i = 4 next_tc = self while i.positive? rotated = next_tc.rotate next_tile_collections << rotated next_tile_collections << rotated.flip next_tc = rotated i -= 1 end next_tile_collections end def clone(tiles = nil) tiles ||= clone_tiles self.class.new(tiles, dimensions) end protected def rotate tiles = clone_tiles rotated = [] rotated_col_i = dimensions (1..dimensions).each do |row_i| (1..dimensions).each do |col_i| rotate_tile(row_i, col_i, rotated_col_i, rotated, tiles) end rotated_col_i -= 1 end clone(rotated) end def flip tiles = clone_tiles top_row_i = 1 bottom_row_i = dimensions while top_row_i <= (dimensions / 2) (1..dimensions).each do |col_i| flip_tile(top_row_i, bottom_row_i, col_i, tiles) end top_row_i += 1 bottom_row_i -= 1 end clone(tiles) end private def flip_tile(top_row_i, bottom_row_i, col_i, tiles) top_i = index(top_row_i, col_i) bottom_i = index(bottom_row_i, col_i) top = tiles[top_i] bottom = tiles[bottom_i] top.row = bottom_row_i bottom.row = top_row_i tiles[top_i] = bottom tiles[bottom_i] = top end def rotate_tile(row_i, col_i, rotated_col_i, rotated, tiles) tile_i = index(row_i, col_i) rotated_tile_i = index(col_i, rotated_col_i) tile = tiles[tile_i] tile.row = col_i tile.col = rotated_col_i rotated[rotated_tile_i] = tile end def clone_tiles @tiles.map(&:clone) end def index(row, col) r = row - 1 c = col - 1 dimensions * r + c end def row_index(index) (index / dimensions) + 1 end def col_index(index) (index % dimensions) + 1 end end end # rubocop:enable Metrics/ClassLength