#include #include #include #define SPACE_SIZE 20 #define BORDER_SIZE 4 #define WIDTH (SPACE_SIZE * 3 + BORDER_SIZE * 4) #define BG ((_pixel_t){.r = 0xd6, .g = 0xd6, .b = 0xd6}) #define FG ((_pixel_t){.r = 0x33, .g = 0x33, .b = 0x33}) #define XC ((_pixel_t){.r = 0x60, .g = 0x06, .b = 0x43}) #define OC ((_pixel_t){.r = 0x2c, .g = 0x77, .b = 0x30}) #define SL ((_pixel_t){.r = 0x9d, .g = 0x99, .b = 0xc2}) static const bool x_pic[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0, 0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0, 0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0, 0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0, 0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0, 0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0, 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const bool o_pic[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static const bool b_pic[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; typedef enum {B, X, O} trit; static const bool *pics[] = {b_pic, x_pic, o_pic}; static const _pixel_t colors[] = {FG, XC, OC}; static _window_handle_t w; static _pixel_t pbuf[WIDTH * WIDTH]; static trit board_state[9]; static uint8_t cursor; static trit playing_as; static uint8_t filled_squares; __attribute__ ((__pure__)) static bool is_win(uint8_t hint) { const uint8_t c = hint % 3; if ((board_state[c] == board_state[c + 3]) && (board_state[c] == board_state[c + 6])) return true; const uint8_t r = hint - c; if ((board_state[r] == board_state[r + 1]) && (board_state[r] == board_state[r + 2])) return true; return board_state[4] && ( ((board_state[0] == board_state[4]) && (board_state[0] == board_state[8])) || ((board_state[2] == board_state[4]) && (board_state[2] == board_state[6])) ); } static void draw_rect(uint8_t y, uint8_t x, uint8_t h, uint8_t w, _pixel_t color) { for (uint8_t yy = y; yy < y + h; ++yy) for (uint8_t xx = x; xx < x + w; ++xx) pbuf[yy * WIDTH + xx] = color; } static void draw_spot(uint8_t n) { const _pixel_t bg_c = n == cursor ? SL : BG; const _pixel_t fg_c = colors[board_state[n]]; const bool *const pic = pics[board_state[n]]; const uint8_t ys = BORDER_SIZE + (n / 3) * (BORDER_SIZE + SPACE_SIZE); const uint8_t xs = BORDER_SIZE + (n % 3) * (BORDER_SIZE + SPACE_SIZE); for (uint8_t y = 0; y < SPACE_SIZE; ++y) for (uint8_t x = 0; x < SPACE_SIZE; ++x) pbuf[(ys + y) * WIDTH + xs + x] = pic[y * SPACE_SIZE + x] ? fg_c : bg_c; } static void ai_turn(); static void reset_board() { cursor = 4; playing_as = gen_rand() % 2 + 1; filled_squares = 0; for (uint8_t i = 0; i < 9; ++i) { board_state[i] = B; draw_spot(i); } if (gen_rand() % 2) ai_turn(); } static uint32_t start_time; static void on_win() { struct popup p; info_popupf(&p, "You win! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); make_modal(&p); reset_board(); _paint_window(w); start_time = _get_timestamp(); } static void on_tie() { struct popup p; info_popupf(&p, "Tie! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); make_modal(&p); reset_board(); _paint_window(w); start_time = _get_timestamp(); } static void ai_turn() { //super easy mode uint8_t n; do n = gen_rand() % 9; while (board_state[n]); board_state[n] = playing_as == O ? X : O; draw_spot(n); _paint_window(w); if (is_win(n)) { struct popup p; info_popupf(&p, "You lose. Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); make_modal(&p); reset_board(); _paint_window(w); start_time = _get_timestamp(); } else if (++filled_squares == 9) on_tie(); } void main() { struct popup controls; info_popup(&controls, "Tic-Tac-Toe Controls:\n\n" "Arrow keys: move selection\n" "Spacebar: confirm selection\n" "Escape: quit\n\n" "Press escape to start.", FG, BG); make_modal(&controls); for (uint16_t i = 0; i < WIDTH * WIDTH; ++i) pbuf[i] = BG; draw_rect(SPACE_SIZE + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG); draw_rect(BORDER_SIZE, SPACE_SIZE + BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG); draw_rect(SPACE_SIZE * 2 + BORDER_SIZE * 2, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG); draw_rect(BORDER_SIZE, SPACE_SIZE * 2 + BORDER_SIZE * 2, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG); reset_board(); w = _new_window(WIDTH, WIDTH, pbuf); start_time = _get_timestamp(); while (1) { struct window_action wa; _get_win_action(w, &wa); if (!wa.action_type) { _wait_for_action(); _yield_task(); continue; } if (wa.action_type != KEY_DOWN) continue; switch (wa.as_key.key_id) { case KEY_UP_ARROW: if (cursor >= 3) { cursor -= 3; draw_spot(cursor + 3); draw_spot(cursor); _paint_window(w); } break; case KEY_DOWN_ARROW: if (cursor < 6) { cursor += 3; draw_spot(cursor - 3); draw_spot(cursor); _paint_window(w); } break; case KEY_LEFT_ARROW: if (cursor % 3) { --cursor; draw_spot(cursor + 1); draw_spot(cursor); _paint_window(w); } break; case KEY_RIGHT_ARROW: if (cursor % 3 != 2) { ++cursor; draw_spot(cursor - 1); draw_spot(cursor); _paint_window(w); } break; case KEY_ESCAPE: return; case KEY_SPACE: if (!board_state[cursor]) { board_state[cursor] = playing_as; draw_spot(cursor); _paint_window(w); if (is_win(cursor)) on_win(); else if (++filled_squares == 9) on_tie(); else ai_turn(); } break; default: break; } } }