nrf5/examples: Adding 2048 game using OLED SSD1306 128x64 display and analog joystick.
This commit is contained in:
parent
73be85dd6d
commit
b0a730d482
|
@ -0,0 +1,348 @@
|
|||
# This file is part of the Micro Python project, http://micropython.org/
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2017 Glenn Ruben Bakke
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
'''
|
||||
Usage:
|
||||
|
||||
from game2048 import Game
|
||||
g = Game()
|
||||
g.start()
|
||||
|
||||
'''
|
||||
|
||||
from machine import ADC
|
||||
from machine import Pin, SPI
|
||||
from display import SSD1306
|
||||
import draw
|
||||
import time
|
||||
|
||||
font_128 = [
|
||||
" x xx xx",
|
||||
" xx x x x x",
|
||||
"x x x x x",
|
||||
" x x xx",
|
||||
" x x x x",
|
||||
" x x x x",
|
||||
" xxx xxxx xx"
|
||||
]
|
||||
|
||||
font_256 = [
|
||||
" xx xxxx xx",
|
||||
"x x x x x",
|
||||
" x xxx x ",
|
||||
" x x xxxx",
|
||||
" x x x x",
|
||||
"x x x x",
|
||||
"xxxx xxx xx"
|
||||
]
|
||||
|
||||
font_512 = [
|
||||
"xxxx x xx",
|
||||
"x xx x x",
|
||||
"xxx x x x",
|
||||
" x x x",
|
||||
" x x x",
|
||||
" x x x",
|
||||
"xxx xxx xxxx"
|
||||
]
|
||||
|
||||
font_1024 = [
|
||||
" xx x x x x",
|
||||
"x x x x x x x x",
|
||||
" x x x x x x",
|
||||
" x x x x xxx",
|
||||
" x x x x x",
|
||||
" x x x x x",
|
||||
" x x xxx x"
|
||||
]
|
||||
|
||||
font_2048 = [
|
||||
" x x x x x",
|
||||
"x x x x x x x x",
|
||||
" x x x x x x x",
|
||||
" x x x xxx x",
|
||||
"x x x x x x",
|
||||
"x x x x x x",
|
||||
"xxx x x x"
|
||||
]
|
||||
|
||||
DIR_UP = const(0x1)
|
||||
DIR_DOWN = const(0x2)
|
||||
DIR_LEFT = const(0x3)
|
||||
DIR_RIGHT = const(0x4)
|
||||
DIR_CENTER = const(0x5)
|
||||
|
||||
class Game:
|
||||
def __init__(self):
|
||||
|
||||
# # setup harware for nrf51822 / pca10028
|
||||
# cs = Pin("A14", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
# reset = Pin("A13", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
# dc = Pin("A12", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
# spi = SPI(0, baudrate=8000000)
|
||||
# self.screen = SSD1306(128, 64, spi, cs, dc, reset)
|
||||
# self.x_adc = ADC(2)
|
||||
# self.y_adc = ADC(3)
|
||||
# self.adc_threshold = 205
|
||||
|
||||
# setup harware for nrf52840 / pca10056
|
||||
cs = Pin("B3", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
reset = Pin("B2", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
dc = Pin("B1", mode=Pin.OUT, pull=Pin.PULL_UP)
|
||||
spi = SPI(0, baudrate=8000000)
|
||||
self.screen = SSD1306(128, 64, spi, cs, dc, reset)
|
||||
self.x_adc = ADC(1)
|
||||
self.y_adc = ADC(2)
|
||||
self.adc_threshold = 130
|
||||
|
||||
# game setup
|
||||
self.grid = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
|
||||
self._rand = 1337
|
||||
self.not_game_over = True
|
||||
self.score = 0
|
||||
|
||||
|
||||
def move(self, dir):
|
||||
if (dir == DIR_UP):
|
||||
# float up
|
||||
for col in range(0, 4):
|
||||
for row1 in range(1, 5):
|
||||
for row0 in range(1, row1):
|
||||
if self.grid[col][row0 - 1] == 0:
|
||||
if self.grid[col][row0]:
|
||||
self.grid[col][row0 - 1] = self.grid[col][row0]
|
||||
self.grid[col][row0] = 0
|
||||
# collapse
|
||||
for col in range(0, 4):
|
||||
for row0 in range(0, 3):
|
||||
if self.grid[col][row0] == self.grid[col][row0 + 1]:
|
||||
self.grid[col][row0] += self.grid[col][row0]
|
||||
self.score += self.grid[col][row0]
|
||||
self.grid[col][row0 + 1] = 0
|
||||
# float up
|
||||
for col in range(0, 4):
|
||||
for row1 in range(1, 5):
|
||||
for row0 in range(1, row1):
|
||||
if self.grid[col][row0 - 1] == 0:
|
||||
if self.grid[col][row0]:
|
||||
self.grid[col][row0 - 1] = self.grid[col][row0]
|
||||
self.grid[col][row0] = 0
|
||||
elif (dir == DIR_DOWN):
|
||||
# float down
|
||||
for col in range(0, 4):
|
||||
for row1 in range(1, 5):
|
||||
for row0 in range(row1, 4):
|
||||
if self.grid[col][row0] == 0:
|
||||
if self.grid[col][row0 - 1]:
|
||||
self.grid[col][row0] = self.grid[col][row0 - 1]
|
||||
self.grid[col][row0 - 1] = 0
|
||||
# collapse
|
||||
for col in range(0, 4):
|
||||
for row0 in range(1, 4):
|
||||
if self.grid[col][row0] == self.grid[col][row0 - 1]:
|
||||
self.grid[col][row0] += self.grid[col][row0]
|
||||
self.score += self.grid[col][row0]
|
||||
self.grid[col][row0 - 1] = 0
|
||||
# float down
|
||||
for col in range(0, 4):
|
||||
for row1 in range(1, 5):
|
||||
for row0 in range(row1, 4):
|
||||
if self.grid[col][row0] == 0:
|
||||
if self.grid[col][row0 - 1]:
|
||||
self.grid[col][row0] = self.grid[col][row0 - 1]
|
||||
self.grid[col][row0 - 1] = 0
|
||||
elif (dir == DIR_LEFT):
|
||||
# float left
|
||||
for row in range(0, 4):
|
||||
for col1 in range(1, 5):
|
||||
for col0 in range(1, col1):
|
||||
if self.grid[col0 - 1][row] == 0:
|
||||
if self.grid[col0][row]:
|
||||
self.grid[col0 - 1][row] = self.grid[col0][row]
|
||||
self.grid[col0][row] = 0
|
||||
# collapse
|
||||
for row in range(0, 4):
|
||||
for col0 in range(0, 3):
|
||||
if self.grid[col0][row] == self.grid[col0 + 1][row]:
|
||||
self.grid[col0][row] += self.grid[col0][row]
|
||||
self.score += self.grid[col0][row]
|
||||
self.grid[col0 + 1][row] = 0
|
||||
# float left
|
||||
for row in range(0, 4):
|
||||
for col1 in range(1, 5):
|
||||
for col0 in range(1, col1):
|
||||
if self.grid[col0 - 1][row] == 0:
|
||||
if self.grid[col0][row]:
|
||||
self.grid[col0 - 1][row] = self.grid[col0][row]
|
||||
self.grid[col0][row] = 0
|
||||
elif (dir == DIR_RIGHT):
|
||||
# float right
|
||||
for row in range(0, 4):
|
||||
for col1 in range(1, 5):
|
||||
for col0 in range(col1, 4):
|
||||
if self.grid[col0][row] == 0:
|
||||
if self.grid[col0 - 1][row]:
|
||||
self.grid[col0][row] = self.grid[col0 - 1][row]
|
||||
self.grid[col0 - 1][row] = 0
|
||||
# collapse
|
||||
for row in range(0, 4):
|
||||
for col0 in range(1, 4):
|
||||
if self.grid[col0][row] == self.grid[col0 - 1][row]:
|
||||
self.grid[col0][row] += self.grid[col0][row]
|
||||
self.score += self.grid[col0][row]
|
||||
self.grid[col0 - 1][row] = 0
|
||||
# float right
|
||||
for row in range(0, 4):
|
||||
for col1 in range(1, 5):
|
||||
for col0 in range(col1, 4):
|
||||
if self.grid[col0][row] == 0:
|
||||
if self.grid[col0 - 1][row]:
|
||||
self.grid[col0][row] = self.grid[col0 - 1][row]
|
||||
self.grid[col0 - 1][row] = 0
|
||||
def set_val(self, x, y, val):
|
||||
self.grid[x][y] = val
|
||||
def get_val(self, x, y):
|
||||
return self.grid[x][y]
|
||||
def draw_high_number(self, font, x, y):
|
||||
for rel_y, line in enumerate(font):
|
||||
for rel_x in range(0, len(line)):
|
||||
if (line[rel_x] == 'x'):
|
||||
self.screen.pixel(x + rel_x, y + rel_y, 1)
|
||||
def draw_tile(self, x, y):
|
||||
val = self.get_val(x, y)
|
||||
if val != 0:
|
||||
x0 = x * 16
|
||||
y0 = y * 16
|
||||
if (val < 16):
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
draw.text(self.screen, str(val), x0 + 4, y0 + 4, 1)
|
||||
elif val == 16:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
draw.text(self.screen, "1", x0 + 1, y0 + 4, 1)
|
||||
draw.text(self.screen, "6", x0 + 7, y0 + 4, 1)
|
||||
elif val == 32:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
draw.text(self.screen, "3", x0 + 1, y0 + 4, 1)
|
||||
draw.text(self.screen, "2", x0 + 7, y0 + 4, 1)
|
||||
elif val == 64:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
draw.text(self.screen, "6", x0 + 1, y0 + 4, 1)
|
||||
draw.text(self.screen, "4", x0 + 7, y0 + 4, 1)
|
||||
elif val == 128:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
self.draw_high_number(font_128, x0 + 1, y0 + 4)
|
||||
elif val == 256:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
self.draw_high_number(font_256, x0 + 1, y0 + 4)
|
||||
elif val == 512:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
self.draw_high_number(font_512, x0 + 1, y0 + 4)
|
||||
elif val == 1024:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
self.draw_high_number(font_1024, x0 + 1, y0 + 4)
|
||||
elif val == 2048:
|
||||
draw.rectangle(self.screen, x0, y0, x0 + 15, y0 + 15, 1)
|
||||
self.draw_high_number(font_2048, x0 + 1, y0 + 4)
|
||||
def read_stick_x(self):
|
||||
return self.x_adc.value()
|
||||
def read_stick_y(self):
|
||||
return self.y_adc.value()
|
||||
def wait_for_move(self):
|
||||
x_val = self.read_stick_x()
|
||||
y_val = self.read_stick_y()
|
||||
if x_val > self.adc_threshold + 15:
|
||||
return DIR_RIGHT
|
||||
elif x_val < self.adc_threshold - 15:
|
||||
return DIR_LEFT
|
||||
if y_val > self.adc_threshold + 15:
|
||||
return DIR_UP
|
||||
elif y_val < self.adc_threshold - 15:
|
||||
return DIR_DOWN
|
||||
return DIR_CENTER
|
||||
def get_free_tiles(self):
|
||||
list = []
|
||||
for x in range(0, 4):
|
||||
for y in range(0, 4):
|
||||
if self.get_val(x, y) == 0:
|
||||
list.append((x, y))
|
||||
return list
|
||||
def draw_all_tiles(self):
|
||||
for x in range(0, 4):
|
||||
for y in range(0, 4):
|
||||
self.draw_tile(x, y)
|
||||
def rand(self, mod=0):
|
||||
self._rand = ((214013*self._rand+2531011)>>16)&0x7FFF
|
||||
if mod:
|
||||
return self._rand % mod
|
||||
else:
|
||||
return self._rand
|
||||
def add_random_tile(self):
|
||||
free_tiles = self.get_free_tiles()
|
||||
if free_tiles:
|
||||
x,y = free_tiles[self.rand(len(free_tiles))]
|
||||
new_val = 2 << self.rand(2)
|
||||
self.set_val(x, y, new_val)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def draw_score(self):
|
||||
draw.text(self.screen, "Score:", 70, 10, 1)
|
||||
draw.text(self.screen, str(self.score), 70, 20, 1)
|
||||
def clear_grid(self):
|
||||
# Because the the double array does not initialize correctly
|
||||
# in micropython, we do an explicit clear
|
||||
for i in range(0, 4):
|
||||
for j in range(0, 4):
|
||||
self.grid[i][j] = 0
|
||||
def start(self):
|
||||
self.screen.fill(0)
|
||||
draw.text(self.screen, "Touch the stick", 10, 20, 1)
|
||||
draw.text(self.screen, " to start the", 10, 30, 1)
|
||||
draw.text(self.screen, " game! =)", 10, 40, 1)
|
||||
self.screen.show()
|
||||
in_center = False
|
||||
x_move = True
|
||||
y_move = True
|
||||
wait_for_center = False
|
||||
self.clear_grid()
|
||||
while self.not_game_over:
|
||||
move_dir = self.wait_for_move()
|
||||
if move_dir != DIR_CENTER and wait_for_center == False:
|
||||
self.move(move_dir)
|
||||
self.screen.fill(0)
|
||||
res = self.add_random_tile()
|
||||
if not res:
|
||||
self.not_game_over = False
|
||||
else:
|
||||
self.draw_all_tiles()
|
||||
self.draw_score()
|
||||
self.screen.show()
|
||||
wait_for_center = True
|
||||
if move_dir == DIR_CENTER:
|
||||
wait_for_center = False
|
||||
self.screen.fill(0)
|
||||
draw.text(self.screen, "Game Over!", 10, 20, 1)
|
||||
draw.text(self.screen, "Score:", 10, 30, 1)
|
||||
draw.text(self.screen, str(self.score), 10, 40, 1)
|
||||
self.screen.show()
|
Loading…
Reference in New Issue