From 77710f445d64bee1325dca63bd9aa778cae6bf2a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 18 Mar 2025 17:03:43 -0500 Subject: [PATCH 1/3] memory game files inital commit --- .../memory_game/btn_exit.bmp | Bin 0 -> 922 bytes .../memory_game/btn_play_again.bmp | Bin 0 -> 922 bytes Metro/Metro_RP2350_Memory/memory_game/code.py | 478 ++++++++++++++++++ .../memory_game/memory_game_sprites.bmp | Bin 0 -> 20698 bytes .../memory_game/memory_title.bmp | Bin 0 -> 77958 bytes .../memory_game/mouse_cursor.bmp | Bin 0 -> 198 bytes Metro/Metro_RP2350_Memory/mouse_demo/code.py | 108 ++++ .../mouse_demo/mouse_cursor.bmp | Bin 0 -> 198 bytes .../tictactoe_demo/code.py | 216 ++++++++ .../tictactoe_demo/mouse_cursor.bmp | Bin 0 -> 198 bytes .../tictactoe_demo/tictactoe_spritesheet.bmp | Bin 0 -> 1686 bytes 11 files changed, 802 insertions(+) create mode 100644 Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp create mode 100644 Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp create mode 100644 Metro/Metro_RP2350_Memory/memory_game/code.py create mode 100644 Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp create mode 100644 Metro/Metro_RP2350_Memory/memory_game/memory_title.bmp create mode 100644 Metro/Metro_RP2350_Memory/memory_game/mouse_cursor.bmp create mode 100644 Metro/Metro_RP2350_Memory/mouse_demo/code.py create mode 100644 Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp create mode 100644 Metro/Metro_RP2350_Memory/tictactoe_demo/code.py create mode 100644 Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp create mode 100644 Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp diff --git a/Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp b/Metro/Metro_RP2350_Memory/memory_game/btn_exit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2c3347e6be40fa803ba6427c27eb3295ca393d90 GIT binary patch literal 922 zcmd6lJr2S!4250b0Ci75;~gRA23?p~xCav}=V0h%!^_{&I70^{tk_AuSk{a5miv07 z6f5c*c}1R)1D#M2c$Z7gNHPsXd8L-+_IRbkj&j)ahB%O($Pa}O&ul~oGtIcD(H-0?#@qd!`J&L{4Lwmwqo*`(d6BJU ZclBTOUiaT~+dtg%RnLc}o#ES_&%Y&tX>b4l literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp b/Metro/Metro_RP2350_Memory/memory_game/btn_play_again.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ce4b8fed924cdf651723b8a6434706b05050cc95 GIT binary patch literal 922 zcmb7?O%lQ&427vb`_dEGuy-7|K{u}4xbhsj^(4J)eF@MaKhBr|O2587LMGE~-Ybb2 z>l^cedBW_}0V@LE&Dl>To-RuHA(H8Of63;LWtV9eHhjSSc~r}Sz0#FvV69cB2P$IJ zeOJLmV;|+l+2prT>-8<=^qX5U@Zmui9A0n0$y$cr+&Liy_sYTt9?(X&g&s-`cvB#%<(dgff8m{9Z=eTB0HU%Alx`m6_RJ}8~T lvEksAi#{ZeN8~7DOflSR*hJfI)UCd1^ 1 else 0 + + # remove the chosen card from the pool, and add it + # to the card locations list at the current location + card_locations.append(pool.pop(random_choice)) + +# center the card grid layout horizontally +card_grid.x = display.width // 2 - card_grid.width // 2 + +# move the card grid layout towards the bottom of the screen +card_grid.y = display.height - card_grid.height + +# add the card grid to the main group +main_group.append(card_grid) + +# create a group to hold the game over elements +game_over_group = Group() + +# create a TextBox to hold the game over message +game_over_label = TextBox( + terminalio.FONT, + text="", + color=0xFFFFFF, + background_color=0x222222, + width=display.width // 2, + height=80, + align=TextBox.ALIGN_CENTER, +) +# move it to the center top of the display +game_over_label.anchor_point = (0, 0) +game_over_label.anchored_position = ( + display.width // 2 - game_over_label.width // 2, + 40, +) + +# make it hidden, we'll show it when the game is over. +game_over_group.hidden = True + +# add the game over lable to the game over group +game_over_group.append(game_over_label) + +# load the play again, and exit button bitmaps +play_again_btn_bmp = OnDiskBitmap("btn_play_again.bmp") +exit_btn_bmp = OnDiskBitmap("btn_exit.bmp") + +# create TileGrid for the play again button +play_again_btn = TileGrid( + bitmap=play_again_btn_bmp, pixel_shader=play_again_btn_bmp.pixel_shader +) + +# transparent pixels in the corners for the rounded corner effect +play_again_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the left +play_again_btn.x = display.width // 2 - play_again_btn_bmp.width // 2 - 30 + +# inside the bounds of the game over label, so it looks like a dialog visually +play_again_btn.y = 80 + +# create TileGrid for the exit button +exit_btn = TileGrid(bitmap=exit_btn_bmp, pixel_shader=exit_btn_bmp.pixel_shader) + +# transparent pixels in the corners for the rounded corner effect +exit_btn_bmp.pixel_shader.make_transparent(0) + +# centered within the display, offset to the right +exit_btn.x = display.width // 2 - exit_btn_bmp.width // 2 + 30 + +# inside the bounds of the game over label, so it looks like a dialog visually +exit_btn.y = 80 + +# add the play again and exit buttons to the game over group +game_over_group.append(play_again_btn) +game_over_group.append(exit_btn) + +# add the game over group to the main group +main_group.append(game_over_group) + +# create score label for each player +for i in range(2): + # create a new label to hold score + score_lbl = Label(terminalio.FONT, text="", color=colors[i], scale=1) + if i == 0: + # if it's player 1 put it in the top left + score_lbl.anchor_point = (0, 0) + score_lbl.anchored_position = (4, 1) + else: + # if it's player 2 put it tin the top right + score_lbl.anchor_point = (1.0, 0) + score_lbl.anchored_position = (display.width - 4, 1) + + # add the label to list of score labels + score_lbls.append(score_lbl) + + # add the label to the main group + main_group.append(score_lbl) + +# initialize the text in the score labels to show 0 +update_score_text() + +# create a label to indicate which player's turn it is +current_player_lbl = Label( + terminalio.FONT, text="Current Player", color=colors[current_turn_index], scale=1 +) + +# place it centered horizontally at the top of the screen +current_player_lbl.anchor_point = (0.5, 0) +current_player_lbl.anchored_position = (display.width // 2, 1) + +# add the score label to the main group +main_group.append(current_player_lbl) + +# load the title screen bitmap +title_screen_bmp = OnDiskBitmap("memory_title.bmp") + +# create a TileGrid for the title screen +title_screen_tg = TileGrid( + bitmap=title_screen_bmp, pixel_shader=title_screen_bmp.pixel_shader +) + +# add it to the main group +main_group.append(title_screen_tg) + +# load the mouse bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# place it in the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# add the mouse to the main group +main_group.append(mouse_tg) + +# variable for the mouse USB device instance +mouse = None + +# wait a second for USB devices to be ready +time.sleep(1) + +# scan for connected USB devices +for device in usb.core.find(find_all=True): + # print information about the found devices + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + + # assume this device is the mouse + mouse = device + + # detach from kernel driver if active + if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + + # set the mouse configuration so it can be used + mouse.set_configuration() + + +# Buffer to hold data read from the mouse +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# timestamp in the future to wait until before +# awarding points for a pair, or flipping cards +# back over and changing turns +WAIT_UNTIL = 0 + +# bool indicating whether we are waiting to reset flipped +# cards and change turns or award points and remove +# cards. Will be True if we are waiting to take action, +# False otherwise. +waiting_to_reset = False + +# main loop +while True: + # timestamp of the current time + now = ticks_ms() + + # attempt mouse read + try: + # read data from the mouse, small timeout so we move on + # quickly if there is no data + data_len = mouse.read(0x81, buf, timeout=10) + + # if we got data, then update the mouse cursor on the display + # using min and max to keep it within the bounds of the display + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1] // 2)) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2] // 2)) + + # timeout error is raised if no data was read within the alotted timeout + except usb.core.USBTimeoutError: + # no problem, just go on + pass + + # if the current state is title screen + if CUR_STATE == STATE_TITLE: + # if the left mouse button was clicked + if buf[0] & (1 << 0) != 0: + # change the current state to playing + CUR_STATE = STATE_PLAYING + # hide the title screen + title_screen_tg.hidden = True + # change the mouse cursor color to match the current player + mouse_bmp.pixel_shader[2] = colors[current_turn_index] + + # if the current state is playing + elif CUR_STATE == STATE_PLAYING: + + # if we are waiting to reset, and it's time to take action + if waiting_to_reset and now >= WAIT_UNTIL: + # this means that there are already 2 cards flipped face up. + # we need to either award points, or flip them back over and + # change to the next players turn. + + # change variable to indicate we're no longer waiting to take action + waiting_to_reset = False + + # if both cards were the same i.e. they found a match + if ( + card_tgs[cards_flipped_this_turn[0]][0] + == card_tgs[cards_flipped_this_turn[1]][0] + ): + + # set the cards tile index to show a blank spot instead of a card + card_tgs[cards_flipped_this_turn[0]][0] = 8 + card_tgs[cards_flipped_this_turn[1]][0] = 8 + + # award a point to the player + player_scores[current_turn_index] += 1 + + # refresh the score texts to show the new score + update_score_text() + + # if the total of both players scores is equal to half the amount + # of cards then we know the game is over because each pair is worth 1 + # point + if ( + player_scores[0] + player_scores[1] + >= (grid_size[0] * grid_size[1]) // 2 + ): + + # if the player's scores are equal + if player_scores[0] == player_scores[1]: + # set the game over message to tie game + game_over_label.text = "Game Over\nTie Game" + + else: # player scores are not equal + + # if player 2 score is larger than player 1 + if player_scores[0] < player_scores[1]: + # set the game over message to indicate player 2 victory + game_over_label.text = "Game Over\nPlayer 2 Wins" + game_over_label.color = colors[1] + + else: # player 1 score is larger than player 2 + # set the game over message to indicate player 1 victory + game_over_label.text = "Game Over\nPlayer 1 Wins" + game_over_label.color = colors[0] + + # set the game over group to visible + game_over_group.hidden = False + + # change the state to gameover + CUR_STATE = STATE_GAMEOVER + + else: # the two cards were different i.e. they did not find a match + # set both cards tile index to the card back sprite to flip it back over + card_tgs[cards_flipped_this_turn[0]][0] = 10 + card_tgs[cards_flipped_this_turn[1]][0] = 10 + + # go to the next players turn + current_turn_index = (current_turn_index + 1) % 2 + + # update the color of the current player indicator + current_player_lbl.color = colors[current_turn_index] + + # update the color of the mouse cursor + mouse_bmp.pixel_shader[2] = colors[current_turn_index] + + # empty out the cards flipped this turn list + cards_flipped_this_turn = [] + + # ignore any clicks while we're waiting to take reset cards + if now >= WAIT_UNTIL: + # left btn pressed + if buf[0] & (1 << 0) != 0: + + # loop over all cards + for card_index, card in enumerate(card_tgs): + # coordinates of the mouse taking into account + # the offset from the card_grid position + coords = (mouse_tg.x - card_grid.x, mouse_tg.y - card_grid.y, 0) + + # if this is a face down card, and the mouse coordinates + # are within its bounding box + if card[0] == 10 and card.contains(coords): + # flip the card face up by setting its tile index + # to the appropriate value from the card_locations list + card[0] = card_locations[card_tgs.index(card)] + + # add this card index to the cards flipped this turn list + cards_flipped_this_turn.append(card_index) + + # if 2 cards have been flipped this turn + if len(cards_flipped_this_turn) == 2: + # set the wait until time to a little bit in the future + WAIT_UNTIL = ticks_ms() + 1500 + # set the waiting to reset flag to True + waiting_to_reset = True + + # if the current state is gameover + elif CUR_STATE == STATE_GAMEOVER: + # left btn pressed + if buf[0] & (1 << 0) != 0: + # get the coordinates of the mouse cursor point + coords = (mouse_tg.x, mouse_tg.y, 0) + + # if the mouse point is within the play again + # button bounding box + if play_again_btn.contains(coords): + # set next code file to this one + supervisor.set_next_code_file(__file__) + # reload + supervisor.reload() + + # if the mouse pint is within the exit + # button bounding box + if exit_btn.contains(coords): + # break to exit out of this script + break diff --git a/Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp b/Metro/Metro_RP2350_Memory/memory_game/memory_game_sprites.bmp new file mode 100644 index 0000000000000000000000000000000000000000..939717fcdf33a6e6982bfb272c799a141dfdc918 GIT binary patch literal 20698 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 literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/code.py b/Metro/Metro_RP2350_Memory/mouse_demo/code.py new file mode 100644 index 000000000..9ea0c5b36 --- /dev/null +++ b/Metro/Metro_RP2350_Memory/mouse_demo/code.py @@ -0,0 +1,108 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic Microsoft optical mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host, +and no other devices connected. +""" +import array +from displayio import Group, OnDiskBitmap, TileGrid +from adafruit_display_text.bitmap_label import Label +import supervisor +import terminalio +import usb.core + +# use the built-in HSTX display for Metro RP2350 +display = supervisor.runtime.display + +# group to hold visual elements +main_group = Group() + +# make the group visible on the display +display.root_group = main_group + +# load the mouse cursor bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# text label to show the x, y coordinates on the screen +output_lbl = Label( + terminalio.FONT, text=f"{mouse_tg.x},{mouse_tg.y}", color=0xFFFFFF, scale=1 +) + +# move it to the upper left corner +output_lbl.anchor_point = (0, 0) +output_lbl.anchored_position = (1, 1) + +# add it to the main group +main_group.append(output_lbl) + +# add the mouse tile grid to the main group +main_group.append(mouse_tg) + +# button names +# This is ordered by bit position. +BUTTONS = ["left", "right", "middle"] + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + # assume the device is the mouse + mouse = device + +# detach the kernel driver if needed +if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + +# set configuration on the mouse so we can use it +mouse.set_configuration() + +# buffer to hold mouse data +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# main loop +while True: + try: + # attempt to read data from the mouse + # 10ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=10) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # string with updated coordinates for the text label + out_str = f"{mouse_tg.x},{mouse_tg.y}" + + # loop over the button names + for i, button in enumerate(BUTTONS): + # check if each button is pressed using bitwise AND shifted + # to the appropriate index for this button + if buf[0] & (1 << i) != 0: + # append the button name to the string to show if + # it is being clicked. + out_str += f" {button}" + + # update the text label with the new coordinates + # and buttons being pressed + output_lbl.text = out_str diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Memory/mouse_demo/mouse_cursor.bmp new file mode 100644 index 0000000000000000000000000000000000000000..94ec328896cfb7dc84ac82d6a5b8b58e8a8a5f12 GIT binary patch literal 198 zcmZ?rJ;ne5(|}YB5VHX>4-hjlumDL01_K~g)`MVXARB}k82-Z$nCIjkR19X2Kro@H r{SPt|2>$;E(h3X=OhOQ>q@=*0C@2KPKpH3p#z1*RAXZ`kD`fxx@`?`& literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py new file mode 100644 index 000000000..7315c0582 --- /dev/null +++ b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py @@ -0,0 +1,216 @@ +# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT +""" +This example is made for a basic Microsoft optical mouse with +two buttons and a wheel that can be pressed. + +It assumes there is a single mouse connected to USB Host, +and no other devices connected. + +It illustrates multi-player turn based logic with a very +basic implementation of tic-tac-toe. +""" +import array +import random +from displayio import Group, OnDiskBitmap, TileGrid +from adafruit_display_text.bitmap_label import Label +from adafruit_displayio_layout.layouts.grid_layout import GridLayout +import supervisor +import terminalio +import usb.core +# use the built-in HSTX display for Metro RP2350 +display = supervisor.runtime.display + +# group to hold visual elements +main_group = Group() + +# make the group visible on the display +display.root_group = main_group + +# load the mouse cursor bitmap +mouse_bmp = OnDiskBitmap("mouse_cursor.bmp") + +# make the background pink pixels transparent +mouse_bmp.pixel_shader.make_transparent(0) + +# create a TileGrid for the mouse, using its bitmap and pixel_shader +mouse_tg = TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader) + +# move it to the center of the display +mouse_tg.x = display.width // 2 +mouse_tg.y = display.height // 2 + +# text label to show the x, y coordinates on the screen +output_lbl = Label(terminalio.FONT, text="", color=0xFFFFFF, scale=1) + +# move it to the right side of the screen +output_lbl.anchor_point = (0, 0) +output_lbl.anchored_position = (180, 40) + +# add it to the main group +main_group.append(output_lbl) + +# scan for connected USB device and loop over any found +for device in usb.core.find(find_all=True): + # print device info + print(f"{device.idVendor:04x}:{device.idProduct:04x}") + print(device.manufacturer, device.product) + print(device.serial_number) + # assume the device is the mouse + mouse = device + +# detach the kernel driver if needed +if mouse.is_kernel_driver_active(0): + mouse.detach_kernel_driver(0) + +# set configuration on the mouse so we can use it +mouse.set_configuration() + +# buffer to hold mouse data +# Boot mice have 4 byte reports +buf = array.array("b", [0] * 4) + +# set up a 3x3 grid for the tic-tac-toe board +board_grid = GridLayout( + x=40, + y=40, + width=128, + height=128, + grid_size=(3, 3) +) + +# load the tic-tac-toe spritesheet +tictactoe_spritesheet = OnDiskBitmap("tictactoe_spritesheet.bmp") + +# X is index 1 in the spritesheet, O is index 2 in the spritesheet +player_icon_indexes = [1, 2] + +# current player variable. +# When this equlas 0 its X's turn, +# when it equals 1 it is O's turn. +current_player_index = random.randint(0, 1) # randomize the initial player + +# loop over rows +for y in range(3): + # loop over columns + for x in range(3): + # create a TileGrid for this cell + new_tg = TileGrid(bitmap=tictactoe_spritesheet, default_tile=0, + tile_height=32, tile_width=32, + height=1, width=1, + pixel_shader=tictactoe_spritesheet.pixel_shader) + + # add the new TileGrid to the board grid at the current position + board_grid.add_content(new_tg, grid_position=(x, y), cell_size=(1, 1)) + +# add the board grid to the main group +main_group.append(board_grid) + +# add the mouse tile grid to the main group +main_group.append(mouse_tg) + + +def check_for_winner(): + """ + check if a player has won + + :return: the player icon index of the winning player, + None if no winner and game continues, -1 if game ended in a tie. + """ + found_empty = False + + # check rows + for row_idx in range(3): + # if the 3 cells in this row match + if (board_grid[0 + (row_idx * 3)][0] != 0 and + board_grid[0 + (row_idx * 3)][0] == + board_grid[1 + (row_idx * 3)][0] == + board_grid[2 + (row_idx * 3)][0]): + return board_grid[0 + (row_idx * 3)][0] + + # if any of the cells in this row are empty + if 0 in (board_grid[0 + (row_idx * 3)][0], + board_grid[1 + (row_idx * 3)][0], + board_grid[2 + (row_idx * 3)][0]): + found_empty = True + + # check columns + for col_idx in range(3): + # if the 3 cells in this column match + if (board_grid[0 + col_idx][0] != 0 and + board_grid[0 + col_idx][0] == + board_grid[3 + col_idx][0] == + board_grid[6 + col_idx][0]): + return board_grid[0 + col_idx][0] + + # if any of the cells in this column are empty + if 0 in (board_grid[0 + col_idx][0], + board_grid[3 + col_idx][0], + board_grid[6 + col_idx][0]): + found_empty = True + + # check diagonals + if board_grid[0][0] != 0 and \ + board_grid[0][0] == board_grid[4][0] == board_grid[8][0]: + return board_grid[0][0] + + if board_grid[2][0] != 0 and \ + board_grid[2][0] == board_grid[4][0] == board_grid[6][0]: + return board_grid[2][0] + + if found_empty: + # return None if there is no winner and the game continues + return None + else: + # return -1 if it's a tie game with no winner + return -1 + + +# main loop +while True: + try: + # attempt to read data from the mouse + # 10ms timeout, so we don't block long if there + # is no data + count = mouse.read(0x81, buf, timeout=10) + except usb.core.USBTimeoutError: + # skip the rest of the loop if there is no data + continue + + # update the mouse tilegrid x and y coordinates + # based on the delta values read from the mouse + mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1])) + mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2])) + + # if left button clicked + if buf[0] & (1 << 0) != 0: + # get the mouse pointer coordinates accounting for the offset of + # the board grid location + coords = (mouse_tg.x - board_grid.x, mouse_tg.y - board_grid.y, 0) + + # loop over all cells in the board + for cell_tg in board_grid: + + # if the current cell is blank, and contains the clicked coordinates + if cell_tg[0] == 0 and cell_tg.contains(coords): + # set the current cell tile index to the current player's icon + cell_tg[0] = player_icon_indexes[current_player_index] + + # change to the next player + current_player_index = (current_player_index + 1) % 2 + + # print out which player's turn it is + print(f"It is now {'X' if current_player_index == 0 else 'O'}'s turn") + + # check for a winner + result = check_for_winner() + + # if Xs or Os have won + if result == 1: + output_lbl.text = "X is the winner!" + elif result == 2: + output_lbl.text = "O is the winner!" + + # if it was a tie game + elif result == -1: + output_lbl.text = "Tie game, no winner." diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp b/Metro/Metro_RP2350_Memory/tictactoe_demo/mouse_cursor.bmp new file mode 100644 index 0000000000000000000000000000000000000000..94ec328896cfb7dc84ac82d6a5b8b58e8a8a5f12 GIT binary patch literal 198 zcmZ?rJ;ne5(|}YB5VHX>4-hjlumDL01_K~g)`MVXARB}k82-Z$nCIjkR19X2Kro@H r{SPt|2>$;E(h3X=OhOQ>q@=*0C@2KPKpH3p#z1*RAXZ`kD`fxx@`?`& literal 0 HcmV?d00001 diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp b/Metro/Metro_RP2350_Memory/tictactoe_demo/tictactoe_spritesheet.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a210c9ab2e64532a17af07e9f56727313c5f0695 GIT binary patch literal 1686 zcmb_cF;c@Y5IhrxieVyN0H)6)(om(rAK(wPe1SHf;c>8gx|QT05B7j2lFqu_y_Kx^ zcsk#hw=>3f^jGu;^uew%q9Olu$bE-LcC#=2{OS1o^5(&Y;pzhWd1p3FliA0urN6d) zBVj|Rjc5zP*sd~r%iMdy$MI3??F>vQfY7-a-mgG>6i_I5mq1VyU<7KoS#lJpl*DxT zlwxYVdn{NIkw9iNUorwG9_?fZg5D7Yu#pc`WzI`DQu4H+bQ5ZcvqL4n0`EH|o@AIP zrrVe~wJ3nIUx$wZPKTysc%-FPT}0#sT%LYv>c8;ZY`x3B>Tlg|mS26ITi+Mu2Pe^a za|xQT?n(FFSs5RPj-zePwlD&y0u=>#=XD9U_WvRu^2H6%M@+>=1Vuin01ZW3u#<0& m7houKcem76O@vMrLF==*e6IYOdMX@s+#tR6dpj%k^Whuv4sT5W literal 0 HcmV?d00001 From 4f9be495459830325ee94e3048f95948364ef452 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 24 Mar 2025 12:55:26 -0500 Subject: [PATCH 2/3] use built-in display if it exists and is initialized. --- Metro/Metro_RP2350_Memory/memory_game/code.py | 28 +++++- Metro/Metro_RP2350_Memory/mouse_demo/code.py | 29 +++++- .../tictactoe_demo/code.py | 98 +++++++++++++------ 3 files changed, 120 insertions(+), 35 deletions(-) diff --git a/Metro/Metro_RP2350_Memory/memory_game/code.py b/Metro/Metro_RP2350_Memory/memory_game/code.py index d680501bb..5205c4b1b 100644 --- a/Metro/Metro_RP2350_Memory/memory_game/code.py +++ b/Metro/Metro_RP2350_Memory/memory_game/code.py @@ -58,8 +58,32 @@ def update_score_text(): # initial state is title screen CUR_STATE = STATE_TITLE -# use the built-in display -display = supervisor.runtime.display +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) # main group will hold all of our visual elements main_group = Group() diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/code.py b/Metro/Metro_RP2350_Memory/mouse_demo/code.py index 9ea0c5b36..59e56f383 100644 --- a/Metro/Metro_RP2350_Memory/mouse_demo/code.py +++ b/Metro/Metro_RP2350_Memory/mouse_demo/code.py @@ -14,8 +14,33 @@ import terminalio import usb.core -# use the built-in HSTX display for Metro RP2350 -display = supervisor.runtime.display + +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) # group to hold visual elements main_group = Group() diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py index 7315c0582..1dab1dda6 100644 --- a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py +++ b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py @@ -18,8 +18,33 @@ import supervisor import terminalio import usb.core -# use the built-in HSTX display for Metro RP2350 -display = supervisor.runtime.display + +if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: + # use the built-in HSTX display for Metro RP2350 + display = supervisor.runtime.display +else: + from displayio import release_displays + import picodvi + import board + import framebufferio + + # initialize display + release_displays() + + fb = picodvi.Framebuffer( + 320, + 240, + clk_dp=board.CKP, + clk_dn=board.CKN, + red_dp=board.D0P, + red_dn=board.D0N, + green_dp=board.D1P, + green_dn=board.D1N, + blue_dp=board.D2P, + blue_dn=board.D2N, + color_depth=16, + ) + display = framebufferio.FramebufferDisplay(fb) # group to hold visual elements main_group = Group() @@ -71,13 +96,7 @@ buf = array.array("b", [0] * 4) # set up a 3x3 grid for the tic-tac-toe board -board_grid = GridLayout( - x=40, - y=40, - width=128, - height=128, - grid_size=(3, 3) -) +board_grid = GridLayout(x=40, y=40, width=128, height=128, grid_size=(3, 3)) # load the tic-tac-toe spritesheet tictactoe_spritesheet = OnDiskBitmap("tictactoe_spritesheet.bmp") @@ -95,10 +114,15 @@ # loop over columns for x in range(3): # create a TileGrid for this cell - new_tg = TileGrid(bitmap=tictactoe_spritesheet, default_tile=0, - tile_height=32, tile_width=32, - height=1, width=1, - pixel_shader=tictactoe_spritesheet.pixel_shader) + new_tg = TileGrid( + bitmap=tictactoe_spritesheet, + default_tile=0, + tile_height=32, + tile_width=32, + height=1, + width=1, + pixel_shader=tictactoe_spritesheet.pixel_shader, + ) # add the new TileGrid to the board grid at the current position board_grid.add_content(new_tg, grid_position=(x, y), cell_size=(1, 1)) @@ -122,40 +146,52 @@ def check_for_winner(): # check rows for row_idx in range(3): # if the 3 cells in this row match - if (board_grid[0 + (row_idx * 3)][0] != 0 and - board_grid[0 + (row_idx * 3)][0] == - board_grid[1 + (row_idx * 3)][0] == - board_grid[2 + (row_idx * 3)][0]): + if ( + board_grid[0 + (row_idx * 3)][0] != 0 + and board_grid[0 + (row_idx * 3)][0] + == board_grid[1 + (row_idx * 3)][0] + == board_grid[2 + (row_idx * 3)][0] + ): return board_grid[0 + (row_idx * 3)][0] # if any of the cells in this row are empty - if 0 in (board_grid[0 + (row_idx * 3)][0], - board_grid[1 + (row_idx * 3)][0], - board_grid[2 + (row_idx * 3)][0]): + if 0 in ( + board_grid[0 + (row_idx * 3)][0], + board_grid[1 + (row_idx * 3)][0], + board_grid[2 + (row_idx * 3)][0], + ): found_empty = True # check columns for col_idx in range(3): # if the 3 cells in this column match - if (board_grid[0 + col_idx][0] != 0 and - board_grid[0 + col_idx][0] == - board_grid[3 + col_idx][0] == - board_grid[6 + col_idx][0]): + if ( + board_grid[0 + col_idx][0] != 0 + and board_grid[0 + col_idx][0] + == board_grid[3 + col_idx][0] + == board_grid[6 + col_idx][0] + ): return board_grid[0 + col_idx][0] # if any of the cells in this column are empty - if 0 in (board_grid[0 + col_idx][0], - board_grid[3 + col_idx][0], - board_grid[6 + col_idx][0]): + if 0 in ( + board_grid[0 + col_idx][0], + board_grid[3 + col_idx][0], + board_grid[6 + col_idx][0], + ): found_empty = True # check diagonals - if board_grid[0][0] != 0 and \ - board_grid[0][0] == board_grid[4][0] == board_grid[8][0]: + if ( + board_grid[0][0] != 0 + and board_grid[0][0] == board_grid[4][0] == board_grid[8][0] + ): return board_grid[0][0] - if board_grid[2][0] != 0 and \ - board_grid[2][0] == board_grid[4][0] == board_grid[6][0]: + if ( + board_grid[2][0] != 0 + and board_grid[2][0] == board_grid[4][0] == board_grid[6][0] + ): return board_grid[2][0] if found_empty: From b38e2c29e3625bd81469777fc9ee23c1fe0d7aa1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 24 Mar 2025 13:07:14 -0500 Subject: [PATCH 3/3] pylint ignore imports outside top-level to avoid imports in environments that wont need them due to built-in display. --- Metro/Metro_RP2350_Memory/memory_game/code.py | 2 ++ Metro/Metro_RP2350_Memory/mouse_demo/code.py | 3 ++- Metro/Metro_RP2350_Memory/tictactoe_demo/code.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Metro/Metro_RP2350_Memory/memory_game/code.py b/Metro/Metro_RP2350_Memory/memory_game/code.py index 5205c4b1b..9db9f919b 100644 --- a/Metro/Metro_RP2350_Memory/memory_game/code.py +++ b/Metro/Metro_RP2350_Memory/memory_game/code.py @@ -58,10 +58,12 @@ def update_score_text(): # initial state is title screen CUR_STATE = STATE_TITLE +# pylint: disable=ungrouped-imports if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: # use the built-in HSTX display for Metro RP2350 display = supervisor.runtime.display else: + # pylint: disable=ungrouped-imports from displayio import release_displays import picodvi import board diff --git a/Metro/Metro_RP2350_Memory/mouse_demo/code.py b/Metro/Metro_RP2350_Memory/mouse_demo/code.py index 59e56f383..4518e8efa 100644 --- a/Metro/Metro_RP2350_Memory/mouse_demo/code.py +++ b/Metro/Metro_RP2350_Memory/mouse_demo/code.py @@ -14,11 +14,12 @@ import terminalio import usb.core - +# pylint: disable=ungrouped-imports if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: # use the built-in HSTX display for Metro RP2350 display = supervisor.runtime.display else: + # pylint: disable=ungrouped-imports from displayio import release_displays import picodvi import board diff --git a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py index 1dab1dda6..886b896c9 100644 --- a/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py +++ b/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py @@ -19,6 +19,7 @@ import terminalio import usb.core +# pylint: disable=ungrouped-imports if hasattr(supervisor.runtime, "display") and supervisor.runtime.display is not None: # use the built-in HSTX display for Metro RP2350 display = supervisor.runtime.display