# Create a Memory Game on Fruit Jam Metro RP2350

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/135/984/medium800/gaming_memory_guide_hero.png?1742929966)

The Metro RP2350 makes a perfect little game console. The on-board HSTX combined with a DVI breakout can output to a standard television or computer monitor for the display. The USB host connection makes it easy to take input from a mouse to control the game.&nbsp;

The Adafruit Fruit Jam simplifies setup even further by having the DVI connector and USB Host connectors directly on the board without the need to solder or connect any ribbon cables or additional breakouts.

This game is an implementation of the [classic game Memory](https://en.wikipedia.org/wiki/Concentration_(card_game)) also known as Concentration. A USB mouse is used by the players to alternate turns clicking on cards to flip them over, revealing the front. Players are rewarded with a point and an extra turn for finding two matching cards.

Play continues until all matches have been found. The player with the most points wins.

![](https://cdn-learn.adafruit.com/assets/assets/000/135/973/medium640thumb/gaming_memory_blinkacards.jpg?1742925339)

## Parts
### Adafruit Fruit Jam - Mini RP2350 Computer

[Adafruit Fruit Jam - Mini RP2350 Computer](https://www.adafruit.com/product/6200)
We were catching up on a recent [hackaday hackchat with eben upton](https://hackaday.io/event/202122-raspberry-pi-hack-chat-with-eben-upton)&nbsp;and learned some fun facts: such as the DVI hack for the RP2040 was inspired by <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/6200)
[Related Guides to the Product](https://learn.adafruit.com/products/6200/guides)
![Angled shot of assembled mini computer PCB with plate.](https://cdn-shop.adafruit.com/640x480/6200-10.jpg)

### Adafruit Metro RP2350

[Adafruit Metro RP2350](https://www.adafruit.com/product/6003)
Choo! Choo! This is the RP2350 Metro Line, making all station stops at "Dual Cortex M33 mountain", "528K RAM round-about" and "16 Megabytes of Flash town". This train is piled high with hardware that complements the Raspberry Pi RP2350 chip to make it an excellent...

In Stock
[Buy Now](https://www.adafruit.com/product/6003)
[Related Guides to the Product](https://learn.adafruit.com/products/6003/guides)
![Angled shot of black, credit card-sized microcontroller with stacking headers.](https://cdn-shop.adafruit.com/640x480/6003-06.jpg)

Or

### Adafruit Metro RP2350 with PSRAM

[Adafruit Metro RP2350 with PSRAM](https://www.adafruit.com/product/6267)
Choo! Choo! This is the RP2350 Metro Line, making all station stops at "Dual Cortex M33 mountain", "528K RAM round-about" and "16 Megabytes of Flash town" and a bonus stop at "8 Megabytes of PSRAM village". This train is piled high with hardware that...

In Stock
[Buy Now](https://www.adafruit.com/product/6267)
[Related Guides to the Product](https://learn.adafruit.com/products/6267/guides)
![Angled shot of black, credit card-sized microcontroller.](https://cdn-shop.adafruit.com/640x480/6267-00.jpg)

### Adafruit RP2350 22-pin FPC HSTX to DVI Adapter for HDMI Displays

[Adafruit RP2350 22-pin FPC HSTX to DVI Adapter for HDMI Displays](https://www.adafruit.com/product/6055)
You may have noticed that our [RP2350 Feather](https://www.adafruit.com/product/6000) has an FPC output connector on the end&nbsp;for accessing the HSTX (High Speed Transmission)&nbsp;peripheral. This new capability, not available on the RP2040, is specifically designed to allow the...

In Stock
[Buy Now](https://www.adafruit.com/product/6055)
[Related Guides to the Product](https://learn.adafruit.com/products/6055/guides)
![black, square-shaped breakout board with DVI and 22-pin FPC connectors connected to a black, rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/6055-01.jpg)

### USB Type A Jack Breakout Cable with Premium Female Jumpers

[USB Type A Jack Breakout Cable with Premium Female Jumpers](https://www.adafruit.com/product/4449)
If you'd like to connect a USB-host-capable chip to your USB peripheral, this cable will make the task very simple.&nbsp; **There is no converter chip in this cable!** &nbsp;It's basically a plain USB cable that's cut in half and with jumper sockets on the power and data...

In Stock
[Buy Now](https://www.adafruit.com/product/4449)
[Related Guides to the Product](https://learn.adafruit.com/products/4449/guides)
![USB Type A Socket Breakout Cable with Premium Female Jumpers](https://cdn-shop.adafruit.com/640x480/4449-02.jpg)

### 22-pin 0.5mm pitch FPC Flex Cable for DSI CSI or HSTX - 20cm

[22-pin 0.5mm pitch FPC Flex Cable for DSI CSI or HSTX - 20cm](https://www.adafruit.com/product/6036)
Connect this to that when a 22-pin FPC connector is needed. This 20 cm long cable is made of a flexible PCB. It's A-B style, meaning that pin one on one side will match with pin one on the other. How handy!

[We're stocking this to...](https://www.adafruit.com/category/360)

In Stock
[Buy Now](https://www.adafruit.com/product/6036)
[Related Guides to the Product](https://learn.adafruit.com/products/6036/guides)
![Angled shot of 20cm long, 22-pin FPC cable.](https://cdn-shop.adafruit.com/640x480/6036-00.jpg)

### Break-away 0.1" 36-pin strip male header - Black - 10 pack

[Break-away 0.1" 36-pin strip male header - Black - 10 pack](https://www.adafruit.com/product/392)
Breakaway header is like the duct tape of electronics. It's great for connecting things together, soldering to perf-boards, fits into any breakout or breadboard, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of ten!<br...></br...>

In Stock
[Buy Now](https://www.adafruit.com/product/392)
[Related Guides to the Product](https://learn.adafruit.com/products/392/guides)
![10 pieces of Break-away 0.1 inch 36-pin strip male header](https://cdn-shop.adafruit.com/640x480/392-01.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
![Official Raspberry Pi HDMI Cable - 1 meter](https://cdn-shop.adafruit.com/640x480/608-03.jpg)

- or -

### HDMI Flat Cable - 1 foot / 30cm long

[HDMI Flat Cable - 1 foot / 30cm long](https://www.adafruit.com/product/2197)
Connect two HDMI devices together and save space with this basic flat HDMI 1.4 cable. It has nice molded grips for easy installation, and is 1 foot long (~30 cm).

This cable is absolutely&nbsp; **perfect** &nbsp;for an LCD Raspberry Pi project. The cable is so thin and...

In Stock
[Buy Now](https://www.adafruit.com/product/2197)
[Related Guides to the Product](https://learn.adafruit.com/products/2197/guides)
![HDMI Flat Cable - 1foot / 30cm long](https://cdn-shop.adafruit.com/640x480/2197-00.jpg)

### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)
![Angled Shot of the USB Wired Mouse - Two Buttons plus Wheel](https://cdn-shop.adafruit.com/640x480/2025-05.jpg)

- or -

# Create a Memory Game on Fruit Jam Metro RP2350

## Preparing the Metro RP2350

The USB Host port is the only part of this project that required soldering.

The USB Host pin connections are highlighted on the Metro image to the left. You will need a small piece of standard 0.1 inch male header, with 4 pins, to fit the holes.

You can cut header with diagonal cutters or break them with pliers or even your fingers. Just be sure to wear eye protection as they can fly when cut.&nbsp;

![Metro RP2350 with USB Host pins 5V, D-, D+, and GND highlighted. They sit between the main chip and the HSTX connector.](https://cdn-learn.adafruit.com/assets/assets/000/135/704/medium640/gaming_raspberry_pi_adafruit_products_pinouts_usbhost_highlight.png?1741378462)

![A row of 4 standard male header pins ready to be soldered to Metro](https://cdn-learn.adafruit.com/assets/assets/000/135/705/medium640/gaming_usb_host_pins.jpg?1741378510)

Put the short end of the header into the holes in the Metro marked USB Host and secure them with putty, blutack, tape, etc. Turn the Metro over and you should see the header barely poking out of the bottom of the board. If the pins stick through a great deal you may have the header pins upside down, double check the short end is sticking into the board.

Solder the 4 pin "nubbins" to the board.

![Metro RP2350 upside down next to HAKO soldering station](https://cdn-learn.adafruit.com/assets/assets/000/135/706/medium640/gaming_usb_host_soldering.jpeg?1741378603)

![Male header pins poking through the USB host pin holes on the Metro RP2350](https://cdn-learn.adafruit.com/assets/assets/000/135/707/medium640/gaming_usb_host_unsoldered.jpg?1741378690)

![Metro RP2350 upside down with USB Host pins soldered.](https://cdn-learn.adafruit.com/assets/assets/000/135/708/medium640/gaming_usb_host_soldered.jpg?1741378758)

Turn the board over and remove the material securing the pins. Now there is a new 4-pin header.&nbsp;

Get the USB Host cable and wire as follows:

**GRD** to **Black**

**D+** to **Green**

**D-** to **White**

**5V** to **Red**

![Metro RP2350 right side up with the USB Host male header pins soldered.](https://cdn-learn.adafruit.com/assets/assets/000/135/709/medium640/gaming_usb_host_pins_complete.jpg?1741378869)

![](https://cdn-learn.adafruit.com/assets/assets/000/135/710/medium800/gaming_usb_host_wire_attached.jpg?1741378939)

## HSTX Connection to DVI
![](https://cdn-learn.adafruit.com/assets/assets/000/135/711/medium800/gaming_hstx_breakout_ribbon_connected.png?1741378983)

Get the HSTX cable. Any length Adafruit sells is fine. CAREFULLY lift the dark grey bar up on the Metro, insert the cable silver side down, blue side up, then put the bar CAREFULLY down, ensuring it locks. If it feels like it doesn't want to go, do not force it.

Do the same with the other end and the DVI breakout. Note that the DVI breakout will be inverted/upside down when compared to the Metro - this is normal for these boards and the Adafruit cables.

# Create a Memory Game on Fruit Jam Metro RP2350

## Install CircuitPython Metro

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_metro_rp2350/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/101/655/medium640/install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg?1618943202)

![](https://cdn-learn.adafruit.com/assets/assets/000/135/292/medium800/adafruit_products_boot_reset_btn_highlights.png?1739467365)

To enter the bootloader, hold down the **BOOT/**** BOOTSEL button**(highlighted in red above), and while continuing to hold it (don't let go!), press and release the**reset button**(highlighted in red or blue above).&nbsp;**Continue to hold the BOOT/BOOTSEL button until the RP2350 drive appears!**

If the drive does not appear, release all the buttons, and then repeat the process above.

You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **RP2350**.

&nbsp;

Drag the **adafruit-circuitpython-_boardname_-_language_-_version_.uf2** file to **RP2350.**

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png](https://cdn-learn.adafruit.com/assets/assets/000/132/253/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png?1726067809)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png](https://cdn-learn.adafruit.com/assets/assets/000/132/254/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png?1726067866)

The **RP2350** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png](https://cdn-learn.adafruit.com/assets/assets/000/132/255/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png?1726067932)

## Safe Mode

You want to edit your **code.py** or modify the files on your **CIRCUITPY** drive, but find that you can't. Perhaps your board has gotten into a state where **CIRCUITPY** is read-only. You may have turned off the **CIRCUITPY** drive altogether. Whatever the reason, safe mode can help.

Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode _bypasses any code in_ **boot.py** (where you can set **CIRCUITPY** read-only or turn it off completely). Second, _it does not run the code in_ **code.py**. And finally, _it does not automatically soft-reload when data is written to the_ **CIRCUITPY** _drive_.

Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the **CIRCUITPY** drive.

### Entering Safe Mode
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)

### In Safe Mode

If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.

If you connect to the serial console, you'll find the following message.

```terminal
Auto-reload is off.
Running in safe mode! Not running saved code.

CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.
```

You can now edit the contents of the **CIRCUITPY** drive. Remember, _your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode._

## Flash Resetting UF2

If your board ever gets into a really _weird_ state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RP2350. which will do a 'deep clean' on your Flash Memory. **You will lose all the files on the board** , but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.

[Download flash erasing "nuke" UF2 for RP2350](https://cdn-learn.adafruit.com/assets/assets/000/132/526/original/rp2350_flash_nuke.uf2)
# Create a Memory Game on Fruit Jam Metro RP2350

## Install CircuitPython Fruit Jam

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

Warning: Please use the latest release of 10.x or higher for the Fruit Jam. Also use the latest libraries for the best functionality.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_fruit_jam/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/101/655/medium640/install_circuitpython_on_rp2040_RP2040_UF2_downloaded.jpg?1618943202)

![reset and boot highlighted](https://cdn-learn.adafruit.com/assets/assets/000/138/708/medium800/adafruit_products_Resetboot.jpg?1754331128 )

To enter the bootloader, hold down the **BOOT/**** BOOTSEL button**(highlighted in red above), and while continuing to hold it (don't let go!), press and release the**reset button**(highlighted in red or blue above).&nbsp;**Continue to hold the BOOT/BOOTSEL button until the RP2350 drive appears!**

If the drive does not appear, release all the buttons, and then repeat the process above.

You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **RP2350**.

&nbsp;

Drag the **adafruit-circuitpython-_boardname_-_language_-_version_.uf2** file to **RP2350.**

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png](https://cdn-learn.adafruit.com/assets/assets/000/132/253/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111518.png?1726067809)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png](https://cdn-learn.adafruit.com/assets/assets/000/132/254/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111742.png?1726067866)

The **RP2350** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it, you're done! :)

![install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png](https://cdn-learn.adafruit.com/assets/assets/000/132/255/medium640/install_circuitpython_on_rp2350_Screenshot_2024-09-11_111843.png?1726067932)

## Safe Mode

You want to edit your **code.py** or modify the files on your **CIRCUITPY** drive, but find that you can't. Perhaps your board has gotten into a state where **CIRCUITPY** is read-only. You may have turned off the **CIRCUITPY** drive altogether. Whatever the reason, safe mode can help.

Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode _bypasses any code in_ **boot.py** (where you can set **CIRCUITPY** read-only or turn it off completely). Second, _it does not run the code in_ **code.py**. And finally, _it does not automatically soft-reload when data is written to the_ **CIRCUITPY** _drive_.

Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the **CIRCUITPY** drive.

### Entering Safe Mode
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)

### In Safe Mode

If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.

If you connect to the serial console, you'll find the following message.

```terminal
Auto-reload is off.
Running in safe mode! Not running saved code.

CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.
```

You can now edit the contents of the **CIRCUITPY** drive. Remember, _your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode._

## Flash Resetting UF2

If your board ever gets into a really _weird_ state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RP2350. which will do a 'deep clean' on your Flash Memory. **You will lose all the files on the board** , but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.

[Download flash erasing "nuke" UF2 for RP2350](https://cdn-learn.adafruit.com/assets/assets/000/132/526/original/rp2350_flash_nuke.uf2)
# Create a Memory Game on Fruit Jam Metro RP2350

## Mouse Input

The Memory game will make use of a USB mouse for input from the players. To start, look at the following basic example of initializing the mouse, reading data from it, and plotting a cursor on the screen.

The basic mouse example is embedded below. Click the 'Download Project Bundle' button to download a zip containing this example and the associated image file and required libraries. Unzip and copy them to your **CIRCUITPY** drive to run the example.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Metro/Metro_RP2350_Memory/mouse_demo/code.py

![](https://cdn-learn.adafruit.com/assets/assets/000/135/968/medium800thumb/gaming_mouse_demo.jpg?1742922033)

The code contains comments describing the purpose of each section. An overview of the code functionality can be found below. Reading both will give you a good understanding of one of the core principals that will get used by the Memory game.

## Display Setup

First the code checks whether there is a built-in display. For the Metro RP2350 starting with CircuitPython 9.2.5 the HSTX connector counts as the built-in display, so it will get used by this script by default. If a display is not found, then it will attempt to initialize one manually using the default HSTX pins.

## Visual Elements Setup

Next the code creates a `main_group` to put all visual elements into and sets it as the `root_group` on the display so it is shown on the screen. Then it creates an `OnDiskBitmap` to load the **mouse\_cursor.bmp** file.

This files contains a pink color in the palette index 0 which is treated as transparency by calling&nbsp;`mouse_bmp.pixel_shader.make_transparent(0)`. A TileGrid is created and stored in the variable `mouse_tg`. Later on when reading mouse data, the program will use it to move `mouse_tg` around the screen. The mouse cursor is put into the center of the screen to start with.

A `Label` named `output_lbl` is created and added to the `main_group` after being placed in the top left corner of the screen. This will be used to show the current mouse coordinates and any buttons that are pressed.

The `mouse_tg` is added to `main_group` last so that it will be visually in front of everything else.&nbsp;

## USB Mouse Device Setup

The list `BUTTONS` is created with values `"left"`, `"right"`, and `"middle"`. The order and indexes of these values align with the mouse protocol which will use bits in the same positions in order to denote whether each button is being pressed or not.

Next the code scans for connected USB devices and sets the first one found to the `mouse` variable. Once found, the connected mouse is detached from the kernel driver, if needed. Next `mouse.set_configuration()` is called in order to get the mouse ready to send data.

An&nbsp;`array` of bytes that can hold 4 elements is created to store the data that is read from the mouse device.&nbsp;

## Main Loop

Inside the main loop, `mouse.read(0x81, buf, timeout=10)` is called to read data from the mouse. `0x81` is the default endpoint address for basic HID mice,&nbsp;`buf` is the 4 byte buffer array that will get filled with the data that is read. `timeout` is how many milliseconds to wait before raising a `USBTimeoutError` if there is no data to read. This code uses a low value of `10` milliseconds to illustrate how the main loop can do other things if the timeout is kept low. Higher timeout values result in the `read()` call blocking other code execution for longer times.

If there is no data, the `USBTimeoutError` is raised and the code skips to the next iteration with `continue`.

If there is data, the code reads the delta x and y values from the buffer indexes `1` and `2`. These delta values represent how far the mouse has moved in each direction. It will have negative values for up/left, and positive values for right/down.&nbsp;

The delta values are used to move the `mouse_tg` to a new location. `min()` and `max()` are used to clamp the mouse cursor to the bounds of the display. The mouse itself is not aware of these bounds, the code enforces staying on the display after reading raw data from the mouse.

The `out_str` is updated with the current x and y coordinates of the `mouse_tg`.&nbsp;

Next the code checks for button presses by looping over the `BUTTONS` list and checking the bits in the respective positions within the byte at index `0` of the buffer. Any buttons that are pressed have their name added to the `out_str`.

Finally `out_str` is set as the text on the `output_lbl` in order to show the current values on the screen.

# Create a Memory Game on Fruit Jam Metro RP2350

## Game Mechanics: Multiplayer Turns

In the Memory game, multiple players take turns playing the game. Each player will need to use the mouse to select cards to flip over and when their turn is over, the mouse is passed to the other player.

The code will need to keep track of which turn it is to assign points to the appropriate player when matching cards are found.

Before getting into all of the complexity that comes with the rest of the Memory game, a look at something simpler: an implementation of Tic-Tac-Toe. This Tic-Tac-Toe game will use the same core mechanism to keep track of player turns as the Memory game. As an added bonus, it also uses the same `GridLayout` technique to position its visual elements on the screen as the Memory game.&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Metro/Metro_RP2350_Memory/tictactoe_demo/code.py

![](https://cdn-learn.adafruit.com/assets/assets/000/135/969/medium800thumb/gaming_tictactoe_demo.jpg?1742922268)

The code contains comments describing the purpose each section. A overview of the code functionality can be found below. Reading both will give you a good understanding of core principals that will get used by the Memory game.

The code makes use of things detailed on the [Mouse Input guide page](https://learn.adafruit.com/memory-game-on-metro-rp2350/mouse-input), see that page for more information about how the mouse data is read and the cursor drawn and moved around the display.

## Visual Elements Setup

In addition to the mouse cursor, this code also creates `board_grid`, a `GridLayout` object, which will hold the cells that make up the Tic-Tac-Toe board. The&nbsp;`GridLayout` takes a `height` and `width` in pixels and a `grid_size` when it is initialized and will automatically distribute the content items added into the cells of the grid using the values specified to determine the appropriate placement.

The **tictactoe\_spritesheet.bmp** is loaded into an `OnDiskBitmap`.&nbsp;

A set of nested for loops with `y` and `x` counter variables are used to create a `TileGrid` for each cell on the board and add it to the `board_grid`. Each `TileGrid` is set to `default_tile=0` which is the index of the blank cell within the spritesheet.

## Player Turn Setup & Logic

An integer variable, `current_player_index`, is created to store a number which will keep track of which player's turn it is. Tic-Tac-Toe and Memory are both 2 player games, but the same approach can be used for games with more than two players as well.

For Memory and Tic-Tac-Toe, the `current_player_index` will always be either `0` or `1`. When the time comes to change turns, the code will swap from the current value to the other.&nbsp;

Initially the value of this variable is set to a random number using `random.randint(0, 1)`.

Now that we have an integer variable that holds whose turn it is, any other player specific data or variables can be stored inside of a list and use the indexes of the list to match up with the&nbsp;`current_player_index` values. In the Tic-Tac-Toe code, it creates the list `player_icon_indexes` to hold the indexes within the spritesheet of the X and O tiles respectively. `current_player_index` of `0` matches up to the X sprite tile, and `current_player_index` of `1` matches up to the O sprite tile.

Whenever the current player clicks a tile to play their turn, the code sets the tile sprite by looking up the appropriate sprite index with `player_icon_indexes[current_player_index]`

Other lists can be created and used similarly to store and retrieve information specific to each player. The Memory game will make use of a few lists like this.

## `check_winner()` Function

This function will check all of the horizontal, vertical and diagonal lines within the game board to find if any player has 3 in a row and thus has won. If a player does have 3 in a row then `check_winner()` will return their `current_player_index` value, i.e. if X wins then `0` will be returned, and if O wins then `1` will be returned. If there is no winner and there are still empty cells then `None` is returned. If there is no winner and there are no empty cells remaining then `-1` is returned to indicate it is a tie game.

## Main Loop

The first part of the main loop reads data from the mouse and moves the `mouse_tg` just as was shown in the mouse demo on the previous page.&nbsp;

`if buf[0] & (1 << 0) != 0` is used to check if the left mouse button has been pressed. Nothing else happens until that button does get pressed.&nbsp;

When the left button is pressed, the code puts the current `mouse_tg` coordinates into a the tuple `coords` then it loops over all of the cell `TileGrid`s that are in the `board_grid` and checks if the mouse coordinates are contained within the bounding box of each by calling `cell_tg.contains(coords)`. If the click was not inside of any of the cell `TileGrid`s then nothing else happens.

If the click was inside of a cell, `TileGrid` the code ensures that the cell is currently empty by checking the sprite index. If it is empty then the current player's sprite is put into the cell `TileGrid`. Afterward the turn is changed by updating `current_player_index`.

Next `check_for_winner()` is called, if there is a winner the `output_lbl` is updated to say which player won. If it's a tie game, the `output_lbl` is updated to reflect that. If there is no winner and the game is continuing, the program goes to the next iteration of the main loop.&nbsp;

# Create a Memory Game on Fruit Jam Metro RP2350

## Code

## CircuitPython Usage

To use the game, you need to update&nbsp; **code.py** with the game program&nbsp;to the **CIRCUITPY** drive.

Thankfully, this can be done in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file.

Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named **CIRCUITPY**.

Extract the contents of the zip file, copy the **lib** directory files to **CIRCUITPY/lib**. Copy the **code.py** file to your **CIRCUITPY** drive. The program should self start.

## Drive Structure

After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum.

![CIRCUITPY](https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/folder-images/Metro_Metro_RP2350_Memory_memory_game.png?raw=true )

## Code

The **code.py** for the Memory game is shown below.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Metro/Metro_RP2350_Memory/memory_game/code.py

# Create a Memory Game on Fruit Jam Metro RP2350

## Code Explanation

The code for the Memory game is thoroughly commented with explanations of what each line or section are for. This page will provide a higher level summary of the major components.

## Hardware Principals

This game is designed around two primary hardware peripherals: the HSTX connector with a DVI breakout for the display, and a basic USB mouse for the player control input.

### HSTX Display

First the code will attempt to use the built-in display from `supervisor.runtime.display`. If that doesn't work, then it will initialize the display using the built-in core modules `picodvi`, and&nbsp;`framebufferio`. These modules support a few different resolutions and color depths. This project is made for the 320x240 resolution with 16 bit color depth. The pixels are automatically doubled before being pushed to the display, so it will come out as 640x480, depending on your monitor or TV, it may further upscale it to fit the screen.

If you haven't already, be sure to add `CIRCUITPY_DISPLAY_WIDTH=320` to your **settings.toml** file to ensure the correct configuration.

## USB Mouse

The USB mouse setup, data reading, and cursor movement are all documented on the [Mouse Input guide page](https://learn.adafruit.com/memory-game-on-metro-rp2350/mouse-input). See that page for more details.

## Helper Functions

The code contains two helper functions: `random_selection()`, and `update_score_text()`.&nbsp;

- `random_selection()` Accepts list and count arguments. It returns a list of items randomly selected from the given list with a length of `count`. This is used to select a number of cards at random out of the pool of all possible cards.&nbsp;
- `update_score_text()` Is a display helper function that will update the visual score text on the display of both players to reflect their current score.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/135/970/medium800/gaming_memory_title_img.png?1742922752)

## State Machine

The code is based upon a [state machine](https://learn.adafruit.com/circuitpython-101-state-machines). There are 3 states that it can be in:

- Title state - shows the title screen and waits for a click of the mouse anywhere on the screen. When click occurs the state is changed to playing.
- Playing state - The primary gameplay occurs during this state. Players take turns flipping cards. Once there are no more cards to flip, the state is changed to gameover.
- Gameover state - The gameover message is shown along with buttons that can be clicked to play again or quit.

## Player Specific Variables

There are a number of player specific variables stored in lists indexed with the `current_player_index` values as described on the [multi-player turns mechanic page](https://learn.adafruit.com/memory-game-on-metro-rp2350/game-mechanics-multiplayer-turns#player-turn-setup-and-logic-3195686).

- `score_lbls` list will contain a Label instance for each player which will get added to `main_group` to be shown on the display. Each player's `score_lbl` will show their score during the gameplay.
- `colors` list will contain a hex color code for each player. By default these are pink `0xff00ff` for player index `0`, and green `0x00ff00` for player index `1`. Feel free to change the colors to suit your own style. The mouse cursor and text indicator at the top of the screen will be set to these colors to indicate which player's turn it is.
- `player_scores` list will contain the numerical score of each player.

## Initializing Cards

First the code builds up `pool`, a list of indexes within the spritesheet, each index representing one of the possible cards. Initially the list is created with two copies of each possible card index. Two of each are desired so that there are guaranteed to be matches for every card used.

There are only 8 different cards, which makes 16 total cards once they are each paired up with a match. The grid is 6x4 which is 24 cards, so an additional 8 cards or 4 pairs are needed in order to fill out the rest of the grid. 4 card indexes are chosen at random using the&nbsp;`random_selection()` function, then those 4 plus a duplicate of each are added to the `pool` list to bring it up to a total of 24 card indexes.

The cards are arranged visually using a&nbsp;`GridLayout` which takes a `height` and `width` in pixels, as well as a `grid_size` in cells and automatically arranges the content added to it in a grid. A nested for loop of 4 rows by 6 columns is used to create a `TileGrid` for each card and add it to the grid at the appropriate cell. All `TileGrid`s are created with `default_tile=10` which is the face down card tile index within the spritesheet.

Within the nested loop the code also chooses and removes a random card index from the `pool` and adds it to the `card_locations` list. `card_locations` serves as the "key" to the location of the cards. It keeps track of which card is where on the board so that when a card is clicked we can change to the appropriate sprite to reveal which card it was.

## Flipping Cards

A list named `cards_flipped_this_turn` stores the `TileGrid` indexes of the cards that have been flipped over this turn. When the first card is clicked it's index within the grid is added to this list, when the second card is clicked its index is added as well, then the code compares the sprite indexes of the&nbsp;`TileGrid`s at the grid indexes stored within `cards_flipped_this_turn`. If they match, a point is awarded to the current player and the cards are removed. If they don't match, there is a small delay before they are flipped back over by changing their `TileGrid` sprite index back to `10`, the face down card sprite. The `WAIT_UNTIL` variable is used to store the timestamp of time in the future when the cards will get flipped back down. The delay gives the players time to see the cards and try to commit their location to memory.

![](https://cdn-learn.adafruit.com/assets/assets/000/135/972/medium800/gaming_memory_blinkacards_scaled.png?1742925156)

## Check If the Game Is Over

To determine whether the game is over, the code will see if the sum of both players score is equal to the total size of the grid divided by two. For the default board of 6x4, this means the code is looking for the sum of scores to be `12`. When it is, the code knows that the game is over because twelve pairs have been found which accounts for all 24 cards we used.

The code checks if one score is higher than the other and sets the `gameover` message accordingly, including a message for tie game if the scores are the same.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/135/992/medium800/gaming_memory_gameover.png?1742932991)

# Create a Memory Game on Fruit Jam Metro RP2350

## Usage

Ensure a USB mouse is plugged into the USB Host port wired up previously. Reset the board by cycling power or pressing the Reset button if you happen to plug in a mouse after power up.

Be sure you connect the DVI breakout to an HDMI monitor and the monitor is on. You might need a long cable if your monitor is not near the Metro RP2350 (like a television). The cables are standard and may be obtained from any trusted retail outlet. Also reset the Metro if you plug in HDMI after powering the Metro.

Once connections are all set, power the Metro RP2350 either via USB C (5 volts) or the barrel connection (5.5 to 17 volts DC, center positive).

## Gameplay
![](https://cdn-learn.adafruit.com/assets/assets/000/135/977/medium800thumb/gaming_memory_blinkacards.jpg?1742928377)

Players alternate using the mouse to take turns clicking on two cards to flip over. If the cards weren't a match, then they are flipped back face down and it becomes the next player's turn. If the two cards revealed are a match, then the player is awarded a point, the cards are removed from the board, and that player gets to take another turn, repeating until they fail to find a match.

The mouse color and an indicator label at the top of the screen are changed to indicate which player's turn it is currently.

Once the game has ended, there are buttons to play again or quit.

![](https://cdn-learn.adafruit.com/assets/assets/000/135/993/medium800/gaming_memory_gameover.png?1742933008)


## Featured Products

### Adafruit Metro RP2350

[Adafruit Metro RP2350](https://www.adafruit.com/product/6003)
Choo! Choo! This is the RP2350 Metro Line, making all station stops at "Dual Cortex M33 mountain", "528K RAM round-about" and "16 Megabytes of Flash town". This train is piled high with hardware that complements the Raspberry Pi RP2350 chip to make it an excellent...

In Stock
[Buy Now](https://www.adafruit.com/product/6003)
[Related Guides to the Product](https://learn.adafruit.com/products/6003/guides)
### Adafruit RP2350 22-pin FPC HSTX to DVI Adapter for HDMI Displays

[Adafruit RP2350 22-pin FPC HSTX to DVI Adapter for HDMI Displays](https://www.adafruit.com/product/6055)
You may have noticed that our [RP2350 Feather](https://www.adafruit.com/product/6000) has an FPC output connector on the end&nbsp;for accessing the HSTX (High Speed Transmission)&nbsp;peripheral. This new capability, not available on the RP2040, is specifically designed to allow the...

In Stock
[Buy Now](https://www.adafruit.com/product/6055)
[Related Guides to the Product](https://learn.adafruit.com/products/6055/guides)
### USB Type A Jack Breakout Cable with Premium Female Jumpers

[USB Type A Jack Breakout Cable with Premium Female Jumpers](https://www.adafruit.com/product/4449)
If you'd like to connect a USB-host-capable chip to your USB peripheral, this cable will make the task very simple.&nbsp; **There is no converter chip in this cable!** &nbsp;It's basically a plain USB cable that's cut in half and with jumper sockets on the power and data...

In Stock
[Buy Now](https://www.adafruit.com/product/4449)
[Related Guides to the Product](https://learn.adafruit.com/products/4449/guides)
### Break-away 0.1" 36-pin strip male header - Black - 10 pack

[Break-away 0.1" 36-pin strip male header - Black - 10 pack](https://www.adafruit.com/product/392)
Breakaway header is like the duct tape of electronics. It's great for connecting things together, soldering to perf-boards, fits into any breakout or breadboard, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of ten!<br...></br...>

In Stock
[Buy Now](https://www.adafruit.com/product/392)
[Related Guides to the Product](https://learn.adafruit.com/products/392/guides)
### 22-pin 0.5mm pitch FPC Flex Cable for DSI CSI or HSTX - 20cm

[22-pin 0.5mm pitch FPC Flex Cable for DSI CSI or HSTX - 20cm](https://www.adafruit.com/product/6036)
Connect this to that when a 22-pin FPC connector is needed. This 20 cm long cable is made of a flexible PCB. It's A-B style, meaning that pin one on one side will match with pin one on the other. How handy!

[We're stocking this to...](https://www.adafruit.com/category/360)

In Stock
[Buy Now](https://www.adafruit.com/product/6036)
[Related Guides to the Product](https://learn.adafruit.com/products/6036/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
### HDMI Cable - 1 meter

[HDMI Cable - 1 meter](https://www.adafruit.com/product/608)
Connect two HDMI devices together with this basic HDMI cable. It has nice molded grips for easy installation, and is 1 meter long (about 3 feet). This is a HDMI 1.3 cable.

We're now stocking a very fancy Official Raspberry Pi cable with overmolding and a Pi logo. Please note...

In Stock
[Buy Now](https://www.adafruit.com/product/608)
[Related Guides to the Product](https://learn.adafruit.com/products/608/guides)
### USB Wired Mouse - Two Buttons plus Wheel

[USB Wired Mouse - Two Buttons plus Wheel](https://www.adafruit.com/product/2025)
This is a mouse. &nbsp;A nice, simple mouse. &nbsp;No bells or whistles. &nbsp;Just a mouse.  
  
But that doesn't mean it's not the best simple mouse!&nbsp; We compared a few and liked this one quite a bit. &nbsp;It's optical for good resolution and precision, has two...

In Stock
[Buy Now](https://www.adafruit.com/product/2025)
[Related Guides to the Product](https://learn.adafruit.com/products/2025/guides)

## Related Guides

- [Adafruit RP2350 22-pin FPC HSTX to DVI Adapter](https://learn.adafruit.com/adafruit-rp2350-22-pin-fpc-hstx-to-dvi-adapter.md)
- [Adafruit Metro RP2350](https://learn.adafruit.com/adafruit-metro-rp2350.md)
- [Using a Mouse with USB Host](https://learn.adafruit.com/using-a-mouse-with-usb-host.md)
- [Adafruit Fruit Jam](https://learn.adafruit.com/adafruit-fruit-jam.md)
- [How to Choose a Microcontroller](https://learn.adafruit.com/how-to-choose-a-microcontroller.md)
- [Snake Game on Metro RP2350](https://learn.adafruit.com/snake-game-on-metro-rp2350.md)
- [Flappy Nyan Cat Game on Fruit Jam and Metro RP2350](https://learn.adafruit.com/flappy-nyan-cat-game-on-metro-rp2350.md)
- [Larsio Paint Music](https://learn.adafruit.com/larsio-paint-music.md)
- [Using a Keyboard with USB Host](https://learn.adafruit.com/using-a-keyboard-with-usb-host.md)
- [Return to The Matrix with the Metro RP2350 or Fruit Jam](https://learn.adafruit.com/return-to-the-matrix-with-the-metro-rp2350.md)
- [Minesweeper on the Fruit Jam and Metro RP2350](https://learn.adafruit.com/minesweeper-on-metro-rp2350.md)
- [Using DVI Video in CircuitPython](https://learn.adafruit.com/using-dvi-video-in-circuitpython.md)
- [Driving TM1814 addressable LEDs](https://learn.adafruit.com/driving-tm1814-addressable-leds.md)
- [Plotting Offline Data - JSONL to CSV files, filters and graphs](https://learn.adafruit.com/plotting-offline-data-jsonl-to-csv-files-filters-and-graphs.md)
- [Tile-Matching Game on the Fruit Jam and Metro RP2350](https://learn.adafruit.com/tile-matching-game-on-the-adafruit-metro-rp2350.md)
- [Breakout Game on the Metro RP2350 and Fruit Jam](https://learn.adafruit.com/breakout-game-on-metro-rp2350-and-fruit-jam.md)
- [NES Emulator for RP2040 & RP2350 DVI Boards](https://learn.adafruit.com/nes-emulator-for-rp2040-dvi-boards.md)
