From fa3a251c779d4aacf00e5983229ed9b584e6606a Mon Sep 17 00:00:00 2001 From: noroi28 Date: Tue, 14 Apr 2026 14:16:12 +0200 Subject: [PATCH 01/14] feat: Initialize Tamagotchi game with needs system and health mechanic. --- lib/mcp23009e/examples/tamagotchie.py | 135 ++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 lib/mcp23009e/examples/tamagotchie.py diff --git a/lib/mcp23009e/examples/tamagotchie.py b/lib/mcp23009e/examples/tamagotchie.py new file mode 100644 index 0000000..418ee02 --- /dev/null +++ b/lib/mcp23009e/examples/tamagotchie.py @@ -0,0 +1,135 @@ +from time import sleep_ms, ticks_ms, ticks_diff + +import ssd1327 +import random +from machine import I2C, SPI, Pin +from mcp23009e import MCP23009E +from mcp23009e.const import ( + MCP23009_BTN_DOWN, + MCP23009_BTN_LEFT, + MCP23009_BTN_RIGHT, + MCP23009_BTN_UP, + MCP23009_DIR_INPUT, + MCP23009_I2C_ADDR, + MCP23009_LOGIC_LOW, + MCP23009_PULLUP, +) + +# setup screen +spi = SPI(1) +dc = Pin("DATA_COMMAND_DISPLAY") +res = Pin("RST_DISPLAY") +cs = Pin("CS_DISPLAY") +display = ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs) + +#setup mcp23009e +i2c = I2C(1) +reset_expander = Pin("RST_EXPANDER", Pin.OUT) +mcp = MCP23009E(i2c, address=MCP23009_I2C_ADDR, reset_pin=reset_expander) + +# D-PAD button mapping +BUTTONS = { + MCP23009_BTN_UP: "UP", + MCP23009_BTN_DOWN: "DOWN", + MCP23009_BTN_LEFT: "LEFT", + MCP23009_BTN_RIGHT: "RIGHT", +} + +ACTION = ["food", "play"] +NEED = ["play whith me", "i'm hungry"] + +#position of button +X0 = 35 +ITEM_Y = 100 +ITEM_SPACING = 14 + +def setup_buttons(): + """Configure all D-PAD buttons as inputs with pull-ups.""" + for pin_number in BUTTONS: + mcp.setup(pin_number, MCP23009_DIR_INPUT, pullup=MCP23009_PULLUP) + + +def wait_for_button(): + """Wait for a button press and return its name.""" + for pin_number, name in BUTTONS.items(): + if mcp.get_level(pin_number) == MCP23009_LOGIC_LOW: + while mcp.get_level(pin_number) == MCP23009_LOGIC_LOW: + sleep_ms(20) + return name + return None + + +def creat_screen(selected_index, life, need): + """displays the screen""" + display.fill(0) + display.text("life {}".format(life),28, 10) + display.text(need, 15, 20) + + for index, label in enumerate(ACTION): + y = ITEM_Y + index * ITEM_SPACING + prefix = ">" if index == selected_index else " " + display.text(prefix + label, X0, y, 15) + + display.show() + + +def action_check(selected_index, need,win): + name = ACTION[selected_index] + if need == "play whith me" and name == "play": + win = True + return win + if need == "i'm hungry" and name == "food": + win = True + return win + else : + win = False + return win + + +def main(): + setup_buttons() + + selected_index = 0 + life = 100 + is_alive = True + + while is_alive: + need = random.choice(NEED) + creat_screen(selected_index, life, need) + + start = ticks_ms() + win = False + make_action = False + + while True: + timer = ticks_diff(ticks_ms(), start) + if timer >= 5000: + break + + button = wait_for_button() + if button == "UP": + selected_index = (selected_index - 1)% len(ACTION) + creat_screen(selected_index, life, need) + elif button == "DOWN": + selected_index = (selected_index + 1) % len(ACTION) + creat_screen(selected_index, life, need) + elif button == "LEFT": + win = action_check(selected_index, need, win) + make_action = True + break + sleep_ms(20) + + if win: + need = random.choice(NEED) + creat_screen(selected_index, life, need) + sleep_ms(1000) + else: + life = max(0, life - 10) + need = random.choice(NEED) + creat_screen(selected_index, life, need) + sleep_ms(1000) + + if life == 0: + is_alive = False + +main() From 11750ef3937bc086310db6fa07e6ae73fe42425c Mon Sep 17 00:00:00 2001 From: noroi28 Date: Wed, 15 Apr 2026 09:55:15 +0200 Subject: [PATCH 02/14] feat: Add first character sprites in different situations. --- lib/mcp23009e/examples/tamagotchie.py | 165 +++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 16 deletions(-) diff --git a/lib/mcp23009e/examples/tamagotchie.py b/lib/mcp23009e/examples/tamagotchie.py index 418ee02..a46b731 100644 --- a/lib/mcp23009e/examples/tamagotchie.py +++ b/lib/mcp23009e/examples/tamagotchie.py @@ -36,13 +36,121 @@ } ACTION = ["food", "play"] -NEED = ["play whith me", "i'm hungry"] +NEED = ["I'm bored", "i'm hungry"] #position of button X0 = 35 ITEM_Y = 100 ITEM_SPACING = 14 +SPRITE_BASE = [ + [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], + [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], + [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], + [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], + [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], + [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], +] + +SPRITE_HUNGRY = [ + [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], + [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], + [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], + [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], + [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], + [ 0,15, 0, 0, 0,15,15,15, 0, 0, 0,15, 0], + [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], + [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], + [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], +] + +SPRITE_SAD = [ + [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], + [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], + [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [ 0,15, 0,15,15, 0, 0, 0,15,15, 0,15, 0], + [15, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0,15], + [15, 0, 0, 0, 0,15, 0,15, 0, 0, 0, 0,15], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], + [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], + [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], +] + +SPRITE_HAPPY = [ + [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], + [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], + [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], + [15, 0, 0,15, 0,15, 0,15, 0,15, 0, 0,15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], + [ 0,15, 0, 0, 0,15, 15,15, 0, 0, 0,15, 0], + [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], + [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], + [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], +] + +SPRITE_HANGRY = [ + [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], + [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], + [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [ 0,15, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [15, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0,15], + [15, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0,15], + [ 0,15, 0, 0, 0,15, 0,15, 0, 0, 0,15, 0], + [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], + [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], + [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], + [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], +] + +SPRITE_DEAD = [ + [ 0, 0, 0, 0, 0, 0,15,15,15,15,15,15, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0,15,15, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0], + [ 0, 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], + [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0], + [ 0,15, 0, 0,15,15, 0, 0, 0, 0, 0,15, 0,15, 0, 0,15], + [ 0,15, 0,15, 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], + [ 0,15, 0,15, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0,15], + [15, 0, 0, 0,15, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15], + [15, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15, 0], + [ 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0,15, 0], + [ 0, 0,15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], + [ 0, 0, 0, 0, 0,15,15, 0, 0, 0, 0,15,15,15, 0, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0,15,15,15,15, 0, 0, 0, 0, 0, 0], +] + def setup_buttons(): """Configure all D-PAD buttons as inputs with pull-ups.""" for pin_number in BUTTONS: @@ -58,13 +166,24 @@ def wait_for_button(): return name return None - -def creat_screen(selected_index, life, need): +def draw_character(cx, cy, scale, sprite): + """Draw caractere""" + fb = display.framebuf + for y, row in enumerate(sprite): + for x, color in enumerate(row): + for dy in range(scale): + for dx in range(scale): + fb.pixel(cx + x*scale + dx, cy + y*scale + dy, color) + + + +def creat_screen(selected_index, need, sprite): """displays the screen""" display.fill(0) - display.text("life {}".format(life),28, 10) display.text(need, 15, 20) + draw_character(40, 40, 3, sprite) + for index, label in enumerate(ACTION): y = ITEM_Y + index * ITEM_SPACING prefix = ">" if index == selected_index else " " @@ -75,7 +194,7 @@ def creat_screen(selected_index, life, need): def action_check(selected_index, need,win): name = ACTION[selected_index] - if need == "play whith me" and name == "play": + if need == "I'm bored" and name == "play": win = True return win if need == "i'm hungry" and name == "food": @@ -85,17 +204,31 @@ def action_check(selected_index, need,win): win = False return win +def creat_game_over_screen(): + display.fill(0) + display.text("Game-Over",25, 20) + draw_character(35, 45, 3, SPRITE_DEAD) + display.show() -def main(): +def main(): setup_buttons() selected_index = 0 - life = 100 + life = 30 is_alive = True - + while is_alive: + need = " " + creat_screen(selected_index, need, SPRITE_BASE) + sleep_ms(1000) + need = random.choice(NEED) - creat_screen(selected_index, life, need) + if need == "I'm bored" : + sprite = SPRITE_SAD + else : + sprite = SPRITE_HUNGRY + + creat_screen(selected_index, need, sprite) start = ticks_ms() win = False @@ -109,10 +242,10 @@ def main(): button = wait_for_button() if button == "UP": selected_index = (selected_index - 1)% len(ACTION) - creat_screen(selected_index, life, need) + creat_screen(selected_index, need, sprite) elif button == "DOWN": selected_index = (selected_index + 1) % len(ACTION) - creat_screen(selected_index, life, need) + creat_screen(selected_index, need, sprite) elif button == "LEFT": win = action_check(selected_index, need, win) make_action = True @@ -120,16 +253,16 @@ def main(): sleep_ms(20) if win: - need = random.choice(NEED) - creat_screen(selected_index, life, need) + sleep_ms(1000) + creat_screen(selected_index, need, SPRITE_HAPPY) sleep_ms(1000) else: - life = max(0, life - 10) - need = random.choice(NEED) - creat_screen(selected_index, life, need) + life = max(-10, life - 10) + creat_screen(selected_index, need, SPRITE_HANGRY) sleep_ms(1000) if life == 0: is_alive = False + creat_game_over_screen() main() From 166cbd6b2bd25ae671191b811b3a2643f352d73b Mon Sep 17 00:00:00 2001 From: noroi28 Date: Wed, 15 Apr 2026 13:50:31 +0200 Subject: [PATCH 03/14] feat: Add a Tamagotchi aging system based on battery percentage. --- lib/mcp23009e/examples/tamagotchie.py | 61 +++++++++++++++++++-------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/lib/mcp23009e/examples/tamagotchie.py b/lib/mcp23009e/examples/tamagotchie.py index a46b731..f347084 100644 --- a/lib/mcp23009e/examples/tamagotchie.py +++ b/lib/mcp23009e/examples/tamagotchie.py @@ -2,6 +2,7 @@ import ssd1327 import random +from bq27441 import BQ27441 from machine import I2C, SPI, Pin from mcp23009e import MCP23009E from mcp23009e.const import ( @@ -27,6 +28,9 @@ reset_expander = Pin("RST_EXPANDER", Pin.OUT) mcp = MCP23009E(i2c, address=MCP23009_I2C_ADDR, reset_pin=reset_expander) +#setup battery +fg = BQ27441(i2c) + # D-PAD button mapping BUTTONS = { MCP23009_BTN_UP: "UP", @@ -43,6 +47,9 @@ ITEM_Y = 100 ITEM_SPACING = 14 + +#sprite + SPRITE_BASE = [ [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], @@ -151,6 +158,8 @@ [ 0, 0, 0, 0, 0, 0, 0,15,15,15,15, 0, 0, 0, 0, 0, 0], ] +#------------------------------------SCREEN---------------------------------------------- + def setup_buttons(): """Configure all D-PAD buttons as inputs with pull-ups.""" for pin_number in BUTTONS: @@ -177,12 +186,26 @@ def draw_character(cx, cy, scale, sprite): -def creat_screen(selected_index, need, sprite): +def creat_screen(selected_index, need, sprite, charge): """displays the screen""" display.fill(0) - display.text(need, 15, 20) + display.text(need, 25, 20) + display.text(str(charge), 50, 10) + + if charge > 70 : + scale = 1 + x = 55 + y = 60 + elif charge < 70 and charge > 40 : + scale = 2 + x = 45 + y = 50 + else : + scale = 3 + x = 40 + y = 40 - draw_character(40, 40, 3, sprite) + draw_character(x, y, scale, sprite) for index, label in enumerate(ACTION): y = ITEM_Y + index * ITEM_SPACING @@ -191,6 +214,12 @@ def creat_screen(selected_index, need, sprite): display.show() +def creat_game_over_screen(): + display.fill(0) + display.text("Game-Over",25, 20) + draw_character(35, 45, 3, SPRITE_DEAD) + display.show() +#------------------------------------gameplay---------------------------------------------- def action_check(selected_index, need,win): name = ACTION[selected_index] @@ -204,22 +233,20 @@ def action_check(selected_index, need,win): win = False return win -def creat_game_over_screen(): - display.fill(0) - display.text("Game-Over",25, 20) - draw_character(35, 45, 3, SPRITE_DEAD) - display.show() + +#------------------------------------main---------------------------------------------- def main(): setup_buttons() selected_index = 0 - life = 30 is_alive = True while is_alive: + charge = fg.state_of_charge() + need = " " - creat_screen(selected_index, need, SPRITE_BASE) + creat_screen(selected_index, need, SPRITE_BASE, charge) sleep_ms(1000) need = random.choice(NEED) @@ -228,7 +255,7 @@ def main(): else : sprite = SPRITE_HUNGRY - creat_screen(selected_index, need, sprite) + creat_screen(selected_index, need, sprite, charge) start = ticks_ms() win = False @@ -239,13 +266,14 @@ def main(): if timer >= 5000: break + button = wait_for_button() if button == "UP": selected_index = (selected_index - 1)% len(ACTION) - creat_screen(selected_index, need, sprite) + creat_screen(selected_index, need, sprite, charge) elif button == "DOWN": selected_index = (selected_index + 1) % len(ACTION) - creat_screen(selected_index, need, sprite) + creat_screen(selected_index, need, sprite, charge) elif button == "LEFT": win = action_check(selected_index, need, win) make_action = True @@ -254,14 +282,13 @@ def main(): if win: sleep_ms(1000) - creat_screen(selected_index, need, SPRITE_HAPPY) + creat_screen(selected_index, need, SPRITE_HAPPY, charge) sleep_ms(1000) else: - life = max(-10, life - 10) - creat_screen(selected_index, need, SPRITE_HANGRY) + creat_screen(selected_index, need, SPRITE_HANGRY, charge) sleep_ms(1000) - if life == 0: + if charge < 10: is_alive = False creat_game_over_screen() From 7d1119d3b4225623692a1d7b8c993a329cd825ce Mon Sep 17 00:00:00 2001 From: noroi28 Date: Wed, 15 Apr 2026 13:56:21 +0200 Subject: [PATCH 04/14] refactor: Move file to correct directory. --- lib/{mcp23009e => bq27441}/examples/tamagotchie.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/{mcp23009e => bq27441}/examples/tamagotchie.py (100%) diff --git a/lib/mcp23009e/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py similarity index 100% rename from lib/mcp23009e/examples/tamagotchie.py rename to lib/bq27441/examples/tamagotchie.py From ce8b6bceb9f8c0bfe56bdf788206e0a46270cbb1 Mon Sep 17 00:00:00 2001 From: noroi28 Date: Wed, 15 Apr 2026 16:09:50 +0200 Subject: [PATCH 05/14] feat: Add sound effects to the Tamagotchi. --- lib/bq27441/examples/tamagotchie.py | 85 +++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index f347084..eb76114 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -1,10 +1,11 @@ -from time import sleep_ms, ticks_ms, ticks_diff - import ssd1327 import random +from pyb import Timer from bq27441 import BQ27441 +from time import sleep_ms, ticks_ms, ticks_diff from machine import I2C, SPI, Pin from mcp23009e import MCP23009E +from apds9960 import uAPDS9960 as APDS9960 from mcp23009e.const import ( MCP23009_BTN_DOWN, MCP23009_BTN_LEFT, @@ -31,6 +32,11 @@ #setup battery fg = BQ27441(i2c) +#sound +buzzer_tim = Timer(1, freq=1000) +buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) +buzzer_ch.pulse_width_percent(0) + # D-PAD button mapping BUTTONS = { MCP23009_BTN_UP: "UP", @@ -47,7 +53,6 @@ ITEM_Y = 100 ITEM_SPACING = 14 - #sprite SPRITE_BASE = [ @@ -233,16 +238,66 @@ def action_check(selected_index, need,win): win = False return win +def soud_effect(name): + sound = { + "start": [ + (523, 120), + (659, 120), + (784, 120), + (1047, 400), + ], + + "hungry": [ + (400, 150), + (350, 150), + (300, 300), + ], + + "bored": [ + (500, 120), + (650, 120), + (800, 200), + ], + + "success": [ + (600, 100), + (800, 100), + (1000, 200), + ], + + "evolution": [ + (600, 120), + (750, 120), + (900, 120), + (1100, 150), + (1300, 300), + ], + + "fail": [ + (500, 150), + (400, 150), + (300, 400), + ] + } + melody = sound[name] + for freq, duration_ms in melody: + buzzer_tim.freq(freq) + buzzer_ch.pulse_width_percent(10) + sleep_ms(duration_ms) + buzzer_ch.pulse_width_percent(0) + sleep_ms(30) + #------------------------------------main---------------------------------------------- def main(): - setup_buttons() - - selected_index = 0 + setup_buttons( + soud_effect("start") is_alive = True + nb_tour = 0 while is_alive: + selected_index = 0 charge = fg.state_of_charge() need = " " @@ -252,13 +307,17 @@ def main(): need = random.choice(NEED) if need == "I'm bored" : sprite = SPRITE_SAD + soud_effect("bored") + nb_tour = nb_tour + 1 else : sprite = SPRITE_HUNGRY + soud_effect("hungry") + nb_tour = nb_tour + 1 creat_screen(selected_index, need, sprite, charge) start = ticks_ms() - win = False + win = None make_action = False while True: @@ -280,16 +339,20 @@ def main(): break sleep_ms(20) - if win: - sleep_ms(1000) + if win: creat_screen(selected_index, need, SPRITE_HAPPY, charge) - sleep_ms(1000) + soud_effect("success") + nb_tour = nb_tour + 1 else: creat_screen(selected_index, need, SPRITE_HANGRY, charge) - sleep_ms(1000) + soud_effect("fail") + nb_tour = nb_tour + 1 + sleep_ms(1000) if charge < 10: is_alive = False creat_game_over_screen() + print("fin de tour") + print(nb_tour) main() From c77a01e17216fabce017342f26b7ba02c67efb71 Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 09:43:54 +0200 Subject: [PATCH 06/14] chore: Fix code with ruff. --- lib/bq27441/examples/tamagotchie.py | 67 +++++++++++++---------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index eb76114..6be0488 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -1,11 +1,10 @@ -import ssd1327 import random -from pyb import Timer +from time import sleep_ms, ticks_diff, ticks_ms + +import ssd1327 from bq27441 import BQ27441 -from time import sleep_ms, ticks_ms, ticks_diff from machine import I2C, SPI, Pin from mcp23009e import MCP23009E -from apds9960 import uAPDS9960 as APDS9960 from mcp23009e.const import ( MCP23009_BTN_DOWN, MCP23009_BTN_LEFT, @@ -16,6 +15,7 @@ MCP23009_LOGIC_LOW, MCP23009_PULLUP, ) +from pyb import Timer # setup screen spi = SPI(1) @@ -24,20 +24,20 @@ cs = Pin("CS_DISPLAY") display = ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs) -#setup mcp23009e +# setup mcp23009e i2c = I2C(1) reset_expander = Pin("RST_EXPANDER", Pin.OUT) mcp = MCP23009E(i2c, address=MCP23009_I2C_ADDR, reset_pin=reset_expander) -#setup battery +# setup battery fg = BQ27441(i2c) -#sound +# sound buzzer_tim = Timer(1, freq=1000) buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) buzzer_ch.pulse_width_percent(0) -# D-PAD button mapping +# D-PAD button mapping BUTTONS = { MCP23009_BTN_UP: "UP", MCP23009_BTN_DOWN: "DOWN", @@ -48,12 +48,12 @@ ACTION = ["food", "play"] NEED = ["I'm bored", "i'm hungry"] -#position of button +# position of button X0 = 35 ITEM_Y = 100 ITEM_SPACING = 14 -#sprite +# sprite SPRITE_BASE = [ [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], @@ -163,7 +163,7 @@ [ 0, 0, 0, 0, 0, 0, 0,15,15,15,15, 0, 0, 0, 0, 0, 0], ] -#------------------------------------SCREEN---------------------------------------------- +# ------------------------------------SCREEN---------------------------------------------- def setup_buttons(): """Configure all D-PAD buttons as inputs with pull-ups.""" @@ -188,16 +188,15 @@ def draw_character(cx, cy, scale, sprite): for dy in range(scale): for dx in range(scale): fb.pixel(cx + x*scale + dx, cy + y*scale + dy, color) - - - + + def creat_screen(selected_index, need, sprite, charge): """displays the screen""" display.fill(0) display.text(need, 25, 20) display.text(str(charge), 50, 10) - if charge > 70 : + if charge > 70 : scale = 1 x = 55 y = 60 @@ -220,18 +219,18 @@ def creat_screen(selected_index, need, sprite, charge): display.show() def creat_game_over_screen(): - display.fill(0) + display.fill(0) display.text("Game-Over",25, 20) draw_character(35, 45, 3, SPRITE_DEAD) display.show() -#------------------------------------gameplay---------------------------------------------- +# ------------------------------------gameplay---------------------------------------------- def action_check(selected_index, need,win): name = ACTION[selected_index] if need == "I'm bored" and name == "play": win = True return win - if need == "i'm hungry" and name == "food": + if need == "i'm hungry" and name == "food": win = True return win else : @@ -241,9 +240,9 @@ def action_check(selected_index, need,win): def soud_effect(name): sound = { "start": [ - (523, 120), - (659, 120), - (784, 120), + (523, 120), + (659, 120), + (784, 120), (1047, 400), ], @@ -285,17 +284,17 @@ def soud_effect(name): buzzer_ch.pulse_width_percent(10) sleep_ms(duration_ms) buzzer_ch.pulse_width_percent(0) - sleep_ms(30) + sleep_ms(30) -#------------------------------------main---------------------------------------------- +# ------------------------------------main---------------------------------------------- def main(): - setup_buttons( - soud_effect("start") + setup_buttons() + # soud_effect("start") is_alive = True nb_tour = 0 - + while is_alive: selected_index = 0 charge = fg.state_of_charge() @@ -308,45 +307,39 @@ def main(): if need == "I'm bored" : sprite = SPRITE_SAD soud_effect("bored") - nb_tour = nb_tour + 1 else : sprite = SPRITE_HUNGRY soud_effect("hungry") - nb_tour = nb_tour + 1 creat_screen(selected_index, need, sprite, charge) start = ticks_ms() win = None - make_action = False while True: timer = ticks_diff(ticks_ms(), start) if timer >= 5000: - break + break button = wait_for_button() - if button == "UP": + if button == "UP": selected_index = (selected_index - 1)% len(ACTION) creat_screen(selected_index, need, sprite, charge) - elif button == "DOWN": + elif button == "DOWN": selected_index = (selected_index + 1) % len(ACTION) creat_screen(selected_index, need, sprite, charge) - elif button == "LEFT": + elif button == "LEFT": win = action_check(selected_index, need, win) - make_action = True - break + break sleep_ms(20) if win: creat_screen(selected_index, need, SPRITE_HAPPY, charge) soud_effect("success") - nb_tour = nb_tour + 1 else: creat_screen(selected_index, need, SPRITE_HANGRY, charge) soud_effect("fail") - nb_tour = nb_tour + 1 sleep_ms(1000) if charge < 10: From 307a55fbe2cb99910dbefb822112bb6a1ad0ed0f Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 10:09:22 +0200 Subject: [PATCH 07/14] chore: Remove debugging code. --- lib/bq27441/examples/tamagotchie.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index 6be0488..5e42bf4 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -293,7 +293,6 @@ def main(): setup_buttons() # soud_effect("start") is_alive = True - nb_tour = 0 while is_alive: selected_index = 0 @@ -345,7 +344,4 @@ def main(): if charge < 10: is_alive = False creat_game_over_screen() - - print("fin de tour") - print(nb_tour) main() From 5c2da7615047791d8fb3d1758b3a9246fa89e78a Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 11:25:49 +0200 Subject: [PATCH 08/14] refactor: Fix typos, move sound dict, add buzzer cleanup. --- lib/bq27441/examples/tamagotchie.py | 196 ++++++++++++++-------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index 5e42bf4..f444d07 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -163,6 +163,47 @@ [ 0, 0, 0, 0, 0, 0, 0,15,15,15,15, 0, 0, 0, 0, 0, 0], ] +SOUND = { + "start": [ + (523, 120), + (659, 120), + (784, 120), + (1047, 400), + ], + + "hungry": [ + (400, 150), + (350, 150), + (300, 300), + ], + + "bored": [ + (500, 120), + (650, 120), + (800, 200), + ], + + "success": [ + (600, 100), + (800, 100), + (1000, 200), + ], + + "evolution": [ + (600, 120), + (750, 120), + (900, 120), + (1100, 150), + (1300, 300), + ], + + "fail": [ + (500, 150), + (400, 150), + (300, 400), + ] + } + # ------------------------------------SCREEN---------------------------------------------- def setup_buttons(): @@ -181,7 +222,7 @@ def wait_for_button(): return None def draw_character(cx, cy, scale, sprite): - """Draw caractere""" + """Draw character""" fb = display.framebuf for y, row in enumerate(sprite): for x, color in enumerate(row): @@ -190,7 +231,7 @@ def draw_character(cx, cy, scale, sprite): fb.pixel(cx + x*scale + dx, cy + y*scale + dy, color) -def creat_screen(selected_index, need, sprite, charge): +def create_screen(selected_index, need, sprite, charge): """displays the screen""" display.fill(0) display.text(need, 25, 20) @@ -218,7 +259,7 @@ def creat_screen(selected_index, need, sprite, charge): display.show() -def creat_game_over_screen(): +def create_game_over_screen(): display.fill(0) display.text("Game-Over",25, 20) draw_character(35, 45, 3, SPRITE_DEAD) @@ -237,48 +278,8 @@ def action_check(selected_index, need,win): win = False return win -def soud_effect(name): - sound = { - "start": [ - (523, 120), - (659, 120), - (784, 120), - (1047, 400), - ], - - "hungry": [ - (400, 150), - (350, 150), - (300, 300), - ], - - "bored": [ - (500, 120), - (650, 120), - (800, 200), - ], - - "success": [ - (600, 100), - (800, 100), - (1000, 200), - ], - - "evolution": [ - (600, 120), - (750, 120), - (900, 120), - (1100, 150), - (1300, 300), - ], - - "fail": [ - (500, 150), - (400, 150), - (300, 400), - ] - } - melody = sound[name] +def sound_effect(name): + melody = SOUND[name] for freq, duration_ms in melody: buzzer_tim.freq(freq) buzzer_ch.pulse_width_percent(10) @@ -291,57 +292,60 @@ def soud_effect(name): def main(): setup_buttons() - # soud_effect("start") + sound_effect("start") is_alive = True - while is_alive: - selected_index = 0 - charge = fg.state_of_charge() - - need = " " - creat_screen(selected_index, need, SPRITE_BASE, charge) - sleep_ms(1000) - - need = random.choice(NEED) - if need == "I'm bored" : - sprite = SPRITE_SAD - soud_effect("bored") - else : - sprite = SPRITE_HUNGRY - soud_effect("hungry") - - creat_screen(selected_index, need, sprite, charge) - - start = ticks_ms() - win = None - - while True: - timer = ticks_diff(ticks_ms(), start) - if timer >= 5000: - break - - - button = wait_for_button() - if button == "UP": - selected_index = (selected_index - 1)% len(ACTION) - creat_screen(selected_index, need, sprite, charge) - elif button == "DOWN": - selected_index = (selected_index + 1) % len(ACTION) - creat_screen(selected_index, need, sprite, charge) - elif button == "LEFT": - win = action_check(selected_index, need, win) - break - sleep_ms(20) - - if win: - creat_screen(selected_index, need, SPRITE_HAPPY, charge) - soud_effect("success") - else: - creat_screen(selected_index, need, SPRITE_HANGRY, charge) - soud_effect("fail") - sleep_ms(1000) - - if charge < 10: - is_alive = False - creat_game_over_screen() + try: + while is_alive: + selected_index = 0 + charge = fg.state_of_charge() + + need = " " + create_screen(selected_index, need, SPRITE_BASE, charge) + sleep_ms(1000) + + need = random.choice(NEED) + if need == "I'm bored" : + sprite = SPRITE_SAD + sound_effect("bored") + else : + sprite = SPRITE_HUNGRY + sound_effect("hungry") + + create_screen(selected_index, need, sprite, charge) + + start = ticks_ms() + win = None + + while True: + timer = ticks_diff(ticks_ms(), start) + if timer >= 5000: + break + + + button = wait_for_button() + if button == "UP": + selected_index = (selected_index - 1)% len(ACTION) + create_screen(selected_index, need, sprite, charge) + elif button == "DOWN": + selected_index = (selected_index + 1) % len(ACTION) + create_screen(selected_index, need, sprite, charge) + elif button == "LEFT": + win = action_check(selected_index, need, win) + break + sleep_ms(20) + + if win: + create_screen(selected_index, need, SPRITE_HAPPY, charge) + sound_effect("success") + else: + create_screen(selected_index, need, SPRITE_HANGRY, charge) + sound_effect("fail") + sleep_ms(1000) + + if charge < 10: + is_alive = False + create_game_over_screen() + finally: + buzzer_ch.pulse_width_percent(0) main() From c823af8f2199cc865e65937f1f8ac3b8ce13284f Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 11:50:29 +0200 Subject: [PATCH 09/14] style: Fix ruff E201/E231 lint errors in sprite arrays. --- lib/bq27441/examples/tamagotchie.py | 182 ++++++++++++++-------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index f444d07..610a13e 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -56,111 +56,111 @@ # sprite SPRITE_BASE = [ - [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], - [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], - [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], - [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], - [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], - [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], - [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], - [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], + [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], + [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], + [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [0, 15, 0, 0, 15, 0, 0, 0, 15, 0, 0, 15, 0], + [ 15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], + [0, 0, 0,15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] SPRITE_HUNGRY = [ - [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], - [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], - [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], - [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], - [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], - [15, 0, 0, 0, 0,15,15,15, 0, 0, 0, 0,15], - [ 0,15, 0, 0, 0,15,15,15, 0, 0, 0,15, 0], - [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], - [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], - [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], + [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], + [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], + [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0], + [0, 15, 0, 0, 15, 0, 0, 0, 15, 0, 0, 15, 0], + [15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15], + [15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15], + [0, 15, 0, 0, 0, 15, 15, 15, 0, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] SPRITE_SAD = [ - [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], - [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], - [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], - [ 0,15, 0,15,15, 0, 0, 0,15,15, 0,15, 0], - [15, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0,15], - [15, 0, 0, 0, 0,15, 0,15, 0, 0, 0, 0,15], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], - [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], - [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], + [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], + [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], + [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0], + [0, 15, 0, 15, 15, 0, 0, 0, 15, 15, 0, 15, 0], + [15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 15], + [15, 0, 0, 0, 0, 15, 0, 15, 0, 0, 0, 0, 15], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] SPRITE_HAPPY = [ - [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], - [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], - [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], - [ 0,15, 0, 0,15, 0, 0, 0,15, 0, 0,15, 0], - [15, 0, 0,15, 0,15, 0,15, 0,15, 0, 0,15], - [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], - [ 0,15, 0, 0, 0,15, 15,15, 0, 0, 0,15, 0], - [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], - [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], - [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], + [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], + [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], + [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0], + [0, 15, 0, 0, 15, 0, 0, 0, 15, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], + [0, 15, 0, 0, 0, 15, 15, 15, 0, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] SPRITE_HANGRY = [ - [ 0, 0,15,15, 0, 0, 0, 0, 0,15,15, 0, 0], - [ 0,15,15,15,15, 0, 0, 0,15,15,15,15, 0], - [ 0,15,15,15,15,15,15,15,15,15,15,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], - [ 0,15, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [15, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0,15], - [15, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0,15], - [ 0,15, 0, 0, 0,15, 0,15, 0, 0, 0,15, 0], - [15, 0, 0,15, 0, 0, 0, 0, 0,15, 0,15, 0], - [ 0,15,15, 0, 0, 0, 0, 0, 0,15,15,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0,15, 0,15,15,15, 0,15, 0, 0, 0], - [ 0, 0, 0,15, 0,15, 0,15, 0,15, 0, 0, 0], - [ 0, 0, 0, 0,15, 0, 0, 0,15, 0, 0, 0, 0], + [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], + [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], + [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0], + [0, 15, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [15, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 15], + [15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 15], + [0, 15, 0, 0, 0, 15, 0, 15, 0, 0, 0, 15, 0], + [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] SPRITE_DEAD = [ - [ 0, 0, 0, 0, 0, 0,15,15,15,15,15,15, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0,15,15, 0, 0, 0, 0, 0, 0,15,15, 0, 0, 0], - [ 0, 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0], - [ 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0], - [ 0,15, 0, 0,15,15, 0, 0, 0, 0, 0,15, 0,15, 0, 0,15], - [ 0,15, 0,15, 0, 0,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15], - [ 0,15, 0,15, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0,15], - [15, 0, 0, 0,15, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15], - [15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15], - [15, 0, 0, 0, 0, 0, 0, 0, 0,15,15,15,15,15, 0,15, 0], - [ 0,15, 0, 0, 0, 0, 0, 0, 0,15, 0,15, 0,15, 0,15, 0], - [ 0, 0,15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0], - [ 0, 0, 0, 0, 0,15,15, 0, 0, 0, 0,15,15,15, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0,15,15,15,15, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], + [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0], + [0, 15, 0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0, 0, 15], + [0, 15, 0, 15, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], + [0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15], + [15, 0, 0, 0, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 15], + [15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 15, 0], + [0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0], + [0, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], + [0, 0, 0, 0, 0, 15, 15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0], ] SOUND = { @@ -295,7 +295,7 @@ def main(): sound_effect("start") is_alive = True - try: + try: while is_alive: selected_index = 0 charge = fg.state_of_charge() From fd04b5f8a44b827637f705f0e4fff3d8f5439016 Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 12:00:41 +0200 Subject: [PATCH 10/14] fix: Fix lint E221 and invisible text on GS4 OLED. --- lib/bq27441/examples/tamagotchie.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index 610a13e..c354b08 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -34,7 +34,7 @@ # sound buzzer_tim = Timer(1, freq=1000) -buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) +buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) buzzer_ch.pulse_width_percent(0) # D-PAD button mapping @@ -59,9 +59,9 @@ [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], - [0, 15, 15, 0, 0, 0, 0, 0, 0, 0,15,15, 0], + [0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0], [0, 15, 0, 0, 15, 0, 0, 0, 15, 0, 0, 15, 0], - [ 15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15], + [15, 0, 0, 0, 0, 15, 15, 15, 0, 0, 0, 0, 15], [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], [15, 0, 0, 15, 0, 0, 0, 0, 0, 15, 0, 15, 0], @@ -69,7 +69,7 @@ [0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0], [0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0], [0, 0, 0, 15, 0, 15, 15, 15, 0, 15, 0, 0, 0], - [0, 0, 0,15, 0, 15, 0, 15, 0, 15, 0, 0, 0], + [0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0], [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] @@ -234,8 +234,8 @@ def draw_character(cx, cy, scale, sprite): def create_screen(selected_index, need, sprite, charge): """displays the screen""" display.fill(0) - display.text(need, 25, 20) - display.text(str(charge), 50, 10) + display.text(need, 25, 20, 15) + display.text(str(charge), 50, 10, 15) if charge > 70 : scale = 1 @@ -261,7 +261,7 @@ def create_screen(selected_index, need, sprite, charge): def create_game_over_screen(): display.fill(0) - display.text("Game-Over",25, 20) + display.text("Game-Over",25, 20, 15) draw_character(35, 45, 3, SPRITE_DEAD) display.show() # ------------------------------------gameplay---------------------------------------------- From 83fb146c678900f088f4bc9177da87ce81ca9928 Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 12:06:27 +0200 Subject: [PATCH 11/14] fix: Fix SPRITE_BASE formatting to comply with ruff E201/E231. --- lib/bq27441/examples/tamagotchie.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index c354b08..065544a 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -237,11 +237,11 @@ def create_screen(selected_index, need, sprite, charge): display.text(need, 25, 20, 15) display.text(str(charge), 50, 10, 15) - if charge > 70 : + if charge >= 70 : scale = 1 x = 55 y = 60 - elif charge < 70 and charge > 40 : + elif 40 <= charge < 70: scale = 2 x = 45 y = 50 From 2a5375c19e54bd70e3813f259d389a09ef53692b Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 12:40:27 +0200 Subject: [PATCH 12/14] fix: Remove redundant upper bound in charge elif condition. --- lib/bq27441/examples/tamagotchie.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index 065544a..ff57dc8 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -237,15 +237,15 @@ def create_screen(selected_index, need, sprite, charge): display.text(need, 25, 20, 15) display.text(str(charge), 50, 10, 15) - if charge >= 70 : + if charge >= 70: scale = 1 x = 55 y = 60 - elif 40 <= charge < 70: + elif 40 <= charge: scale = 2 x = 45 y = 50 - else : + else: scale = 3 x = 40 y = 40 From 21c8f9ddb0b1096cb2dd4cf3d306e58dfe0c7c47 Mon Sep 17 00:00:00 2001 From: noroi28 Date: Thu, 16 Apr 2026 12:43:07 +0200 Subject: [PATCH 13/14] fix: Fix ruff linting errors. --- lib/bq27441/examples/tamagotchie.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchie.py index ff57dc8..b3812c4 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchie.py @@ -241,7 +241,7 @@ def create_screen(selected_index, need, sprite, charge): scale = 1 x = 55 y = 60 - elif 40 <= charge: + elif charge >= 40: scale = 2 x = 45 y = 50 From e3629488242769cdd515fe70d79c35aabfaa524b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20NEDJAR?= Date: Thu, 16 Apr 2026 22:13:16 +0200 Subject: [PATCH 14/14] fix(bq27441): Fix tamagotchi example naming, logic and style. Address review comments from #399: 1. Rename tamagotchie.py -> tamagotchi.py (fix English spelling). 2. Harmonize NEED casing: "i'm hungry" -> "I'm hungry" and update the matching logic in action_check accordingly. 3. Simplify action_check: remove the unused `win` parameter (it was always overwritten before being read) and return a boolean directly. 4. Remove unused "evolution" sound (defined but never played). 5. Rename SPRITE_HANGRY -> SPRITE_ANGRY (standard English). 6. Fix all style issues: spaces before colons (E203), inconsistent SOUND dict indentation, missing blank lines before functions (E302), missing operator spacing in draw_character (E225), double blank lines inside blocks (E303). 7. Add docstrings to all functions and a module-level docstring. 8. Name magic timing constants: IDLE_DISPLAY_MS, RESPONSE_TIMEOUT_MS, RESULT_DISPLAY_MS. 9. Add phase comments in main() for readability (idle / need / response / result). --- .../{tamagotchie.py => tamagotchi.py} | 184 +++++++++--------- 1 file changed, 93 insertions(+), 91 deletions(-) rename lib/bq27441/examples/{tamagotchie.py => tamagotchi.py} (76%) diff --git a/lib/bq27441/examples/tamagotchie.py b/lib/bq27441/examples/tamagotchi.py similarity index 76% rename from lib/bq27441/examples/tamagotchie.py rename to lib/bq27441/examples/tamagotchi.py index b3812c4..d5b873d 100644 --- a/lib/bq27441/examples/tamagotchie.py +++ b/lib/bq27441/examples/tamagotchi.py @@ -1,3 +1,15 @@ +"""Battery Tamagotchi example using BQ27441, MCP23009E D-PAD, SSD1327 OLED and buzzer. + +The creature ages based on the real battery percentage and periodically asks +to be fed or played with via the D-PAD. A correct answer triggers a happy +sprite + success sound; a wrong or missed answer triggers an angry sprite + +fail sound. When the battery drops below 10 %, the game is over. + +Controls: + UP / DOWN -> navigate the action menu + LEFT -> confirm selection +""" + import random from time import sleep_ms, ticks_diff, ticks_ms @@ -17,27 +29,26 @@ ) from pyb import Timer -# setup screen +# --- Hardware setup --- + spi = SPI(1) dc = Pin("DATA_COMMAND_DISPLAY") res = Pin("RST_DISPLAY") cs = Pin("CS_DISPLAY") display = ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs) -# setup mcp23009e i2c = I2C(1) reset_expander = Pin("RST_EXPANDER", Pin.OUT) mcp = MCP23009E(i2c, address=MCP23009_I2C_ADDR, reset_pin=reset_expander) -# setup battery fg = BQ27441(i2c) -# sound buzzer_tim = Timer(1, freq=1000) buzzer_ch = buzzer_tim.channel(4, Timer.PWM, pin=Pin("SPEAKER")) buzzer_ch.pulse_width_percent(0) -# D-PAD button mapping +# --- Constants --- + BUTTONS = { MCP23009_BTN_UP: "UP", MCP23009_BTN_DOWN: "DOWN", @@ -46,14 +57,17 @@ } ACTION = ["food", "play"] -NEED = ["I'm bored", "i'm hungry"] +NEED = ["I'm bored", "I'm hungry"] + +IDLE_DISPLAY_MS = 1000 +RESPONSE_TIMEOUT_MS = 5000 +RESULT_DISPLAY_MS = 1000 -# position of button X0 = 35 ITEM_Y = 100 ITEM_SPACING = 14 -# sprite +# --- Sprites --- SPRITE_BASE = [ [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], @@ -127,7 +141,7 @@ [0, 0, 0, 0, 15, 0, 0, 0, 15, 0, 0, 0, 0], ] -SPRITE_HANGRY = [ +SPRITE_ANGRY = [ [0, 0, 15, 15, 0, 0, 0, 0, 0, 15, 15, 0, 0], [0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 0], [0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0], @@ -163,48 +177,39 @@ [0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0], ] +# --- Sounds --- + SOUND = { - "start": [ - (523, 120), - (659, 120), - (784, 120), + "start": [ + (523, 120), + (659, 120), + (784, 120), (1047, 400), - ], - - "hungry": [ - (400, 150), - (350, 150), - (300, 300), - ], - - "bored": [ - (500, 120), - (650, 120), - (800, 200), - ], - - "success": [ - (600, 100), - (800, 100), - (1000, 200), - ], - - "evolution": [ - (600, 120), - (750, 120), - (900, 120), - (1100, 150), - (1300, 300), - ], - - "fail": [ - (500, 150), - (400, 150), - (300, 400), - ] - } - -# ------------------------------------SCREEN---------------------------------------------- + ], + "hungry": [ + (400, 150), + (350, 150), + (300, 300), + ], + "bored": [ + (500, 120), + (650, 120), + (800, 200), + ], + "success": [ + (600, 100), + (800, 100), + (1000, 200), + ], + "fail": [ + (500, 150), + (400, 150), + (300, 400), + ], +} + +# --- Helpers --- + def setup_buttons(): """Configure all D-PAD buttons as inputs with pull-ups.""" @@ -213,7 +218,7 @@ def setup_buttons(): def wait_for_button(): - """Wait for a button press and return its name.""" + """Poll D-PAD once and return the pressed button name, or None.""" for pin_number, name in BUTTONS.items(): if mcp.get_level(pin_number) == MCP23009_LOGIC_LOW: while mcp.get_level(pin_number) == MCP23009_LOGIC_LOW: @@ -221,66 +226,57 @@ def wait_for_button(): return name return None + def draw_character(cx, cy, scale, sprite): - """Draw character""" + """Draw a scaled pixel-art sprite on the display framebuf.""" fb = display.framebuf for y, row in enumerate(sprite): for x, color in enumerate(row): for dy in range(scale): for dx in range(scale): - fb.pixel(cx + x*scale + dx, cy + y*scale + dy, color) + fb.pixel(cx + x * scale + dx, cy + y * scale + dy, color) def create_screen(selected_index, need, sprite, charge): - """displays the screen""" + """Render one game frame: sprite, need text, charge and action menu.""" display.fill(0) display.text(need, 25, 20, 15) display.text(str(charge), 50, 10, 15) if charge >= 70: - scale = 1 - x = 55 - y = 60 + scale, x, y = 1, 55, 60 elif charge >= 40: - scale = 2 - x = 45 - y = 50 + scale, x, y = 2, 45, 50 else: - scale = 3 - x = 40 - y = 40 + scale, x, y = 3, 40, 40 draw_character(x, y, scale, sprite) for index, label in enumerate(ACTION): - y = ITEM_Y + index * ITEM_SPACING + row_y = ITEM_Y + index * ITEM_SPACING prefix = ">" if index == selected_index else " " - display.text(prefix + label, X0, y, 15) + display.text(prefix + label, X0, row_y, 15) display.show() + def create_game_over_screen(): + """Display the game-over screen.""" display.fill(0) - display.text("Game-Over",25, 20, 15) + display.text("Game Over", 25, 20, 15) draw_character(35, 45, 3, SPRITE_DEAD) display.show() -# ------------------------------------gameplay---------------------------------------------- -def action_check(selected_index, need,win): + +def action_check(selected_index, need): + """Check if the selected action matches the current need.""" name = ACTION[selected_index] - if need == "I'm bored" and name == "play": - win = True - return win - if need == "i'm hungry" and name == "food": - win = True - return win - else : - win = False - return win + return (need == "I'm bored" and name == "play") or (need == "I'm hungry" and name == "food") + def sound_effect(name): - melody = SOUND[name] - for freq, duration_ms in melody: + """Play a short melody from the SOUND dictionary.""" + for freq, duration_ms in SOUND[name]: buzzer_tim.freq(freq) buzzer_ch.pulse_width_percent(10) sleep_ms(duration_ms) @@ -288,9 +284,11 @@ def sound_effect(name): sleep_ms(30) -# ------------------------------------main---------------------------------------------- +# --- Main game loop --- + def main(): + """Run the Tamagotchi game.""" setup_buttons() sound_effect("start") is_alive = True @@ -300,52 +298,56 @@ def main(): selected_index = 0 charge = fg.state_of_charge() - need = " " - create_screen(selected_index, need, SPRITE_BASE, charge) - sleep_ms(1000) + # Idle phase + create_screen(selected_index, " ", SPRITE_BASE, charge) + sleep_ms(IDLE_DISPLAY_MS) + # Need phase need = random.choice(NEED) - if need == "I'm bored" : + if need == "I'm bored": sprite = SPRITE_SAD sound_effect("bored") - else : + else: sprite = SPRITE_HUNGRY sound_effect("hungry") create_screen(selected_index, need, sprite, charge) + # Response phase start = ticks_ms() win = None while True: - timer = ticks_diff(ticks_ms(), start) - if timer >= 5000: + elapsed = ticks_diff(ticks_ms(), start) + if elapsed >= RESPONSE_TIMEOUT_MS: break - button = wait_for_button() if button == "UP": - selected_index = (selected_index - 1)% len(ACTION) + selected_index = (selected_index - 1) % len(ACTION) create_screen(selected_index, need, sprite, charge) elif button == "DOWN": selected_index = (selected_index + 1) % len(ACTION) create_screen(selected_index, need, sprite, charge) elif button == "LEFT": - win = action_check(selected_index, need, win) + win = action_check(selected_index, need) break sleep_ms(20) + # Result phase if win: create_screen(selected_index, need, SPRITE_HAPPY, charge) sound_effect("success") else: - create_screen(selected_index, need, SPRITE_HANGRY, charge) + create_screen(selected_index, need, SPRITE_ANGRY, charge) sound_effect("fail") - sleep_ms(1000) + sleep_ms(RESULT_DISPLAY_MS) if charge < 10: is_alive = False create_game_over_screen() finally: buzzer_ch.pulse_width_percent(0) + + main()