' ' falling blocks - tetris clone ' option predef grmode 300x300 ' cell size in pixels const c_w = 10 const c_h = 10 ' board position const b_x = 40 const b_y = 10 ' board size const b_w = 12 const b_h = 28 ' board color const b_col = rgb(111,199,222) ' the number of available play blocks const num_blocks = 5 ' holder for board pieces dim blocks(0 to num_blocks - 1) ' remember used positions dim board(0 to b_w - 1, 0 to b_h - 1) ' event loop delay factor drop_speed = 300 ' whether the game is over game_over = false ' number of played shapes num_shapes = 0 ' number of completed rows num_rows = 0 ' ' block, rotation, x+y coordinates on the game board ' sub draw_block(b, r, pos_x, pos_y, c) local x, y, px, py for x = 0 to 3 for y = 0 to 3 if b(r)(x, y) = 1 then px = b_x + ((pos_x + x) * c_w) py = b_y + ((pos_y + y) * c_h) rect px, py, step c_w, c_h, c filled fi next y next x SHOWPAGE end ' ' show the given block ' sub show_block(block) draw_block block.b, block.r, block.x, block.y, block.col end ' ' erase the given block ' sub hide_block(block) draw_block block.b, block.r, block.x, block.y, b_col end ' ' returns the right edge of the given block ' func right_edge(block) local x, y, r r = block.r for x = 3 to 0 step -1 for y = 0 to 3 if block.b(r)(x, y) = 1 then right_edge = x + 1 exit func fi next y next x end ' ' create one of the four block rotations ' func create_cell local x, y, result dim result(0 to 3, 0 to 3) for y = 0 to 3 for x = 0 to 3 read result(x, y) next x next y create_cell = result end ' ' creates 4 rotations of a 4 x 4 pattern. address like this: b(0)(1,1) ' func create_block local i, result dim result(0 to 3) for i = 0 to 3 result(i) = create_cell next i create_block = result end ' ' draw the board outline ' sub draw_board(x1, y1) local w = b_w * c_w local h = b_h * c_h rect x1, y1, step w, h, b_col filled local x, y, px, py for y = b_h -1 to 0 step -1 for x = 0 to b_w -1 if (board(x, y) != 0) then px = x1 + (x * c_w) py = y1 + (y * c_h) rect px, py, step c_w, c_h, board(x, y) filled fi next x next y end ' ' creates a new active block ' func next_block local i = int(rnd * num_blocks) result.b = blocks(i) result.r = int(rnd * 4) result.col = i + 2 result.x = b_w / 2 result.y = 0 show_block result num_shapes++ next_block = result end ' ' prepare the game board ' sub init_game local i, x, y ' create the blocks for i = 0 to num_blocks - 1 blocks(i) = create_block next i ' setup the bottom boundary holder for x = 0 to b_w - 1 for y = 0 to b_h - 1 board(x, y) = 0 next y next x draw_board b_x, b_y randomize timer end ' ' handle row completion ' func row_completed local x, y, n, x2, y2 row_completed = 0 for y = b_h -1 to 0 step -1 n = 0 for x = 0 to b_w -1 if (board(x, y) != 0) then n++ fi next x if (n == b_w) then ' erase the completed row for y2 = y to 1 step -1 for x2 = 0 to b_w - 1 board(x2, y2) = board(x2, y2 - 1) next x2 next y2 ' clear the top row for x2 = 0 to b_w - 1 board(x2, 0) = 0 next x2 y += 1 'next row now in y row_completed = 1 fi next y end ' ' whether the block can move any further down ' func is_bottom(block) local x, y local br = block.r local bx = block.x local by = block.y local touch = false for y = 3 to 0 step -1 for x = 0 to 3 if (block.b(br)(x, y) = 1 && & (by + y + 1 == b_h || board(bx + x, by + y + 1) != 0)) then touch = true fi next x next y if (touch) then ' check for end of game for y = 3 to 0 step -1 for x = 0 to 3 if (block.b(br)(x, y) = 1) then if (by == 0 || (by < 4 && board(bx + x, by + y) != 0)) then game_over = true exit func fi fi next x next y ' record the resting position on the board for y = 3 to 0 step -1 for x = 0 to 3 if (block.b(br)(x, y) = 1) then board(bx + x, by + y) = block.col fi next x next y fi is_bottom = touch end ' ' update the block position by the given offsets ' sub moveBlock(x, y) hide_block block block.x += x block.y += y show_block block end ' ' move the block left ' sub moveLeft if (block.x > 0) then moveBlock -1, 0 fi end ' ' move the block right ' sub moveRight if ((block.x + right_edge(block)) < b_w) then moveBlock 1, 0 fi end ' ' rotate the block ' sub moveRotate hide_block block block.r = iff(block.r == 3, 0, block.r+1) ' ensure rotation doesn't extend beyond board while ((block.x + right_edge(block)) > b_w) block.x -- wend show_block block end ' ' drop the block ' sub dropBlock while !is_bottom(block) moveBlock 0, 1 wend end ' ' show game statistics ' sub show_stats at b_x + (b_w * c_w) + 10, b_y: ? "Shapes:"; num_shapes at b_x + (b_w * c_w) + 10, b_y+20: ? "Rows:"; num_rows at b_x + (b_w * c_w) + 10, b_y+40: ? "Speed:"; drop_speed end ' ' main game loop ' sub play_game block = next_block show_stats while game_over = false delay drop_speed ' check for collision if is_bottom(block) then show_block block 'show final position erase block if row_completed then num_rows++ draw_board b_x, b_y drop_speed -= 20 fi block = next_block show_stats else ' drop the block down one position moveBlock 0, 1 fi wend end defineKey 0xFF04, moveLeft defineKey 0xFF05, moveRight defineKey 0xFF09, moveRotate defineKey asc(" "), dropBlock init_game play_game ' ' define the game pieces ' 'block 1 - bar data 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 data 1,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0 data 1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0 data 1,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0 'block 2 - elbow data 1,0,0,0, 1,0,0,0, 1,1,0,0, 0,0,0,0 data 1,1,1,0, 1,0,0,0, 0,0,0,0, 0,0,0,0 data 0,1,1,0, 0,0,1,0, 0,0,1,0, 0,0,0,0 data 0,0,0,0, 0,0,1,0, 1,1,1,0, 0,0,0,0 'block 3 - tee data 1,1,1,0, 0,1,0,0, 0,0,0,0, 0,0,0,0 data 0,1,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0 data 0,1,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0 data 1,0,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0 'block 4 - cube data 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 data 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 data 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 data 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 'block 5 - s-bend data 1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0 data 0,1,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0 data 1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0 data 0,1,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0