<commit_before>#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#include "lib/meta.h"
#include "lib/arduino_pins.h"
#include "lib/calc.h"
#include "lib/colors.h"
#include "lib/ws2812.h"
#include "lib/adc.h"

#define DEBO_CHANNELS 6
#define DEBO_TICKS 1  // in 0.01s

#include "lib/debounce.h"


// #define BOARD_WIDTH 6
// #define BOARD_HEIGHT 5
#define BOARD_WIDTH 6
#define BOARD_HEIGHT 5

// number of cards
#define CARD_COUNT (BOARD_WIDTH * BOARD_HEIGHT)

// number of pairs
#define PAIR_COUNT (CARD_COUNT / 2)

// when the "small" pin is DOWN, only this many cards are dealt - on the same board size
#define CARD_COUNT_SMALL 18

// color palette
const xrgb_t COLORS[] = {
	rgb24_xrgbc(0x00FF99), // emerald
	rgb24_xrgbc(0x0000CC), // full blue
	rgb24_xrgbc(0xFF00FF), // magenta
	rgb24_xrgbc(0xFF0000), // red
	rgb24_xrgbc(0xFF2B00), // orange
	rgb24_xrgbc(0xFFFF00), // yellow
	rgb24_xrgbc(0x0BEE00), // green
	rgb24_xrgbc(0xFF6D00), // tangerine yellow/orange
	rgb24_xrgbc(0x00CCCC), // cyan
	rgb24_xrgbc(0x4400FF), // blue-purple
	rgb24_xrgbc(0x5FBA00), // yellow-green
	rgb24_xrgbc(0xD70053), // wine
	rgb24_xrgbc(0xCD2B64), // brick
	rgb24_xrgbc(0xED1B24), // firetruck red
	rgb24_xrgbc(0xFF6D55), // salmon?
};


// assert valid board size
#if CARD_COUNT % 2 == 1
# error "Board size is not even!"
#endif


// Pin assignments (see pins.h)

// RGB LED strip data line
#define WS1   D10

// Buttons (to ground)
#define BTN_LEFT     D2
#define BTN_RIGHT    D3
#define BTN_UP       D4
#define BTN_DOWN     D5
#define BTN_SELECT   D6
#define BTN_RESTART  D7

// connect this pin to ground to get smaller board size (for kids ^^)
#define FLAG_SMALL   D12

// Debouncer channels for buttons
// (Must be added in this order to debouncer)
#define D_LEFT      0
#define D_RIGHT     1
#define D_UP        2
#define D_DOWN      3
#define D_SELECT    4
#define D_RESTART   5

// [ IMPORTANT ]
// Pin A0 must not be connected, it is used to get
// entropy for the random number generator


// Prototypes
void render();
void update();
void deal_cards();


/** Program initialization */
void SECTION(".init8") init()
{
	// Randomize RNG
	adc_init();
	srand(adc_read_word(0));

	// led strip data
	as_output(WS1);

	// gamepad buttons
	as_input_pu(BTN_LEFT);
	as_input_pu(BTN_RIGHT);
	as_input_pu(BTN_UP);
	as_input_pu(BTN_DOWN);
	as_input_pu(BTN_SELECT);
	as_input_pu(BTN_RESTART);

	as_input_pu(FLAG_SMALL); // when LOW, use smaller board.

	// add buttons to debouncer
	debo_add_rev(BTN_LEFT);
	debo_add_rev(BTN_RIGHT);
	debo_add_rev(BTN_UP);
	debo_add_rev(BTN_DOWN);
	debo_add_rev(BTN_SELECT);
	debo_add_rev(BTN_RESTART);

	// setup timer
	TCCR0A = _BV(WGM01); // CTC
	TCCR0B = _BV(CS02) | _BV(CS00);  // prescaler 1024
	OCR0A = 156;  // interrupt every 10 ms
	sbi(TIMSK0, OCIE0A);

	// prepare game board
	deal_cards();

	// enable timer interrupts (update & render)
	sei();
}



/** Tile state enum */
typedef enum {
	SECRET,
	REVEALED,
	GONE
} tilestate_t;


/** Tile struct */
typedef struct {
	uint8_t color;  // color index from COLORS[]
	tilestate_t state;  // state of the tile (used for render)
} tile_t;


