|
@@ -1,416 +0,0 @@
|
|
|
-#include "ttt_multi_game_view.h"
|
|
|
|
|
-
|
|
|
|
|
-struct TttMultiGameView {
|
|
|
|
|
- View* view;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-typedef struct {
|
|
|
|
|
- TttMultiGame* game;
|
|
|
|
|
- uint8_t position_x;
|
|
|
|
|
- uint8_t position_y;
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGamePlayer local_player;
|
|
|
|
|
- bool is_local;
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGameViewCallback callback;
|
|
|
|
|
- void* context;
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGameMove* last_move;
|
|
|
|
|
- TttMultiGameResult result;
|
|
|
|
|
-} TttMultiGameViewModel;
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_draw_callback(Canvas* canvas, void* _model) {
|
|
|
|
|
- TttMultiGameViewModel* model = _model;
|
|
|
|
|
-
|
|
|
|
|
- canvas_clear(canvas);
|
|
|
|
|
- const uint8_t top = 2;
|
|
|
|
|
- const uint8_t left = 4;
|
|
|
|
|
- const uint8_t cell_size = 20;
|
|
|
|
|
- const uint8_t padding = 4;
|
|
|
|
|
-
|
|
|
|
|
- canvas_draw_frame(canvas, left - 1, top - 1, 3 * cell_size + 2, 3 * cell_size + 2);
|
|
|
|
|
-
|
|
|
|
|
- for(uint8_t i = 0; i < 3; i++) {
|
|
|
|
|
- for(uint8_t j = 0; j < 3; j++) {
|
|
|
|
|
- canvas_draw_frame(
|
|
|
|
|
- canvas, left + i * cell_size, top + j * cell_size, cell_size, cell_size);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for(uint8_t i = 0; i < 3; i++) {
|
|
|
|
|
- for(uint8_t j = 0; j < 3; j++) {
|
|
|
|
|
- bool is_selected = model->position_x == i && model->position_y == j &&
|
|
|
|
|
- ttt_multi_game_get_state(model->game) != TttMultiGameStateFinished;
|
|
|
|
|
-
|
|
|
|
|
- if(ttt_multi_game_player_at(model->game, i, j) == TttMultiGamePlayerX) {
|
|
|
|
|
- canvas_draw_line(
|
|
|
|
|
- canvas,
|
|
|
|
|
- left + i * cell_size + padding,
|
|
|
|
|
- top + j * cell_size + padding,
|
|
|
|
|
- left + i * cell_size + cell_size - padding,
|
|
|
|
|
- top + j * cell_size + cell_size - padding);
|
|
|
|
|
- canvas_draw_line(
|
|
|
|
|
- canvas,
|
|
|
|
|
- left + i * cell_size + cell_size - padding,
|
|
|
|
|
- top + j * cell_size + padding,
|
|
|
|
|
- left + i * cell_size + padding,
|
|
|
|
|
- top + j * cell_size + cell_size - padding);
|
|
|
|
|
- } else if(ttt_multi_game_player_at(model->game, i, j) == TttMultiGamePlayerO) {
|
|
|
|
|
- canvas_draw_circle(
|
|
|
|
|
- canvas,
|
|
|
|
|
- left + i * cell_size + cell_size / 2,
|
|
|
|
|
- top + j * cell_size + cell_size / 2,
|
|
|
|
|
- cell_size / 2 - padding);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(is_selected) {
|
|
|
|
|
- canvas_draw_frame(
|
|
|
|
|
- canvas,
|
|
|
|
|
- left + i * cell_size + 1,
|
|
|
|
|
- top + j * cell_size + 1,
|
|
|
|
|
- cell_size - 2,
|
|
|
|
|
- cell_size - 2);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- char* status_str = "";
|
|
|
|
|
- // TODO: Rewrite this
|
|
|
|
|
- if(model->is_local) {
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateFinished) {
|
|
|
|
|
- if(ttt_multi_game_get_result(model->game) == TttMultiGameResultXWin) {
|
|
|
|
|
- status_str = "X win";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultOWin) {
|
|
|
|
|
- status_str = "O win";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultDraw) {
|
|
|
|
|
- status_str = "Draw";
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if(ttt_multi_game_current_player(model->game) == TttMultiGamePlayerX) {
|
|
|
|
|
- status_str = "X turn";
|
|
|
|
|
- } else {
|
|
|
|
|
- status_str = "O turn";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateFinished) {
|
|
|
|
|
- if(model->local_player == TttMultiGamePlayerX) {
|
|
|
|
|
- if(ttt_multi_game_get_result(model->game) == TttMultiGameResultXWin) {
|
|
|
|
|
- status_str = "You win";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultOWin) {
|
|
|
|
|
- status_str = "You lose";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultDraw) {
|
|
|
|
|
- status_str = "Draw";
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if(ttt_multi_game_get_result(model->game) == TttMultiGameResultXWin) {
|
|
|
|
|
- status_str = "You lose";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultOWin) {
|
|
|
|
|
- status_str = "You win";
|
|
|
|
|
- } else if(ttt_multi_game_get_result(model->game) == TttMultiGameResultDraw) {
|
|
|
|
|
- status_str = "Draw";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if(model->local_player == TttMultiGamePlayerX) {
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateTurnX) {
|
|
|
|
|
- status_str = "Your turn";
|
|
|
|
|
- } else {
|
|
|
|
|
- status_str = "Opponent turn";
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateTurnO) {
|
|
|
|
|
- status_str = "Your turn";
|
|
|
|
|
- } else {
|
|
|
|
|
- status_str = "Opponent turn";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- elements_text_box(canvas, 64, 16, 64, 16, AlignCenter, AlignCenter, status_str, false);
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateFinished) {
|
|
|
|
|
- elements_multiline_text_aligned(
|
|
|
|
|
- canvas, 100, 32, AlignCenter, AlignTop, "Press OK\nto restart");
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-static void ttt_multi_game_view_process_left(TttMultiGameView* view);
|
|
|
|
|
-static void ttt_multi_game_view_process_right(TttMultiGameView* view);
|
|
|
|
|
-static void ttt_multi_game_view_process_up(TttMultiGameView* view);
|
|
|
|
|
-static void ttt_multi_game_view_process_down(TttMultiGameView* view);
|
|
|
|
|
-static void ttt_multi_game_view_process_ok(TttMultiGameView* view);
|
|
|
|
|
-
|
|
|
|
|
-static bool ttt_multi_game_view_input_callback(InputEvent* event, void* context) {
|
|
|
|
|
- furi_assert(context);
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGameView* game_view = context;
|
|
|
|
|
- bool consumed = false;
|
|
|
|
|
-
|
|
|
|
|
- if(event->type == InputTypeShort) {
|
|
|
|
|
- switch(event->key) {
|
|
|
|
|
- case InputKeyLeft:
|
|
|
|
|
- ttt_multi_game_view_process_left(game_view);
|
|
|
|
|
- consumed = true;
|
|
|
|
|
- break;
|
|
|
|
|
- case InputKeyRight:
|
|
|
|
|
- ttt_multi_game_view_process_right(game_view);
|
|
|
|
|
- consumed = true;
|
|
|
|
|
- break;
|
|
|
|
|
- case InputKeyUp:
|
|
|
|
|
- ttt_multi_game_view_process_up(game_view);
|
|
|
|
|
- consumed = true;
|
|
|
|
|
- break;
|
|
|
|
|
- case InputKeyDown:
|
|
|
|
|
- ttt_multi_game_view_process_down(game_view);
|
|
|
|
|
- consumed = true;
|
|
|
|
|
- break;
|
|
|
|
|
- case InputKeyOk:
|
|
|
|
|
- ttt_multi_game_view_process_ok(game_view);
|
|
|
|
|
- consumed = true;
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return consumed;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_model_reset(TttMultiGameViewModel* model) {
|
|
|
|
|
- furi_assert(model);
|
|
|
|
|
- furi_assert(model->game);
|
|
|
|
|
-
|
|
|
|
|
- model->position_x = 1;
|
|
|
|
|
- model->position_y = 1;
|
|
|
|
|
- ttt_multi_game_reset(model->game);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-TttMultiGameView* ttt_multi_game_view_alloc() {
|
|
|
|
|
- TttMultiGameView* game_view = malloc(sizeof(TttMultiGameView));
|
|
|
|
|
- game_view->view = view_alloc();
|
|
|
|
|
- view_set_context(game_view->view, game_view);
|
|
|
|
|
- view_allocate_model(game_view->view, ViewModelTypeLocking, sizeof(TttMultiGameViewModel));
|
|
|
|
|
- view_set_draw_callback(game_view->view, (ViewDrawCallback)ttt_multi_game_view_draw_callback);
|
|
|
|
|
- view_set_input_callback(game_view->view, ttt_multi_game_view_input_callback);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- model->game = ttt_multi_game_alloc();
|
|
|
|
|
- model->last_move = ttt_multi_game_move_alloc();
|
|
|
|
|
- ttt_multi_game_view_model_reset(model);
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-
|
|
|
|
|
- return game_view;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_free(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- ttt_multi_game_free(model->game);
|
|
|
|
|
- ttt_multi_game_move_free(model->last_move);
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-
|
|
|
|
|
- view_free(game_view->view);
|
|
|
|
|
- free(game_view);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-View* ttt_multi_game_get_view(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- return game_view->view;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_process_up(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(model->position_y > 0) {
|
|
|
|
|
- model->position_y--;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_process_down(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(model->position_y < 2) {
|
|
|
|
|
- model->position_y++;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_process_left(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(model->position_x > 0) {
|
|
|
|
|
- model->position_x--;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_process_right(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(model->position_x < 2) {
|
|
|
|
|
- model->position_x++;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_process_ok(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
- TttMultiGameViewCallback callback = NULL;
|
|
|
|
|
- void* context = NULL;
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(ttt_multi_game_get_state(model->game) == TttMultiGameStateFinished) {
|
|
|
|
|
- ttt_multi_game_view_model_reset(model);
|
|
|
|
|
- } else {
|
|
|
|
|
- model->last_move->player = ttt_multi_game_current_player(model->game);
|
|
|
|
|
- model->last_move->x = model->position_x;
|
|
|
|
|
- model->last_move->y = model->position_y;
|
|
|
|
|
-
|
|
|
|
|
- if(ttt_multi_game_is_move_valid(model->game, model->last_move)) {
|
|
|
|
|
- callback = model->callback;
|
|
|
|
|
- context = model->context;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-
|
|
|
|
|
- if(callback) {
|
|
|
|
|
- callback(context, TttMultiCustomEventGameMove);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_move(TttMultiGameView* game_view, TttMultiGameMove* move) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
- furi_assert(move);
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGameResult result;
|
|
|
|
|
- TttMultiGameViewCallback callback = NULL;
|
|
|
|
|
- void* context = NULL;
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- ttt_multi_game_make_move(model->game, move);
|
|
|
|
|
- result = ttt_multi_game_get_result(model->game);
|
|
|
|
|
- if(result != TttMultiGameResultNone) {
|
|
|
|
|
- callback = model->callback;
|
|
|
|
|
- context = model->context;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-
|
|
|
|
|
- if(callback) {
|
|
|
|
|
- callback(context, TttMultiCustomEventGameFinish);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_set_callback(
|
|
|
|
|
- TttMultiGameView* game_view,
|
|
|
|
|
- TttMultiGameViewCallback callback,
|
|
|
|
|
- void* context) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- model->callback = callback;
|
|
|
|
|
- model->context = context;
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_set_remote_play(TttMultiGameView* game_view, TttMultiGamePlayer player) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- model->local_player = player;
|
|
|
|
|
- model->is_local = false;
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_set_local_play(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view, TttMultiGameViewModel * model, { model->is_local = true; }, true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_get_last_move(TttMultiGameView* game_view, TttMultiGameMove* move) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
- furi_assert(move);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- {
|
|
|
|
|
- if(model->last_move->player != TttMultiGamePlayerNone) {
|
|
|
|
|
- ttt_multi_game_move_copy(move, model->last_move);
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-TttMultiGameResult ttt_multi_game_view_get_result(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- TttMultiGameResult result = TttMultiGameResultNone;
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- { result = ttt_multi_game_get_result(model->game); },
|
|
|
|
|
- true);
|
|
|
|
|
-
|
|
|
|
|
- return result;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void ttt_multi_game_view_reset(TttMultiGameView* game_view) {
|
|
|
|
|
- furi_assert(game_view);
|
|
|
|
|
-
|
|
|
|
|
- with_view_model(
|
|
|
|
|
- game_view->view,
|
|
|
|
|
- TttMultiGameViewModel * model,
|
|
|
|
|
- { ttt_multi_game_view_model_reset(model); },
|
|
|
|
|
- true);
|
|
|
|
|
-}
|
|
|