Skip to content

Commit 06dded0

Browse files
authored
Merge pull request #2994 from FoamyGuy/memory_game
memory game files
2 parents 53234f9 + b38e2c2 commit 06dded0

File tree

11 files changed

+891
-0
lines changed

11 files changed

+891
-0
lines changed
922 Bytes
Binary file not shown.
Binary file not shown.

Metro/Metro_RP2350_Memory/memory_game/code.py

Lines changed: 504 additions & 0 deletions
Large diffs are not rendered by default.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
"""
4+
This example is made for a basic Microsoft optical mouse with
5+
two buttons and a wheel that can be pressed.
6+
7+
It assumes there is a single mouse connected to USB Host,
8+
and no other devices connected.
9+
"""
10+
import array
11+
from displayio import Group, OnDiskBitmap, TileGrid
12+
from adafruit_display_text.bitmap_label import Label
13+
import supervisor
14+
import terminalio
15+
import usb.core
16+
17+
# pylint: disable=ungrouped-imports
18+
if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None:
19+
# use the built-in HSTX display for Metro RP2350
20+
display = supervisor.runtime.display
21+
else:
22+
# pylint: disable=ungrouped-imports
23+
from displayio import release_displays
24+
import picodvi
25+
import board
26+
import framebufferio
27+
28+
# initialize display
29+
release_displays()
30+
31+
fb = picodvi.Framebuffer(
32+
320,
33+
240,
34+
clk_dp=board.CKP,
35+
clk_dn=board.CKN,
36+
red_dp=board.D0P,
37+
red_dn=board.D0N,
38+
green_dp=board.D1P,
39+
green_dn=board.D1N,
40+
blue_dp=board.D2P,
41+
blue_dn=board.D2N,
42+
color_depth=16,
43+
)
44+
display = framebufferio.FramebufferDisplay(fb)
45+
46+
# group to hold visual elements
47+
main_group = Group()
48+
49+
# make the group visible on the display
50+
display.root_group = main_group
51+
52+
# load the mouse cursor bitmap
53+
mouse_bmp = OnDiskBitmap("mouse_cursor.bmp")
54+
55+
# make the background pink pixels transparent
56+
mouse_bmp.pixel_shader.make_transparent(0)
57+
58+
# create a TileGrid for the mouse, using its bitmap and pixel_shader
59+
mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
60+
61+
# move it to the center of the display
62+
mouse_tg.x = display.width // 2
63+
mouse_tg.y = display.height // 2
64+
65+
# text label to show the x, y coordinates on the screen
66+
output_lbl = Label(
67+
terminalio.FONT, text=f"{mouse_tg.x},{mouse_tg.y}", color=0xFFFFFF, scale=1
68+
)
69+
70+
# move it to the upper left corner
71+
output_lbl.anchor_point = (0, 0)
72+
output_lbl.anchored_position = (1, 1)
73+
74+
# add it to the main group
75+
main_group.append(output_lbl)
76+
77+
# add the mouse tile grid to the main group
78+
main_group.append(mouse_tg)
79+
80+
# button names
81+
# This is ordered by bit position.
82+
BUTTONS = ["left", "right", "middle"]
83+
84+
# scan for connected USB device and loop over any found
85+
for device in usb.core.find(find_all=True):
86+
# print device info
87+
print(f"{device.idVendor:04x}:{device.idProduct:04x}")
88+
print(device.manufacturer, device.product)
89+
print(device.serial_number)
90+
# assume the device is the mouse
91+
mouse = device
92+
93+
# detach the kernel driver if needed
94+
if mouse.is_kernel_driver_active(0):
95+
mouse.detach_kernel_driver(0)
96+
97+
# set configuration on the mouse so we can use it
98+
mouse.set_configuration()
99+
100+
# buffer to hold mouse data
101+
# Boot mice have 4 byte reports
102+
buf = array.array("b", [0] * 4)
103+
104+
# main loop
105+
while True:
106+
try:
107+
# attempt to read data from the mouse
108+
# 10ms timeout, so we don't block long if there
109+
# is no data
110+
count = mouse.read(0x81, buf, timeout=10)
111+
except usb.core.USBTimeoutError:
112+
# skip the rest of the loop if there is no data
113+
continue
114+
115+
# update the mouse tilegrid x and y coordinates
116+
# based on the delta values read from the mouse
117+
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1]))
118+
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2]))
119+
120+
# string with updated coordinates for the text label
121+
out_str = f"{mouse_tg.x},{mouse_tg.y}"
122+
123+
# loop over the button names
124+
for i, button in enumerate(BUTTONS):
125+
# check if each button is pressed using bitwise AND shifted
126+
# to the appropriate index for this button
127+
if buf[0] & (1 << i) != 0:
128+
# append the button name to the string to show if
129+
# it is being clicked.
130+
out_str += f" {button}"
131+
132+
# update the text label with the new coordinates
133+
# and buttons being pressed
134+
output_lbl.text = out_str
Binary file not shown.
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
"""
4+
This example is made for a basic Microsoft optical mouse with
5+
two buttons and a wheel that can be pressed.
6+
7+
It assumes there is a single mouse connected to USB Host,
8+
and no other devices connected.
9+
10+
It illustrates multi-player turn based logic with a very
11+
basic implementation of tic-tac-toe.
12+
"""
13+
import array
14+
import random
15+
from displayio import Group, OnDiskBitmap, TileGrid
16+
from adafruit_display_text.bitmap_label import Label
17+
from adafruit_displayio_layout.layouts.grid_layout import GridLayout
18+
import supervisor
19+
import terminalio
20+
import usb.core
21+
22+
# pylint: disable=ungrouped-imports
23+
if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None:
24+
# use the built-in HSTX display for Metro RP2350
25+
display = supervisor.runtime.display
26+
else:
27+
from displayio import release_displays
28+
import picodvi
29+
import board
30+
import framebufferio
31+
32+
# initialize display
33+
release_displays()
34+
35+
fb = picodvi.Framebuffer(
36+
320,
37+
240,
38+
clk_dp=board.CKP,
39+
clk_dn=board.CKN,
40+
red_dp=board.D0P,
41+
red_dn=board.D0N,
42+
green_dp=board.D1P,
43+
green_dn=board.D1N,
44+
blue_dp=board.D2P,
45+
blue_dn=board.D2N,
46+
color_depth=16,
47+
)
48+
display = framebufferio.FramebufferDisplay(fb)
49+
50+
# group to hold visual elements
51+
main_group = Group()
52+
53+
# make the group visible on the display
54+
display.root_group = main_group
55+
56+
# load the mouse cursor bitmap
57+
mouse_bmp = OnDiskBitmap("mouse_cursor.bmp")
58+
59+
# make the background pink pixels transparent
60+
mouse_bmp.pixel_shader.make_transparent(0)
61+
62+
# create a TileGrid for the mouse, using its bitmap and pixel_shader
63+
mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
64+
65+
# move it to the center of the display
66+
mouse_tg.x = display.width // 2
67+
mouse_tg.y = display.height // 2
68+
69+
# text label to show the x, y coordinates on the screen
70+
output_lbl = Label(terminalio.FONT, text="", color=0xFFFFFF, scale=1)
71+
72+
# move it to the right side of the screen
73+
output_lbl.anchor_point = (0, 0)
74+
output_lbl.anchored_position = (180, 40)
75+
76+
# add it to the main group
77+
main_group.append(output_lbl)
78+
79+
# scan for connected USB device and loop over any found
80+
for device in usb.core.find(find_all=True):
81+
# print device info
82+
print(f"{device.idVendor:04x}:{device.idProduct:04x}")
83+
print(device.manufacturer, device.product)
84+
print(device.serial_number)
85+
# assume the device is the mouse
86+
mouse = device
87+
88+
# detach the kernel driver if needed
89+
if mouse.is_kernel_driver_active(0):
90+
mouse.detach_kernel_driver(0)
91+
92+
# set configuration on the mouse so we can use it
93+
mouse.set_configuration()
94+
95+
# buffer to hold mouse data
96+
# Boot mice have 4 byte reports
97+
buf = array.array("b", [0] * 4)
98+
99+
# set up a 3x3 grid for the tic-tac-toe board
100+
board_grid = GridLayout(x=40, y=40, width=128, height=128, grid_size=(3, 3))
101+
102+
# load the tic-tac-toe spritesheet
103+
tictactoe_spritesheet = OnDiskBitmap("tictactoe_spritesheet.bmp")
104+
105+
# X is index 1 in the spritesheet, O is index 2 in the spritesheet
106+
player_icon_indexes = [1, 2]
107+
108+
# current player variable.
109+
# When this equlas 0 its X's turn,
110+
# when it equals 1 it is O's turn.
111+
current_player_index = random.randint(0, 1) # randomize the initial player
112+
113+
# loop over rows
114+
for y in range(3):
115+
# loop over columns
116+
for x in range(3):
117+
# create a TileGrid for this cell
118+
new_tg = TileGrid(
119+
bitmap=tictactoe_spritesheet,
120+
default_tile=0,
121+
tile_height=32,
122+
tile_width=32,
123+
height=1,
124+
width=1,
125+
pixel_shader=tictactoe_spritesheet.pixel_shader,
126+
)
127+
128+
# add the new TileGrid to the board grid at the current position
129+
board_grid.add_content(new_tg, grid_position=(x, y), cell_size=(1, 1))
130+
131+
# add the board grid to the main group
132+
main_group.append(board_grid)
133+
134+
# add the mouse tile grid to the main group
135+
main_group.append(mouse_tg)
136+
137+
138+
def check_for_winner():
139+
"""
140+
check if a player has won
141+
142+
:return: the player icon index of the winning player,
143+
None if no winner and game continues, -1 if game ended in a tie.
144+
"""
145+
found_empty = False
146+
147+
# check rows
148+
for row_idx in range(3):
149+
# if the 3 cells in this row match
150+
if (
151+
board_grid[0 + (row_idx * 3)][0] != 0
152+
and board_grid[0 + (row_idx * 3)][0]
153+
== board_grid[1 + (row_idx * 3)][0]
154+
== board_grid[2 + (row_idx * 3)][0]
155+
):
156+
return board_grid[0 + (row_idx * 3)][0]
157+
158+
# if any of the cells in this row are empty
159+
if 0 in (
160+
board_grid[0 + (row_idx * 3)][0],
161+
board_grid[1 + (row_idx * 3)][0],
162+
board_grid[2 + (row_idx * 3)][0],
163+
):
164+
found_empty = True
165+
166+
# check columns
167+
for col_idx in range(3):
168+
# if the 3 cells in this column match
169+
if (
170+
board_grid[0 + col_idx][0] != 0
171+
and board_grid[0 + col_idx][0]
172+
== board_grid[3 + col_idx][0]
173+
== board_grid[6 + col_idx][0]
174+
):
175+
return board_grid[0 + col_idx][0]
176+
177+
# if any of the cells in this column are empty
178+
if 0 in (
179+
board_grid[0 + col_idx][0],
180+
board_grid[3 + col_idx][0],
181+
board_grid[6 + col_idx][0],
182+
):
183+
found_empty = True
184+
185+
# check diagonals
186+
if (
187+
board_grid[0][0] != 0
188+
and board_grid[0][0] == board_grid[4][0] == board_grid[8][0]
189+
):
190+
return board_grid[0][0]
191+
192+
if (
193+
board_grid[2][0] != 0
194+
and board_grid[2][0] == board_grid[4][0] == board_grid[6][0]
195+
):
196+
return board_grid[2][0]
197+
198+
if found_empty:
199+
# return None if there is no winner and the game continues
200+
return None
201+
else:
202+
# return -1 if it's a tie game with no winner
203+
return -1
204+
205+
206+
# main loop
207+
while True:
208+
try:
209+
# attempt to read data from the mouse
210+
# 10ms timeout, so we don't block long if there
211+
# is no data
212+
count = mouse.read(0x81, buf, timeout=10)
213+
except usb.core.USBTimeoutError:
214+
# skip the rest of the loop if there is no data
215+
continue
216+
217+
# update the mouse tilegrid x and y coordinates
218+
# based on the delta values read from the mouse
219+
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1]))
220+
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2]))
221+
222+
# if left button clicked
223+
if buf[0] & (1 << 0) != 0:
224+
# get the mouse pointer coordinates accounting for the offset of
225+
# the board grid location
226+
coords = (mouse_tg.x - board_grid.x, mouse_tg.y - board_grid.y, 0)
227+
228+
# loop over all cells in the board
229+
for cell_tg in board_grid:
230+
231+
# if the current cell is blank, and contains the clicked coordinates
232+
if cell_tg[0] == 0 and cell_tg.contains(coords):
233+
# set the current cell tile index to the current player's icon
234+
cell_tg[0] = player_icon_indexes[current_player_index]
235+
236+
# change to the next player
237+
current_player_index = (current_player_index + 1) % 2
238+
239+
# print out which player's turn it is
240+
print(f"It is now {'X' if current_player_index == 0 else 'O'}'s turn")
241+
242+
# check for a winner
243+
result = check_for_winner()
244+
245+
# if Xs or Os have won
246+
if result == 1:
247+
output_lbl.text = "X is the winner!"
248+
elif result == 2:
249+
output_lbl.text = "O is the winner!"
250+
251+
# if it was a tie game
252+
elif result == -1:
253+
output_lbl.text = "Tie game, no winner."
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)