// board tiles
tile_t board[CARD_COUNT];


/** Randomly place pairs of cards on the board */
void deal_cards()
{
	// clear the board
	for (uint8_t i = 0; i < CARD_COUNT; ++i) {
		board[i] = (tile_t) { .color = 0, .state = GONE };
	}

	const uint8_t dealt_cards = get_pin(FLAG_SMALL) ? CARD_COUNT : CARD_COUNT_SMALL;

	// for all pair_COUNT
	for (uint8_t i = 0; i < (dealt_cards / 2); ++i) {
		// for both cards in pair
		for (uint8_t j = 0; j < 2; j++) {
			// loop until empty slot is found
			while(1) {
				const uint8_t pos = rand() % dealt_cards;

				if (board[pos].state == GONE) {
					board[pos] = (tile_t) { .color = i, .state = SECRET };
					break;
				}
			}
		}
	}
}


/** timer 0 interrupt vector */
ISR(TIMER0_COMPA_vect)
{
	debo_tick();  // poll debouncer
	update();  // update game state
	render();
}


// player cursor position
uint8_t cursor = 0;
uint8_t animframe = 0;

bool hide_timeout_match;
uint8_t hide_timeout = 0;

// Game state
uint8_t tiles_revealed = 0;
uint8_t tile1;
uint8_t tile2;

// length of pulse animation (in 10ms)
#define F_ANIM_LEN 20
#define HIDE_TIME 100

// length of button holding before it's repeated (in 10ms)
#define BTNHOLD_REPEAT 15

uint8_t btn_hold_cnt[DEBO_CHANNELS];


