From b69004db7b1489e44d9ef1c64ff6d3da4a51b16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 16 Sep 2017 23:58:43 +0200 Subject: [PATCH] improved the randomizer --- CMakeLists.txt | 2 +- Makefile | 1 + README.md | 11 ++++--- display.h | 24 +++++++++++++++ game.c | 79 +++++++++++++++++--------------------------------- game.h | 9 ++++++ leds.h | 8 +++++ main.c | 2 +- rng.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++ rng.h | 16 ++++++++++ 10 files changed, 167 insertions(+), 59 deletions(-) create mode 100644 rng.c create mode 100644 rng.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 33c5c95..cf9c217 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ set(SOURCE_FILES leds.c leds.h game.c - game.h) + game.h rng.c rng.h) include_directories(lib /usr/avr/include/) diff --git a/Makefile b/Makefile index d66f101..8b1b0db 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ OBJS += lib/color.o OBJS += display.o OBJS += game.o OBJS += leds.o +OBJS += rng.o # Dirs with header files INCL_DIRS = . lib/ diff --git a/README.md b/README.md index 046d3bd..6ef5ef7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# Simon Says with Pro Mini +# Simon game with Pro Mini -Fun little project that has grown quite more than expected, at least on the hardware side. +Fun little project that has grown quite more than expected, at least on the +hardware side. -There will be a proper log for this later, with schematics etc. +There will be a proper log for this later, with schematics etc. +(update, 3 months later: or maybe not) -For now, you can have a peek and thank heavens you don't have to understand any of it xD +For now, you can have a peek and thank heavens you don't have to understand +any of it xD diff --git a/display.h b/display.h index cb64c41..a15ce80 100644 --- a/display.h +++ b/display.h @@ -7,6 +7,15 @@ #include +// AAA +// F B +// F B +// GGG +// E C +// E C +// DDD H + +// individual segments #define SEG_A _BV(0) #define SEG_B _BV(1) #define SEG_C _BV(2) @@ -16,6 +25,7 @@ #define SEG_G _BV(6) #define SEG_H _BV(7) +// composed digits #define DIGIT_0 (SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F) #define DIGIT_1 (SEG_B|SEG_C) #define DIGIT_2 (SEG_A|SEG_B|SEG_D|SEG_E|SEG_G) @@ -30,8 +40,22 @@ extern const uint8_t disp_digits[10]; extern volatile uint8_t disp_brightness; // place to globally store display brightness +/** + * Send raw digits to the display + * @param dig0 - segments of the left digit + * @param dig1 - segments of the right digit + */ void display_show(uint8_t dig0, uint8_t dig1); + +/** + * Show a number 0-99 on the display + * @param num - number to show + */ void display_show_number(uint8_t num); + +/** + * Init the PWM timer with automatic adjust from ADC level + */ void setup_pwm(void); #endif //FIRMWARE_DISPLAY_H diff --git a/game.c b/game.c index ffdec0b..89044be 100644 --- a/game.c +++ b/game.c @@ -10,11 +10,13 @@ #include #include #include +#include #include "lib/color.h" #include "leds.h" #include "lib/timebase.h" #include "display.h" #include "pinout.h" +#include "rng.h" //region Colors @@ -72,13 +74,6 @@ const uint32_t dimwhite[4] = {C_DIMWHITE, C_DIMWHITE, C_DIMWHITE, C_DIMWHITE}; #define SUC_EFF_TIME 500 #define FAIL_EFF_TIME 1000 -/** Sequence of colors to show. Seed is constant thorough a game. - * rng_state is used by rand_r() for building the sequence. */ -uint32_t game_seed; -unsigned long game_rng_state; -uint8_t last_item; -uint8_t repeat_count; - /** Nr of revealed colors in sequence */ uint8_t game_revealed_n; /** Nr of next color to replay/input */ @@ -94,36 +89,6 @@ void show_screen() leds_set(screen); } -/** Prepare rng sequence for replay / test */ -void reset_sequence() -{ - game_rng_state = game_seed; - last_item = 99; - repeat_count = 0; -} - -/** Get next item in the sequence */ -uint8_t get_next_item() -{ - uint8_t item; - while (1) { - item = (uint8_t) rand_r(&game_rng_state) & 0x03; - if (item == last_item) { - repeat_count++; - if (repeat_count < 2) { - goto suc; - } - } else { - last_item = item; - repeat_count = 0; - goto suc; - } - } - -suc: - return item; -} - /** Enter state - callback for delayed state change */ void deferred_enter_state(void *state) { @@ -144,7 +109,7 @@ void replay_callback(void *onOff) screen[3] = C_DARK; if (on) { - uint8_t color = get_next_item(); + uint8_t color = rng_next_item(); game_replay_n++; screen[color] = brt[color]; show_screen(); @@ -208,6 +173,7 @@ void enter_state(enum GameState_enum state) switch (state) { case STATE_NEW_GAME: + usart_puts("State: new game\r\n"); // new game - idle state before new game is started // all dimly lit @@ -215,28 +181,32 @@ void enter_state(enum GameState_enum state) break; case STATE_REPLAY: + usart_puts("State: replay\r\n"); game_replay_n = 0; - reset_sequence(); + rng_restart(); // Start replay replay_callback((void *) 1); break; case STATE_USER_INPUT: + usart_puts("State: repeat\r\n"); memcpy(screen, dim, sizeof(screen)); // Start entering & checking game_repeat_n = 0; - reset_sequence(); + rng_restart(); break; case STATE_SUCCESS_EFFECT: + usart_puts("State: succ\r\n"); memcpy(screen, dim, sizeof(screen)); //suc_eff_callback((void *) 1); schedule_task(suc_eff_callback, (void *) 1, 250, false); break; case STATE_FAIL_EFFECT: + usart_puts("State: fail\r\n"); memcpy(screen, dim, sizeof(screen)); //fail_eff_callback((void *) 1); schedule_task(fail_eff_callback, (void *) 1, 250, false); @@ -249,15 +219,13 @@ void enter_state(enum GameState_enum state) /** Prepare new sequence, using time for seed. */ void prepare_sequence() { - game_seed = time_ms; - game_rng_state = game_seed; - last_item = 99; - repeat_count = 0; + rng_set_seed(time_ms); + rng_restart(); } volatile uint16_t idle_cnt = 0; -/** Main function, called from MX-generated main.c */ +/** game main function */ void game_main(void) { display_show(SEG_G, SEG_G); // two dashes... @@ -268,13 +236,13 @@ void game_main(void) while (1) { if (GameState == last_state) { if (GameState == STATE_NEW_GAME) { - if (idle_cnt == 20 && !holding_new_game_button) { - // clear after 2 secs + if (idle_cnt == 25 && !holding_new_game_button) { + usart_puts("clear highscore display\r\n"); display_show(SEG_G, SEG_G); } if (idle_cnt == 3000) { - // Shut down after 5 mins + usart_puts("automatic shutdown\r\n"); screen[0] = C_CRIMSON; screen[1] = C_CRIMSON; screen[2] = C_CRIMSON; @@ -285,8 +253,9 @@ void game_main(void) while(1); // wait for shutdown } } else { - if (idle_cnt > 150) {// 15 secs = stop game. + if (idle_cnt > 200) { // reset state + usart_puts("game reset, user walked away\r\n"); enter_state(STATE_NEW_GAME); show_screen(); display_show(SEG_G, SEG_G); @@ -316,12 +285,14 @@ void game_button_handler(uint8_t button, bool press) switch (GameState) { case STATE_NEW_GAME: if (press) { + usart_puts("pressed a new-game button\r\n"); // feedback display_show_number(0); // show 0 holding_new_game_button = true; } if (!press) { // released + usart_puts("game begins\r\n"); // user wants to start playing prepare_sequence(); game_revealed_n = 1; // start with 1 revealed @@ -336,6 +307,7 @@ void game_button_handler(uint8_t button, bool press) //enter_state(STATE_REPLAY); } break; + case STATE_USER_INPUT: // Reset idle counter, so it doesn't cut off in the middle of input idle_cnt = 0; @@ -349,16 +321,17 @@ void game_button_handler(uint8_t button, bool press) } else { // Button is released // Verify correctness - uint8_t expected = get_next_item(); + uint8_t expected = rng_next_item(); if (expected == button) { - // good! + usart_puts("good key!\r\n"); game_repeat_n++; if (game_repeat_n == game_revealed_n) { - // repeated all, good work! + usart_puts("repeated all, good work!\r\n"); game_revealed_n++; enter_state(STATE_SUCCESS_EFFECT); } } else { + usart_puts("oops bad key\r\n"); enter_state(STATE_FAIL_EFFECT); } } @@ -367,7 +340,7 @@ void game_button_handler(uint8_t button, bool press) break; default: - // discard button press, not expecting input now + usart_puts("discard button press, not expecting input now\r\n"); break; } } diff --git a/game.h b/game.h index 3c349ba..5a3faf7 100644 --- a/game.h +++ b/game.h @@ -8,8 +8,17 @@ #include #include +/** + * Game entry point + */ void game_main(void); +/** + * Button press handler + * + * @param button + * @param press + */ void game_button_handler(uint8_t button, bool press); #endif //FIRMWARE_GAME_H diff --git a/leds.h b/leds.h index 9234281..e5e39b9 100644 --- a/leds.h +++ b/leds.h @@ -7,8 +7,16 @@ #include +/** + * Set led colors + * + * @param new_leds - array of 4 ints for the 4 leds + */ void leds_set(const uint32_t *new_leds); +/** + * Send the set colors to the neopixels + */ void leds_show(void); #endif //FIRMWARE_LEDS_H diff --git a/main.c b/main.c index 0d6c459..c4489ea 100644 --- a/main.c +++ b/main.c @@ -96,7 +96,7 @@ void task_check_shutdown_btn(void *unused) { if (debo_get_pin(0) // 0 - first && !booting - && (time_ms - time_pwr_pressed > 1000)) { + && (time_ms - time_pwr_pressed > 250)) { cli(); ws_no_cli_sei = true; diff --git a/rng.c b/rng.c new file mode 100644 index 0000000..5b79e68 --- /dev/null +++ b/rng.c @@ -0,0 +1,74 @@ +// +// Created by MightyPork on 2017/09/16. +// + +#include "rng.h" + +#include +#include + +/** Sequence of colors to show. Seed is constant thorough a game. + * rng_state is used by rand_r() for building the sequence. */ +static uint32_t game_seed; +static unsigned long game_rng_state; +static uint8_t last_item; +static uint8_t repeat_count; + +#define NUM_CNT 4 +static uint16_t weights[NUM_CNT]; + +void rng_set_seed(uint32_t seed) +{ + game_seed = seed; +} + +void rng_restart(void) +{ + game_rng_state = game_seed; + repeat_count = 0; + last_item = 99; + for (uint8_t i = 0; i < 4; i++) { + weights[i] = 1; + } +} + +static uint8_t pick_do(void) +{ + uint16_t total = 0; + for (uint8_t i = 0; i < 4; i++) { + total += weights[i]; + } + uint16_t rn = rand_r(&game_rng_state) % total; + + for (uint8_t i = 0; i < 4; i++) { + if (rn < weights[i]) { + // got our number + for (uint8_t j = 0; j < 4; j++) { + if (i == j) { + weights[j]/=2; + } + else weights[j]+=4; + } + + return i; + } + rn -= weights[i]; + } + return 0; // this never happens but keeps the compiler happy +} + +uint8_t rng_next_item(void) +{ + uint8_t item; + while (1) { + item = pick_do(); + if (item == last_item) { + repeat_count++; + if (repeat_count < 2) return item; + } else { + last_item = item; + repeat_count = 0; + return item; + } + } +} diff --git a/rng.h b/rng.h new file mode 100644 index 0000000..4646ab3 --- /dev/null +++ b/rng.h @@ -0,0 +1,16 @@ +// +// Created by MightyPork on 2017/09/16. +// + +#ifndef FIRMWARE_RNG_H +#define FIRMWARE_RNG_H + +#include + +void rng_set_seed(uint32_t seed); + +void rng_restart(void); + +uint8_t rng_next_item(void); + +#endif //FIRMWARE_RNG_H