class GlimmerTetris::Model::Tetromino
Constants
- LETTER_COLORS
- ORIENTATIONS
Attributes
blocks[RW]
column[RW]
game[R]
letter[R]
orientation[RW]
preview[R]
preview?[R]
row[RW]
Public Class Methods
new(game)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 45 def initialize(game) @game = game @letter = LETTER_COLORS.keys.sample @orientation = :north @blocks = default_blocks @preview = true new_row = 0 new_column = (Model::Game::PREVIEW_PLAYFIELD_WIDTH - width)/2 update_playfield(new_row, new_column) end
Public Instance Methods
add_to_playfield()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 78 def add_to_playfield update_playfield_block do |playfield_row, playfield_column, row_index, column_index| playfield[playfield_row][playfield_column].color = blocks[row_index][column_index].color if playfield_row >= 0 && playfield[playfield_row][playfield_column]&.clear? && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column].color != blocks[row_index][column_index].color end end
bottom_most_block_for_column(column)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 123 def bottom_most_block_for_column(column) bottom_most_blocks.detect {|bottom_most_block| (@column + bottom_most_block[:column_index]) == column} end
bottom_most_blocks()
click to toggle source
Returns bottom-most blocks of a tetromino, which could be from multiple rows depending on shape (e.g. T)
# File app/glimmer_tetris/model/tetromino.rb, line 108 def bottom_most_blocks width.times.map do |column_index| row_blocks_with_row_index = @blocks.each_with_index.to_a.reverse.detect do |row_blocks, row_index| !row_blocks[column_index].clear? end bottom_most_block = row_blocks_with_row_index[0][column_index] bottom_most_block_row = row_blocks_with_row_index[1] { block: bottom_most_block, row_index: bottom_most_block_row, column_index: column_index } end end
color()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 300 def color LETTER_COLORS[@letter] end
default_blocks()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 261 def default_blocks case @letter when :I [ [block, block, block, block] ] when :J [ [block, block, block], [empty, empty, block], ] when :L [ [block, block, block], [block, empty, empty], ] when :O [ [block, block], [block, block], ] when :S [ [empty, block, block], [block, block, empty], ] when :T [ [block, block, block], [empty, block, empty], ] when :Z [ [block, block, empty], [empty, block, block], ] end end
down!(instant: false)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 185 def down!(instant: false) launch! if preview? unless stopped? block_count = 1 if instant remaining_height, bottom_touching_block = remaining_height_and_bottom_touching_block block_count = remaining_height - @row end new_row = @row + block_count update_playfield(new_row, @column) end end
height()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 181 def height @blocks.size end
hypothetical_tetromino()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 242 def hypothetical_tetromino clone.tap do |hypo_clone| remove_from_playfield hypo_clone.blocks = @blocks.map do |row_blocks| row_blocks.map do |column_block| column_block.clone end end end end
include_block?(block)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 304 def include_block?(block) @blocks.flatten.include?(block) end
launch!()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 60 def launch! remove_from_playfield @preview = false new_row = 1 - height new_column = (game.playfield_width - width)/2 update_playfield(new_row, new_column) game.tetrominoes << self end
left!()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 198 def left! unless left_blocked? new_column = @column - 1 update_playfield(@row, new_column) end end
left_blocked?()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 152 def left_blocked? (@column == 0) || left_most_blocks.any? { |left_most_block| (@row + left_most_block[:row_index]) >= 0 && playfield[@row + left_most_block[:row_index]][@column + left_most_block[:column_index] - 1].occupied? } end
left_most_blocks()
click to toggle source
Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
# File app/glimmer_tetris/model/tetromino.rb, line 161 def left_most_blocks @blocks.each_with_index.map do |row_blocks, row_index| column_block_with_column_index = row_blocks.each_with_index.to_a.detect do |column_block, column_index| !column_block.clear? end if column_block_with_column_index left_most_block = column_block_with_column_index[0] { block: left_most_block, row_index: row_index, column_index: column_block_with_column_index[1] } end end.compact end
playfield()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 56 def playfield @preview ? game.preview_playfield : game.playfield end
remaining_height_and_bottom_touching_block()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 253 def remaining_height_and_bottom_touching_block playfield_remaining_heights = game.playfield_remaining_heights(self) bottom_most_blocks.map do |bottom_most_block| playfield_column = @column + bottom_most_block[:column_index] [playfield_remaining_heights[playfield_column] - (bottom_most_block[:row_index] + 1), bottom_most_block] end.min_by(&:first) end
remove_from_playfield()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 84 def remove_from_playfield return if @row.nil? || @column.nil? update_playfield_block do |playfield_row, playfield_column, row_index, column_index| playfield[playfield_row][playfield_column].clear if playfield_row >= 0 && !blocks[row_index][column_index].clear? && playfield[playfield_row][playfield_column]&.color == color end end
right!()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 205 def right! unless right_blocked? new_column = @column + 1 update_playfield(@row, new_column) end end
right_blocked?()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 127 def right_blocked? (@column == game.playfield_width - width) || right_most_blocks.any? { |right_most_block| (@row + right_most_block[:row_index]) >= 0 && playfield[@row + right_most_block[:row_index]][@column + right_most_block[:column_index] + 1].occupied? } end
right_most_blocks()
click to toggle source
Returns right-most blocks of a tetromino, which could be from multiple columns depending on shape (e.g. T)
# File app/glimmer_tetris/model/tetromino.rb, line 136 def right_most_blocks @blocks.each_with_index.map do |row_blocks, row_index| column_block_with_column_index = row_blocks.each_with_index.to_a.reverse.detect do |column_block, column_index| !column_block.clear? end if column_block_with_column_index right_most_block = column_block_with_column_index[0] { block: right_most_block, row_index: row_index, column_index: column_block_with_column_index[1] } end end.compact end
rotate!(direction)
click to toggle source
Rotate in specified direcation, which can be :right (clockwise) or :left (counterclockwise)
# File app/glimmer_tetris/model/tetromino.rb, line 213 def rotate!(direction) return if stopped? can_rotate = nil new_blocks = nil game.hypothetical do hypothetical_rotated_tetromino = hypothetical_tetromino new_blocks = hypothetical_rotated_tetromino.rotate_blocks(direction) can_rotate = !hypothetical_rotated_tetromino.stopped? && !hypothetical_rotated_tetromino.right_blocked? && !hypothetical_rotated_tetromino.left_blocked? end if can_rotate remove_from_playfield self.orientation = ORIENTATIONS[ORIENTATIONS.rotate(direction == :right ? -1 : 1).index(@orientation)] self.blocks = new_blocks update_playfield(@row, @column) end rescue => e puts e.full_message end
rotate_blocks(direction)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 232 def rotate_blocks(direction) new_blocks = Matrix[*@blocks].transpose.to_a if direction == :right new_blocks = new_blocks.map(&:reverse) else new_blocks = new_blocks.reverse end Matrix[*new_blocks].to_a end
stopped?()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 91 def stopped? return true if @stopped || @preview playfield_remaining_heights = game.playfield_remaining_heights(self) result = bottom_most_blocks.any? do |bottom_most_block| playfield_column = @column + bottom_most_block[:column_index] playfield_remaining_heights[playfield_column] && @row + bottom_most_block[:row_index] >= playfield_remaining_heights[playfield_column] - 1 end if result && !game.hypothetical? @stopped = result game.consider_eliminating_lines @game.consider_adding_tetromino end result end
update_playfield(new_row = nil, new_column = nil)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 69 def update_playfield(new_row = nil, new_column = nil) remove_from_playfield if !new_row.nil? && !new_column.nil? @row = new_row @column = new_column add_to_playfield end end
width()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 177 def width @blocks[0].size end
Private Instance Methods
block()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 310 def block Block.new(color) end
empty()
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 314 def empty Block.new end
update_playfield_block(&updater)
click to toggle source
# File app/glimmer_tetris/model/tetromino.rb, line 318 def update_playfield_block(&updater) @row.upto(@row + height - 1) do |playfield_row| @column.upto(@column + width - 1) do |playfield_column| row_index = playfield_row - @row column_index = playfield_column - @column updater.call(playfield_row, playfield_column, row_index, column_index) end end end