# NeoTrellis M4 Animated Dice Roller

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/066/106/medium800thumb/gaming_demo.jpg?1542413106)

In this project we'll take the NeoTrellisM4 and use it to make a dice roller.

We want to be able to select between 1 and 8 dice to roll, and the type of dice: 4, 6, 8, 10, 12, or 20 sided. To keep the interface simply, we can't mix types of dice.

The number of dice is selected using the top row of buttons: 1-8 starting from the left. As the count is selected, a bar fills in from the left.

The type of die is selected by buttons on the second row. Each type of die is assigned a unique color that is used to display the result of rolls as well as the associated selection button when a die is selected.

Button use and color is shown below.

![](https://cdn-learn.adafruit.com/assets/assets/000/066/107/medium800/gaming_dd.png?1542413132)

Once the number and type of dice are selected, shaking the Trellis will roll the dice and display the result.

![](https://cdn-learn.adafruit.com/assets/assets/000/066/081/medium800/gaming_circuitpython_blinka-small.png?1542398768)

We'll be using CircuitPython for this project. Are you new to using CircuitPython? No worries,&nbsp;[there is a full getting started guide here](https://learn.adafruit.com/welcome-to-circuitpython).

Adafruit suggests using the Mu editor to edit your code and have an interactive REPL in CircuitPython.&nbsp;[You can learn about Mu and its installation in this tutorial](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor).

There's a guide to get you up and running with [CircuitPython specifically for the NeoTrellisM4](https://learn.adafruit.com/adafruit-neotrellis-m4/circuitpython). You should read it before starting to get the most recent CircuitPython build for the NeoTrellisM4 installed and running along with the required libraries.

## Parts
### Adafruit NeoTrellis M4 with Enclosure and Buttons Kit Pack

[Adafruit NeoTrellis M4 with Enclosure and Buttons Kit Pack](https://www.adafruit.com/product/4020)
So you've got a cool/witty name for your band, a Soundcloud account,&nbsp;[a 3D-printed Daft Punk helmet](https://learn.adafruit.com/3d-printed-daft-punk-helmet-with-bluetooth)...&nbsp;so what could be missing from your road to stardom? The **NeoTrellis M4 Kit...**

Out of Stock
[Buy Now](https://www.adafruit.com/product/4020)
[Related Guides to the Product](https://learn.adafruit.com/products/4020/guides)
![Demo Video of Hands pressing buttons on lit up NeoTrellis M4.](https://cdn-shop.adafruit.com/product-videos/640x480/4020-00.jpg)

### USB cable - USB A to Micro-B

[USB cable - USB A to Micro-B](https://www.adafruit.com/product/592)
This here is your standard A to micro-B USB cable, for USB 1.1 or 2.0. Perfect for connecting a PC to your Metro, Feather, Raspberry Pi or other dev-board or microcontroller

Approximately 3 feet / 1 meter long

In Stock
[Buy Now](https://www.adafruit.com/product/592)
[Related Guides to the Product](https://learn.adafruit.com/products/592/guides)
![USB cable - USB A to Micro-B - 3 foot long](https://cdn-shop.adafruit.com/640x480/592-01.jpg)

# NeoTrellis M4 Animated Dice Roller

## Code Walkthrough

As is usual for a Python script, we start by importing what is needed, and initializing the hardware. Most of what we need is in the (Neo)TrellisM4 Express class. However, the accelerometer has to be set up separately.

```auto
import math
import time
import random
import board
import adafruit_trellism4
import adafruit_adxl34x
import busio

# Set up the trellis and accelerometer

trellis = adafruit_trellism4.TrellisM4Express()

i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
accelerometer = adafruit_adxl34x.ADXL345(i2c)

```

Since we want to display numbers on the Trellis's pixels, we need to define the bitmaps. The approach used is to use a string of three characters (the width of each glyph). Here we use spaces and asterisks to denote unlit/lit pixels. A 3x4 grid isn't much to work with, but this font does ok. See&nbsp;[http://pixeljoint.com/pixelart/24172.htm](http://pixeljoint.com/pixelart/24172.htm)&nbsp;by Adam Simpson.

```auto
number_patterns = [
    [" * ", "* *", "* *", "***"],         # 0
    [" * ", "** ", " * ", "***"],         # 1
    ["** ", "  *", " * ", "***"],         # 2
    ["** ", "  *", " **", "***"],         # 3
    ["* *", "* *", "***", "  *"],         # 4
    ["***", "*  ", " **", "***"],         # 5
    [" **", "*  ", "***", "***"],         # 6
    ["***", "  *", " * ", " * "],         # 7
    [" * ", "* *", "***", "***"],         # 8
    [" * " ,"* *", " **", "  *"]          # 9
]
```

Now that the look of the digits is decided, we need to display them. First we need a function to display a single digit. Since this will be used for both the ones and tens place, it will need to have a parameter telling it where to display its digit; that's `offset`.&nbsp; Since each type of die will have it's own color, that needs to be passed in as well. Finally there's a flag to specify whether a zero will be displayed or left blank. Why? If the number is less than 10 it would be nice to suppress the leading 0.

The `display_digit` function simply gets the pixel pattern for the value of the `number` parameter, and loops through the rows and columns setting each pixel based on the pattern.

```auto
def display_digit(number, offset, color, force_zero):
    """Display a digit.
    number     -- the number (0-9) to display
    offset     -- the left-most column of the displayed digit
    color      -- the RGB color to use to display the digit
    force_zero -- whether to leave a 0 blank (False) or display it
    """
    bits = number_patterns[number]
    for row in range(4):
        for col in range(3):
            if bits[row][col] == " " or (number == 0 and not force_zero):
                trellis.pixels[col + offset, row] = (0, 0, 0)
            else:
                trellis.pixels[col + offset, row] = color
```

Now that a single digit can be displayed, that function gets used in another that is responsible for displaying the entire number. This displays the ones digit, and then the tens digit (suppressing it if it's a leading zero). Note that if the number is 100 or more, the tens digit is always displayed.

What happens next is a bit different. Since a roll with several larger dice could result in a number greater than will fit in two digits, the hundreds place uses the otherwise unused pixels on the far left to indicate 100, 200, 300, or 400. This is just a matter of scanning through, lighting the appropriate one.

That's it other than a bit of range checking on the number being displayed.

```auto
def display_number(number, color):
    """Display a multi-digit number.
    If the number is &gt; 99, the hundreds digit (1-4) is indicated on the far left column:
        100 is the top pixel, 400 is the bottom.
    number      -- the number to display
    color       -- the RGB color to use to display the digit
    force_zeros -- whether to leave a 0 in the tens place blank (False) or display it
    """
    if number &gt;= 500 or number &lt; 0:
        return False
    display_digit(number % 10, 5, color, True)
    display_digit((number // 10) % 10, 1, color, number &gt;= 100)
    hundreds = number // 100
    for h in range(4):
        if h + 1 == hundreds:
            trellis.pixels[0, h] = (255, 255, 255)
        else:
            trellis.pixels[0, h] = (0, 0, 0)
    return True
```

While we could just slap a number onto the display without fanfare, it's far more interesting to have some animation suggesting rolling dice.

That's what the `animate_to` function does. Simply, it displays 10 random two digit numbers with a slight delay between them. After that's done, the number to be displayed is shown.

```auto
def animate_to(number, color):
    """Perform an animation (displaying random numbers) before displaying the requested number.
    number -- the number to eventually display
    color  -- the color to use (indicates the type of dice used)
    """
    for _ in range(10):
        trellis.pixels.fill((0, 0, 0))
        display_number(random.randint(10, 99), color, True)
        time.sleep(0.1)
    trellis.pixels.fill((0, 0, 0))
    display_number(number, color)
```

Now that we can display numbers we need numbers to display.

That's where the roll function comes in. It has parameters for the number of dice to roll, as well as the number of sides those dice have. It generates the specified number of random integers between 1 and the number of sides and returns the sum.

```auto
def roll(number, sides):
    """Generate a random dice roll.
    Returns the total of the roll.
    number -- the number of dice to roll
    sides  -- the number of side on dice to roll (4, 6, 8, 10, 12, 20)
    """
    total = 0
    for _ in range(number):
        total += random.randint(1, sides + 1)
    return total
```

As mentioned earlier, we want to roll the dice when the Trellis is shaken. To know when that happens we need to use the accelerometer.&nbsp; The approach to detecting a shake is inspired by [this article](http://www.profoundlogic.com/docs/display/PUI/Accelerometer+Test+for+Shaking). Put simply, look for sudden significant changes in all accelerometer axis. To do that we keep track of the previous reading, and compare the new one to it.

The `bound` variable is the threshold for axis change.

```auto
previous_reading = [None, None, None]
bound = 4.0

def shaken():
    """Detect when the Trellis is shaken.
    See http://www.profoundlogic.com/docs/display/PUI/Accelerometer+Test+for+Shaking
    TL;DR one or more axis experiences a significant (set by bound) change very quickly
    Returns whether a shake was detected.
    """
    global previous_reading
    result = False
    x, y, z = accelerometer.acceleration
    if previous_reading[0] is not None:
        result = (math.fabs(previous_reading[0] - x) &gt; bound and
                      math.fabs(previous_reading[1] - y) &gt; bound and
                      math.fabs(previous_reading[2] - z) &gt; bound)
    previous_reading = (x, y, z)
    return result
```

Finally, we have the main loop.

Each time through, we start by clearing the display and initializing the shake detector.

Next we have another loop that cycles until a shake is detected. In this loop we check for presses in the top two rows and process them into the number and type of die to roll. By looping until a shake is detected, we can keep adjusting count and die until we're ready to roll.

Once a shake is detected, we confirm that both count and die have, indeed, been selected. If so the dice are rolled and the result displayed in the appropriate color. It's displayed for 5 seconds, or until any key is pressed.

Then the outer loop restarts.

```auto
selected_count = -1
selected_die = -1

while True:
    trellis.pixels.fill((0, 0, 0))
    previous_reading = accelerometer.acceleration
    while not shaken():
        # update selected count/die if a respective selection has been made
        pressed = trellis.pressed_keys    # Get the pressed buttons
        count_selector = [key for key in pressed if key[1] == 0]   # first row presses
        die_selector = [key for key in pressed if key[1] == 1]     # second row presses
        if len(count_selector) &gt; 0:
            selected_count = count_selector[0][0] + 1
        if len(die_selector) &gt; 0 and die_selector[0][0] &lt; 6:   # only 6 types of dice
            selected_die = die_selector[0][0]

        # update the pixels to reflect the selections
        for i in range(8):
            if i &lt; selected_count:        # Display a bar for the count
                trellis.pixels[i, 0] = (128, 64, 16)
            else:
                trellis.pixels[i, 0] = (0, 0, 0)
            if i == selected_die:         # Just the selected dice, in the appropriate color
                trellis.pixels[i, 1] = die_colors[selected_die]
            else:
                trellis.pixels[i, 1] = (0, 0, 0)

    # Only do the roll if both count and die have been selected
    if (selected_count &gt; -1) and (selected_die &gt; -1):
        animate_to(roll(selected_count, sides_per_die[selected_die]), die_colors[selected_die])
        timeout = time.monotonic() + 5.0
        while len(trellis.pressed_keys) == 0 and time.monotonic() &lt; timeout:
            pass
```

The full code is below. Save it as **code.py** on your Trellis's **CIRCUITPY** drive.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/NeoTrellis/NeoTrellisM4_Dice/code.py


## Featured Products

### Adafruit NeoTrellis M4 with Enclosure and Buttons Kit Pack

[Adafruit NeoTrellis M4 with Enclosure and Buttons Kit Pack](https://www.adafruit.com/product/4020)
So you've got a cool/witty name for your band, a Soundcloud account,&nbsp;[a 3D-printed Daft Punk helmet](https://learn.adafruit.com/3d-printed-daft-punk-helmet-with-bluetooth)...&nbsp;so what could be missing from your road to stardom? The **NeoTrellis M4 Kit...**

Out of Stock
[Buy Now](https://www.adafruit.com/product/4020)
[Related Guides to the Product](https://learn.adafruit.com/products/4020/guides)
### Adafruit NeoTrellis M4 Mainboard - featuring SAMD51

[Adafruit NeoTrellis M4 Mainboard - featuring SAMD51](https://www.adafruit.com/product/3938)
We got a big ol' blender and tossed in an ItsyBitsy M4, two NeoTrellis boards and an electret mic amp - turned on the 'mix' button and out came the NeoTrellis M4 - a super fun dev board for anyone who likes to squish buttons, see pretty lights and maybe make a tune or...

In Stock
[Buy Now](https://www.adafruit.com/product/3938)
[Related Guides to the Product](https://learn.adafruit.com/products/3938/guides)
### NeoTrellis M4 Acrylic Enclosure Kit

[NeoTrellis M4 Acrylic Enclosure Kit](https://www.adafruit.com/product/3963)
So you've got your&nbsp;[Adafruit NeoTrellis M4](https://www.adafruit.com/product/3938), a cool/witty name for your band, a Soundcloud account,&nbsp;[a 3D-printed Daft Punk helmet](https://learn.adafruit.com/3d-printed-daft-punk-helmet-with-bluetooth)...&nbsp;so what...

Out of Stock
[Buy Now](https://www.adafruit.com/product/3963)
[Related Guides to the Product](https://learn.adafruit.com/products/3963/guides)
### Silicone Elastomer 4x4 Button Keypad - for 3mm LEDs

[Silicone Elastomer 4x4 Button Keypad - for 3mm LEDs](https://www.adafruit.com/product/1611)
So squishy! These silicone elastomer keypads are just waiting for your fingers to press them. Go ahead, squish all you like! (They're durable and easy to clean, just wipe with mild soap and water) These are just like the light up rubber buttons you find on stuff like appliances and tools,...

Out of Stock
[Buy Now](https://www.adafruit.com/product/1611)
[Related Guides to the Product](https://learn.adafruit.com/products/1611/guides)
### USB Patterned Fabric Cable - A/MicroB

[USB Patterned Fabric Cable - A/MicroB](https://www.adafruit.com/product/2008)
Oooh it's so soft! And that beautiful&nbsp;pattern! If you have to have visible cables&nbsp;then you might as well have the nicest fabric bound cable with a eye-catching snake-like pattern. &nbsp;That's why we now carry this standard A to micro-B USB cable&nbsp;for USB 1.1 or 2.0....

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/2008)
[Related Guides to the Product](https://learn.adafruit.com/products/2008/guides)
### Little Rubber Bumper Feet - Pack of 4

[Little Rubber Bumper Feet - Pack of 4](https://www.adafruit.com/product/550)
Keep your electronics from going barefoot, give them little rubber feet! These small sticky bumpers are our favorite accessory for any electronic kit or device. They are sticky, but not impossible to remove. They're small enough to fit onto any board, and have just enough height to give...

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

## Related Guides

- [Adafruit NeoTrellis M4 Express](https://learn.adafruit.com/adafruit-neotrellis-m4.md)
- [NeoTrellis M4 MIDI File Synthesizer](https://learn.adafruit.com/neotrellism4-midi-file-player-synthesizer.md)
- [NeoTrellis MIDI Feedback Controller](https://learn.adafruit.com/neotrellis-midi-feedback-controller.md)
- [Trellis M4 Beat Sequencers](https://learn.adafruit.com/trellis-m4-beat-sequencer.md)
- [Trellis Python Library](https://learn.adafruit.com/trellis-python-library.md)
- [iPad Pro Bumper](https://learn.adafruit.com/ipad-pro-bumper.md)
- [FlappyBird Game for NeoTrellis M4 in CircuitPython](https://learn.adafruit.com/circuitpython-neotrellism4-flappybird.md)
- [UNTZtrument: a Trellis MIDI Instrument](https://learn.adafruit.com/untztrument-trellis-midi-instrument.md)
- [NeoTrellis M4 Memory Game](https://learn.adafruit.com/neotrellis-m4-memory-game.md)
- [Christmas Soundboard with NeoTrellis M4](https://learn.adafruit.com/xmas-sound-board.md)
- [Star Trek Soundboard with NeoTrellis](https://learn.adafruit.com/star-trek-sound-board-with-neotrellism4.md)
- [Adafruit NeoTrellis](https://learn.adafruit.com/adafruit-neotrellis.md)
- [Keypad and Matrix Scanning in CircuitPython](https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython.md)
- [Game Grrl](https://learn.adafruit.com/game-grrl.md)
- [AdaBox 016](https://learn.adafruit.com/adabox016.md)
- [Pico Four Keypad](https://learn.adafruit.com/pico-four-key-macropad.md)
