functional memory ganme!!!

pull/1/head
Ondřej Hruška 9 years ago
parent c3201fe3aa
commit c96cdbe66d
  1. 4
      devel/lib/colors.h
  2. 300
      devel/memorygame/main.c

@ -35,8 +35,8 @@ typedef uint8_t rgb6_t;
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24c(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)

@ -20,30 +20,35 @@
#define BOARD_WIDTH 6
#define BOARD_HEIGHT 5
#define BOARD_LEN (BOARD_WIDTH * BOARD_HEIGHT)
#define TILE_COUNT (BOARD_LEN / 2)
// number of cards
#define CARD_COUNT (BOARD_WIDTH * BOARD_HEIGHT)
// number of pairs
#define PAIR_COUNT (CARD_COUNT / 2)
// color palette
const xrgb_t COLORS[] = {
rgb24_xrgbc(0xB14835), // brick red
rgb24_xrgbc(0x4C1661), // indigo
rgb24_xrgbc(0xA3268E), // royal purple
rgb24_xrgbc(0x009ADA), // cobalt blue
rgb24_xrgbc(0x007D8F), // teal
rgb24_xrgbc(0x002E5A), // navy blue
rgb24_xrgbc(0x56BCC1), // turquoise
rgb24_xrgbc(0x01654D), // emerald dark
rgb24_xrgbc(0xF5864F), // papaya orange
rgb24_xrgbc(0x00FF99), // emerald
rgb24_xrgbc(0x00CCCC), // cyan
rgb24_xrgbc(0x0000CC), // full blue
rgb24_xrgbc(0xFF6D55), // salmon?
rgb24_xrgbc(0x4400FF), // blue-purple
rgb24_xrgbc(0xFF00FF), // magenta
rgb24_xrgbc(0xD70053), // wine
rgb24_xrgbc(0xFF0000), // red
rgb24_xrgbc(0xCD2B64), // brick
rgb24_xrgbc(0xED1B24), // firetruck red
rgb24_xrgbc(0xFDAF17), // tangerine orange
rgb24_xrgbc(0xF58F83), // coral
rgb24_xrgbc(0xED008C), // magenta
rgb24_xrgbc(0xFEF200), // sunshine yellow
rgb24_xrgbc(0x6D9346), // treetop green
rgb24_xrgbc(0xFF6D00), // tangerine yellow/orange
rgb24_xrgbc(0xFF2B00), // orange
rgb24_xrgbc(0xFFFF00), // yellow
rgb24_xrgbc(0x5FBA00), // yellow-green
rgb24_xrgbc(0x0BEE00), // green
};
// assert valid board size
#if BOARD_LEN % 2 == 1
#if CARD_COUNT % 2 == 1
# error "Board size is not even!"
#endif
@ -72,6 +77,7 @@ const xrgb_t COLORS[] = {
// Prototypes
void render();
void update();
void deal_cards();
void SECTION(".init8") init()
@ -104,25 +110,12 @@ void SECTION(".init8") init()
OCR0A = 156; // interrupt every 10 ms
sbi(TIMSK0, OCIE0A);
deal_cards();
sei();
}
/** timer 0 interrupt vector */
ISR(TIMER0_COMPA_vect)
{
//debo_tick(); // poll debouncer
update(); // update game state
render();
}
void main()
{
while(1); // Timer does everything
}
/** Tile state enum */
typedef enum {
@ -140,46 +133,255 @@ typedef struct {
// board tiles
tile_t board[BOARD_LEN];
tile_t board[CARD_COUNT];
void deal_cards()
{
// clear the board
for (uint8_t i = 0; i < CARD_COUNT; ++i) {
board[i] = (tile_t) { .color = 0, .state = GONE };
}
// for all pair_COUNT
for (uint8_t i = 0; i < PAIR_COUNT; ++i) {
// for both cards in pair
for (uint8_t j = 0; j < 2; j++) {
// loop until empty slot is found
while(1) {
uint8_t pos = rand() % CARD_COUNT;
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;
uint8_t noise = 0;
uint8_t xxx = 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];
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;
break;
case D_DOWN:
if (cursor >= (CARD_COUNT - BOARD_WIDTH)) // last row
cursor -= (CARD_COUNT - BOARD_WIDTH);
else
cursor += BOARD_WIDTH;
break;
case D_LEFT:
if (cursor > 0) // last row
cursor--;
else
cursor = (CARD_COUNT - 1);
break;
case D_RIGHT:
if (cursor < (CARD_COUNT - 1)) // last row
cursor++;
else
cursor = 0;
break;
case D_SELECT:
if (tiles_revealed == 2) break; // two already shown
if (board[cursor].state != SECRET) break; // selected tile not secret
// reveal a tile
if (tiles_revealed < 2) {
board[cursor].state = REVEALED;
tiles_revealed++;
if(tiles_revealed == 1) {
tile1 = cursor;
} else {
tile2 = cursor;
}
}
// Check equality if it's the second
if (tiles_revealed == 2) {
hide_timeout_match = (board[tile1].color == board[tile2].color);
hide_timeout = HIDE_TIME;
}
/** Update game */
break;
case D_RESTART:
deal_cards();
break;
}
}
/** Press arrow key, skip empty tiles */
void safe_press_arrow_key(uint8_t n)
{
// attempt to arrive at some secret tile
for (uint8_t j = 0; j < BOARD_HEIGHT; j++) {
for (uint8_t k = 0; k < BOARD_WIDTH; k++) {
button_click(n);
if (board[cursor].state != GONE) break;
}
if (board[cursor].state != GONE) break;
// traverse right since current column is empty
//
button_click(D_RIGHT);
}
}
#define is_arrow_key(id) ((id) == D_LEFT || (id) == D_RIGHT || (id) == D_UP || (id) == D_DOWN)
/** Update game (every 10 ms) */
void update()
{
if(xxx++ >= 10) {
noise = rand();
xxx = 0;
// handle buttons (repeating)
for (uint8_t i = 0; i < DEBO_CHANNELS; i++) {
if (debo_get_pin(i)) {
if (btn_hold_cnt[i] == 0) {
if (is_arrow_key(i)) {
safe_press_arrow_key(i);
} else {
button_click(i);
}
}
// non-arrows wrap to 1 -> do not generate repeated clicks
inc_wrap(btn_hold_cnt[i], is_arrow_key(i) ? 1 : 0, BTNHOLD_REPEAT);
} else {
btn_hold_cnt[i] = 0;
}
}
// handle game logic
if (hide_timeout > 0) {
if (--hide_timeout == 0) {
if (hide_timeout_match) {
// Tiles removed from board
board[tile1].state = GONE;
board[tile2].state = GONE;
if (board[cursor].state == GONE) {
// move to some other tile
// try not to change row if possible
if ((cursor % BOARD_WIDTH) == (BOARD_WIDTH-1))
safe_press_arrow_key(D_LEFT);
else
safe_press_arrow_key(D_RIGHT);
}
} else {
// Tiles made secret again
board[tile1].state = SECRET;
board[tile2].state = SECRET;
}
tiles_revealed = 0; // no revealed
}
}
inc_wrap(animframe, 0, F_ANIM_LEN * 2);
}
// LED off
#define BLACK rgb24_xrgb(0x000000)
// LED on - secret tile
#define WHITE rgb24_xrgb(0x555555)
// colors to be displayed
rgb24_t screen[BOARD_LEN];
xrgb_t screen[CARD_COUNT];
/** Update screen[] and send to display */
void render()
{
#define BLUE 0x005397
#define RED 0xFF0000
#define YELLOW 0xFFFF00
#define BLACK 0x000000
for (uint8_t i = 0; i < BOARD_LEN; i++) {
if (i < 8) {
screen[i] = get_bit(noise, i) ? RED : BLUE;
for (uint8_t i = 0; i < CARD_COUNT; i++) {
switch (board[i].state) {
case SECRET:
screen[i] = WHITE;
break;
case REVEALED:
screen[i] = COLORS[board[i].color];
break;
default:
case GONE:
screen[i] = BLACK;
break;
}
if (i == cursor) {
// flashy animation state
uint16_t mult;
if (animframe < F_ANIM_LEN) {
mult = animframe;
} else {
screen[i] = YELLOW;
mult = (F_ANIM_LEN * 2) - animframe;
}
screen[i] = (xrgb_t) {
.r = (uint8_t) ((((uint16_t) screen[i].r) * mult) / F_ANIM_LEN),
.g = (uint8_t) ((((uint16_t) screen[i].g) * mult) / F_ANIM_LEN),
.b = (uint8_t) ((((uint16_t) screen[i].b) * mult) / F_ANIM_LEN),
};
}
}
// debo_get_pin(BTN_LEFT_D) ? PINK : BLACK;
ws_send_rgb24_array(WS1, screen, BOARD_LEN);
ws_send_xrgb_array(WS1, screen, CARD_COUNT);
ws_show();
}
void main()
{
while(1); // Timer does everything
}

Loading…
Cancel
Save