/** Handle a button press event */
void button_click(uint8_t n)
{
	switch (n) {
		case D_UP:
			if (cursor < BOARD_WIDTH)  // first row
				cursor += (CARD_COUNT - BOARD_WIDTH);
			else
				cursor -= BOARD_WIDTH;<commit_msg>slightly slowed memogame btn walk speed<commit_after>#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#include "lib/meta.h"
#include "lib/arduino_pins.h"
#include "lib/calc.h"
#include "lib/colors.h"
#include "lib/ws2812.h"
#include "lib/adc.h"

#define DEBO_CHANNELS 6
#define DEBO_TICKS 1  // in 0.01s

#include "lib/debounce.h"


// #define BOARD_WIDTH 6
// #define BOARD_HEIGHT 5
#define BOARD_WIDTH 6
#define BOARD_HEIGHT 5

// number of cards
#define CARD_COUNT (BOARD_WIDTH * BOARD_HEIGHT)

// number of pairs
#define PAIR_COUNT (CARD_COUNT / 2)

// when the "small" pin is DOWN, only this many cards are dealt - on the same board size
#define CARD_COUNT_SMALL 12

// color palette
const xrgb_t COLORS[] = {
	rgb24_xrgbc(0x00FF99), // emerald
	rgb24_xrgbc(0x0000CC), // full blue
	rgb24_xrgbc(0xFF00FF), // magenta
	rgb24_xrgbc(0xFF0000), // red
	rgb24_xrgbc(0xFF2B00), // orange
	rgb24_xrgbc(0xFFFF00), // yellow
	rgb24_xrgbc(0x0BEE00), // green
	rgb24_xrgbc(0xFF6D00), // tangerine yellow/orange
	rgb24_xrgbc(0x00CCCC), // cyan
	rgb24_xrgbc(0x4400FF), // blue-purple
	rgb24_xrgbc(0x5FBA00), // yellow-green
	rgb24_xrgbc(0xD70053), // wine
	rgb24_xrgbc(0xCD2B64), // brick
	rgb24_xrgbc(0xED1B24), // firetruck red
	rgb24_xrgbc(0xFF6D55), // salmon?
};


// assert valid board size
#if CARD_COUNT % 2 == 1
# error "Board size is not even!"
#endif


// Pin assignments (see pins.h)

// RGB LED strip data line
#define WS1   D10

// Buttons (to ground)
#define BTN_LEFT     D2
#define BTN_RIGHT    D3
#define BTN_UP       D4
#define BTN_DOWN     D5
#define BTN_SELECT   D6
#define BTN_RESTART  D7

// connect this pin to ground to get smaller board size (for kids ^^)
#define FLAG_SMALL   D12

// Debouncer channels for buttons
// (Must be added in this order to debouncer)
#define D_LEFT      0
#define D_RIGHT     1
#define D_UP        2
#define D_DOWN      3
#define D_SELECT    4
#define D_RESTART   5

// [ IMPORTANT ]
// Pin A0 must not be connected, it is used to get
// entropy for the random number generator


// Prototypes
void render();
void update();
void deal_cards();


/** Program initialization */
void SECTION(".init8") init()
{
	// Randomize RNG
	adc_init();
	srand(adc_read_word(0));

	// led strip data
	as_output(WS1);

	// gamepad buttons
	as_input_pu(BTN_LEFT);
	as_input_pu(BTN_RIGHT);
	as_input_pu(BTN_UP);
	as_input_pu(BTN_DOWN);
	as_input_pu(BTN_SELECT);
	as_input_pu(BTN_RESTART);

	as_input_pu(FLAG_SMALL); // when LOW, use smaller board.

	// add buttons to debouncer
	debo_add_rev(BTN_LEFT);
	debo_add_rev(BTN_RIGHT);
	debo_add_rev(BTN_UP);
	debo_add_rev(BTN_DOWN);
	debo_add_rev(BTN_SELECT);
	debo_add_rev(BTN_RESTART);

	// setup timer
	TCCR0A = _BV(WGM01); // CTC
	TCCR0B = _BV(CS02) | _BV(CS00);  // prescaler 1024
	OCR0A = 156;  // interrupt every 10 ms
	sbi(TIMSK0, OCIE0A);

	// prepare game board
	deal_cards();

	// enable timer interrupts (update & render)
	sei();
}



/** Tile state enum */
typedef enum {
	SECRET,
	REVEALED,
	GONE
} tilestate_t;


/** Tile struct */
typedef struct {
	uint8_t color;  // color index from COLORS[]
	tilestate_t state;  // state of the tile (used for render)
} tile_t;


// board tiles
tile_t board[CARD_COUNT];


/** Randomly place pairs of cards on the board */
void deal_cards()
{
	// clear the board
	for (uint8_t i = 0; i < CARD_COUNT; ++i) {
		board[i] = (tile_t) { .color = 0, .state = GONE };
	}

	const uint8_t dealt_cards = get_pin(FLAG_SMALL) ? CARD_COUNT : CARD_COUNT_SMALL;

	// for all pair_COUNT
	for (uint8_t i = 0; i < (dealt_cards / 2); ++i) {
		// for both cards in pair
		for (uint8_t j = 0; j < 2; j++) {
			// loop until empty slot is found
			while(1) {
				const uint8_t pos = rand() % dealt_cards;

				if (board[pos].state == GONE) {
					board[pos] = (tile_t) { .color = i, .state = SECRET };
					break;
				}
			}
		}
	}
}


/** timer 0 interrupt vector */
ISR(TIMER0_COMPA_vect)
{
	debo_tick();  // poll debouncer
	update();  // update game state
	render();
}


// player cursor position
uint8_t cursor = 0;
uint8_t animframe = 0;

bool hide_timeout_match;
uint8_t hide_timeout = 0;

// Game state
uint8_t tiles_revealed = 0;
uint8_t tile1;
uint8_t tile2;

// length of pulse animation (in 10ms)
#define F_ANIM_LEN 20
#define HIDE_TIME 100

// length of button holding before it's repeated (in 10ms)
#define BTNHOLD_REPEAT 20

uint8_t btn_hold_cnt[DEBO_CHANNELS];


/** Handle a button press event */
void button_click(uint8_t n)
{
	switch (n) {
		case D_UP:
			if (cursor < BOARD_WIDTH)  // first row
				cursor += (CARD_COUNT - BOARD_WIDTH);
			else
				cursor -= BOARD_WIDTH;
{'fraction_non_alphanumeric': 0.1240343347639485, 'fraction_numerical': 0.041201716738197426, 'mean_word_length': 3.520368574199806, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3202405', 'n_tokens_mistral': 4122, 'n_tokens_neox': 3761, 'n_words': 996}