For this challenge we are creating a game of Tetris to play on the BBC micro:bit.
The game will be based on the following four shapes:
The game will use the following inputs:
- Button A: Move current brick to the left
- Button B: Move current brick to the right
- Button A and B simultaneously: Rotate current brick clockwise
Video Demo
The game will use the LED screen which consists of a 5×5 grid of 25 LEDs.
Each LED can be on (value: 9 for maximum brightness) or Off (value: 0)
The side/borders of the grid will note be displayed.
The Python code will use 2-dimension arrays (list of lists in Python) to store the main grid (7×5) and the current brick (2×2)
To test this code you will need to use the Python Editor from the micro:bit website.
Python Code
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 |
from microbit import * from random import choice #Set up the tetris grid grid=[[1,0,0,0,0,0,1],[1,0,0,0,0,0,1],[1,0,0,0,0,0,1],[1,0,0,0,0,0,1],[1,0,0,0,0,0,1],[1,1,1,1,1,1,1]] #Store a list of 4 bricks, each brick is a 2x2 grid bricks = [[9,9],[9,0]],[[9,9],[0,9]],[[9,9],[9,9]],[[9,9],[0,0]] #select a brick randomly and position it at the center/top of the grid (y=0,x=3) brick = choice(bricks) x=3 y=0 frameCount=0 #A function to return the maximum of two values def max(a,b): if a>=b: return a else: return b #A function to hide the 2x2 brick on the LED screen def hideBrick(): if x>0: display.set_pixel(x-1,y,grid[y][x]) if x<5: display.set_pixel(x+1-1,y,grid[y][x+1]) if x>0 and y<4: display.set_pixel(x-1,y+1,grid[y+1][x]) if x<5 and y<4: display.set_pixel(x+1-1,y+1,grid[y+1][x+1]) #A function to show the 2x2 brick on the LED screen def showBrick(): if x>0: display.set_pixel(x-1,y,max(brick[0][0],grid[y][x])) if x<5: display.set_pixel(x+1-1,y,max(brick[0][1],grid[y][x+1])) if x>0 and y<4: display.set_pixel(x-1,y+1,max(brick[1][0],grid[y+1][x])) if x<5 and y<4: display.set_pixel(x+1-1,y+1,max(brick[1][1],grid[y+1][x+1])) #A function to rotate the 2x2 brick def rotateBrick(): pixel00 = brick[0][0] pixel01 = brick[0][1] pixel10 = brick[1][0] pixel11 = brick[1][1] #Check if the rotation is possible if not ((grid[y][x]>0 and pixel00>0) or (grid[y+1][x]>0 and pixel10>0) or (grid[y][x+1]>0 and pixel01>0) or (grid[y+1][x+1]>0 and pixel11>0)): hideBrick() brick[0][0] = pixel10 brick[1][0] = pixel11 brick[1][1] = pixel01 brick[0][1] = pixel00 showBrick() #A function to move/translate the brick def moveBrick(delta_x,delta_y): global x,y move=False #Check if the move if possible: no collision with other blocks or borders of the grid if delta_x==-1 and x>0: if not ((grid[y][x-1]>0 and brick[0][0]>0) or (grid[y][x+1-1]>0 and brick[0][1]>0) or (grid[y+1][x-1]>0 and brick[1][0]>0) or (grid[y+1][x+1-1]>0 and brick[1][1]>0)): move=True elif delta_x==1 and x<5: if not ((grid[y][x+1]>0 and brick[0][0]>0) or (grid[y][x+1+1]>0 and brick[0][1]>0) or (grid[y+1][x+1]>0 and brick[1][0]>0) or (grid[y+1][x+1+1]>0 and brick[1][1]>0)): move=True elif delta_y==1 and y<4: if not ((grid[y+1][x]>0 and brick[0][0]>0) or (grid[y+1][x+1]>0 and brick[0][1]>0) or (grid[y+1+1][x]>0 and brick[1][0]>0) or (grid[y+1+1][x+1]>0 and brick[1][1]>0)): move=True #If the move is possible, update x,y coordinates of the brick if move: hideBrick() x+=delta_x y+=delta_y showBrick() #Return True or False to confirm if the move took place return move #A function to check for and remove completed lines def checkLines(): global score removeLine=False #check each line one at a time for i in range(0, 5): #If 5 blocks are filled in (9) then a line is complete (9*5=45) if (grid[i][1]+grid[i][2]+grid[i][3]+grid[i][4]+grid[i][5])==45: removeLine = True #Increment the score (10 pts per line) score+=10 #Remove the line and make all lines above fall by 1: for j in range(i,0,-1): grid[j] = grid[j-1] grid[0]=[1,0,0,0,0,0,1] if removeLine: #Refresh the LED screen for i in range(0, 5): for j in range(0, 5): display.set_pixel(i,j,grid[j][i+1]) return removeLine gameOn=True score=0 showBrick() #Main Program Loop - iterates every 50ms while gameOn: sleep(50) frameCount+=1 #Capture user inputs if button_a.is_pressed() and button_b.is_pressed(): rotateBrick() elif button_a.is_pressed(): moveBrick(-1,0) elif button_b.is_pressed(): moveBrick(1,0) #Every 15 frames try to move the brick down if frameCount==15 and moveBrick(0,1) == False: frameCount=0 #The move was not possible, the brick stays in position grid[y][x]=max(brick[0][0],grid[y][x]) grid[y][x+1]=max(brick[0][1],grid[y][x+1]) grid[y+1][x]=max(brick[1][0],grid[y+1][x]) grid[y+1][x+1]=max(brick[1][1],grid[y+1][x+1]) if checkLines()==False and y==0: #The brick has reached the top of the grid - Game Over gameOn=False else: #select a new brick randomly x=3 y=0 brick = choice(bricks) showBrick() if frameCount==15: frameCount=0 #End of Game sleep(2000) display.scroll("Game Over: Score: " + str(score)) |
Note: When testing this code, you may want to remove some of the #annotations especially if your micro:bit returns a “memory full” error.