mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-11 06:09:08 -07:00
727 lines
23 KiB
C
727 lines
23 KiB
C
#include "../flipchess.h"
|
|
#include <furi.h>
|
|
// #include <furi_hal.h>
|
|
// #include <furi_hal_random.h>
|
|
#include <input/input.h>
|
|
#include <gui/elements.h>
|
|
//#include <dolphin/dolphin.h>
|
|
#include <string.h>
|
|
//#include "flipchess_icons.h"
|
|
#include "../helpers/flipchess_voice.h"
|
|
#include "../helpers/flipchess_haptic.h"
|
|
|
|
#define SCL_960_CASTLING 0 // setting to 1 compiles a 960 version of smolchess
|
|
#define XBOARD_DEBUG 0 // will create files with xboard communication
|
|
#define SCL_EVALUATION_FUNCTION SCL_boardEvaluateStatic
|
|
#define SCL_DEBUG_AI 0
|
|
|
|
#include "../chess/smallchesslib.h"
|
|
|
|
#define ENABLE_960 0 // setting to 1 enables 960 chess
|
|
#define MAX_TEXT_LEN 15 // 15 = max length of text
|
|
#define MAX_TEXT_BUF (MAX_TEXT_LEN + 1) // max length of text + null terminator
|
|
#define THREAD_WAIT_TIME 20 // time to wait for draw thread to finish
|
|
|
|
struct FlipChessScene1 {
|
|
View* view;
|
|
FlipChessScene1Callback callback;
|
|
void* context;
|
|
};
|
|
typedef struct {
|
|
uint8_t paramPlayerW;
|
|
uint8_t paramPlayerB;
|
|
|
|
uint8_t paramAnalyze; // depth of analysis
|
|
uint8_t paramMoves;
|
|
uint8_t paramInfo;
|
|
uint8_t paramFlipBoard;
|
|
uint8_t paramExit;
|
|
uint16_t paramStep;
|
|
char* paramFEN;
|
|
char* paramPGN;
|
|
|
|
int clockSeconds;
|
|
SCL_Game game;
|
|
SCL_Board startState;
|
|
|
|
#if ENABLE_960
|
|
int16_t random960PosNumber;
|
|
#endif
|
|
|
|
//uint8_t picture[SCL_BOARD_PICTURE_WIDTH * SCL_BOARD_PICTURE_WIDTH];
|
|
uint8_t squareSelected;
|
|
uint8_t squareSelectedLast;
|
|
|
|
char* msg;
|
|
char* msg2;
|
|
char* msg3;
|
|
char moveString[MAX_TEXT_BUF];
|
|
char moveString2[MAX_TEXT_BUF];
|
|
char moveString3[MAX_TEXT_BUF];
|
|
uint8_t thinking;
|
|
|
|
SCL_SquareSet moveHighlight;
|
|
uint8_t squareFrom;
|
|
uint8_t squareTo;
|
|
uint8_t turnState;
|
|
|
|
} FlipChessScene1Model;
|
|
|
|
static uint8_t picture[SCL_BOARD_PICTURE_WIDTH * SCL_BOARD_PICTURE_WIDTH];
|
|
|
|
void flipchess_putImagePixel(uint8_t pixel, uint16_t index) {
|
|
picture[index] = pixel;
|
|
}
|
|
|
|
uint8_t flipchess_stringsEqual(const char* s1, const char* s2, int max) {
|
|
for(int i = 0; i < max; ++i) {
|
|
if(*s1 != *s2) return 0;
|
|
|
|
if(*s1 == 0) return 1;
|
|
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int16_t flipchess_makeAIMove(
|
|
SCL_Board board,
|
|
uint8_t* s0,
|
|
uint8_t* s1,
|
|
char* prom,
|
|
FlipChessScene1Model* model) {
|
|
uint8_t level = SCL_boardWhitesTurn(board) ? model->paramPlayerW : model->paramPlayerB;
|
|
uint8_t depth = (level > 0) ? level : 1;
|
|
uint8_t extraDepth = 3;
|
|
uint8_t endgameDepth = 1;
|
|
uint8_t randomness =
|
|
model->game.ply < 2 ? 1 : 0; /* in first moves increase randomness for different
|
|
openings */
|
|
uint8_t rs0, rs1;
|
|
|
|
SCL_gameGetRepetiotionMove(&(model->game), &rs0, &rs1);
|
|
|
|
if(model->clockSeconds >= 0) // when using clock, choose AI params accordingly
|
|
{
|
|
if(model->clockSeconds <= 5) {
|
|
depth = 1;
|
|
extraDepth = 2;
|
|
endgameDepth = 0;
|
|
} else if(model->clockSeconds < 15) {
|
|
depth = 2;
|
|
extraDepth = 2;
|
|
} else if(model->clockSeconds < 100) {
|
|
depth = 2;
|
|
} else if(model->clockSeconds < 5 * 60) {
|
|
depth = 3;
|
|
} else {
|
|
depth = 3;
|
|
extraDepth = 4;
|
|
}
|
|
}
|
|
|
|
return SCL_getAIMove(
|
|
board,
|
|
depth,
|
|
extraDepth,
|
|
endgameDepth,
|
|
SCL_boardEvaluateStatic,
|
|
SCL_randomBetter,
|
|
randomness,
|
|
rs0,
|
|
rs1,
|
|
s0,
|
|
s1,
|
|
prom);
|
|
}
|
|
|
|
bool flipchess_isPlayerTurn(FlipChessScene1Model* model) {
|
|
return (SCL_boardWhitesTurn(model->game.board) && model->paramPlayerW == 0) ||
|
|
(!SCL_boardWhitesTurn(model->game.board) && model->paramPlayerB == 0);
|
|
}
|
|
|
|
void flipchess_shiftMessages(FlipChessScene1Model* model) {
|
|
// shift messages
|
|
model->msg3 = model->msg2;
|
|
model->msg2 = model->msg;
|
|
strncpy(model->moveString3, model->moveString2, MAX_TEXT_LEN);
|
|
strncpy(model->moveString2, model->moveString, MAX_TEXT_LEN);
|
|
}
|
|
|
|
void flipchess_drawBoard(FlipChessScene1Model* model) {
|
|
// draw chess board
|
|
SCL_drawBoard(
|
|
model->game.board,
|
|
flipchess_putImagePixel,
|
|
model->squareSelected,
|
|
model->moveHighlight,
|
|
model->paramFlipBoard);
|
|
}
|
|
|
|
uint8_t flipchess_saveState(FlipChess* app, FlipChessScene1Model* model) {
|
|
for(uint8_t i = 0; i < SCL_FEN_MAX_LENGTH; i++) {
|
|
app->import_game_text[i] = '\0';
|
|
}
|
|
const uint8_t res = SCL_boardToFEN(model->game.board, app->import_game_text);
|
|
if(res > 0) {
|
|
app->import_game = 1;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
uint8_t flipchess_turn(FlipChessScene1Model* model) {
|
|
// 0: none, 1: player, 2: AI, 3: undo
|
|
uint8_t moveType = FlipChessStatusNone;
|
|
|
|
// if(model->paramInfo) {
|
|
|
|
// if(model->random960PosNumber >= 0)
|
|
// printf("960 random position number: %d\n", model->random960PosNumber);
|
|
|
|
// printf("ply number: %d\n", model->game.ply);
|
|
|
|
// int16_t eval = SCL_boardEvaluateStatic(model->game.board);
|
|
// printf(
|
|
// "board static evaluation: %lf (%d)\n",
|
|
// ((double)eval) / ((double)SCL_VALUE_PAWN),
|
|
// eval);
|
|
// printf("board hash: %u\n", SCL_boardHash32(model->game.board));
|
|
// printf("phase: ");
|
|
|
|
// switch(SCL_boardEstimatePhase(model->game.board)) {
|
|
// case SCL_PHASE_OPENING:
|
|
// puts("opening");
|
|
// break;
|
|
// case SCL_PHASE_ENDGAME:
|
|
// puts("endgame");
|
|
// break;
|
|
// default:
|
|
// puts("midgame");
|
|
// break;
|
|
// }
|
|
|
|
// printf(
|
|
// "en passant: %d\n",
|
|
// ((model->game.board[SCL_BOARD_ENPASSANT_CASTLE_BYTE] & 0x0f) + 1) % 16);
|
|
// printf(
|
|
// "50 move rule count: %d\n", model->game.board[SCL_BOARD_MOVE_COUNT_BYTE]);
|
|
|
|
// if(model->paramFEN == NULL && model->paramPGN == NULL) {
|
|
// printf("PGN: ");
|
|
// SCL_printPGN(model->game.record, putCharacter, startState);
|
|
// putchar('\n');
|
|
// }
|
|
// }
|
|
|
|
if(model->game.state != SCL_GAME_STATE_PLAYING) {
|
|
model->paramExit = FlipChessStatusNone;
|
|
|
|
} else {
|
|
char movePromote = 'q';
|
|
|
|
if(flipchess_isPlayerTurn(model)) {
|
|
// if(stringsEqual(string, "undo", 5))
|
|
// moveType = FlipChessStatusMoveUndo;
|
|
// else if(stringsEqual(string, "quit", 5))
|
|
// break;
|
|
|
|
if(model->turnState == 0 && model->squareSelected != 255) {
|
|
model->squareFrom = model->squareSelected;
|
|
model->turnState = 1;
|
|
} else if(model->turnState == 1 && model->squareSelected != 255) {
|
|
model->squareTo = model->squareSelected;
|
|
model->turnState = 2;
|
|
model->squareSelectedLast = model->squareSelected;
|
|
//model->squareSelected = 255;
|
|
}
|
|
|
|
if(model->turnState == 1 && model->squareFrom != 255) {
|
|
if((model->game.board[model->squareFrom] != '.') &&
|
|
(SCL_pieceIsWhite(model->game.board[model->squareFrom]) ==
|
|
SCL_boardWhitesTurn(model->game.board))) {
|
|
SCL_boardGetMoves(model->game.board, model->squareFrom, model->moveHighlight);
|
|
}
|
|
} else if(model->turnState == 2) {
|
|
if(SCL_squareSetContains(model->moveHighlight, model->squareTo)) {
|
|
moveType = FlipChessStatusMovePlayer;
|
|
}
|
|
model->turnState = 0;
|
|
SCL_squareSetClear(model->moveHighlight);
|
|
}
|
|
|
|
} else {
|
|
model->squareSelected = 255;
|
|
flipchess_makeAIMove(
|
|
model->game.board, &(model->squareFrom), &(model->squareTo), &movePromote, model);
|
|
moveType = FlipChessStatusMoveAI;
|
|
model->turnState = 0;
|
|
}
|
|
|
|
if(moveType == FlipChessStatusMovePlayer || moveType == FlipChessStatusMoveAI) {
|
|
flipchess_shiftMessages(model);
|
|
|
|
SCL_moveToString(
|
|
model->game.board,
|
|
model->squareFrom,
|
|
model->squareTo,
|
|
movePromote,
|
|
model->moveString);
|
|
|
|
SCL_gameMakeMove(&(model->game), model->squareFrom, model->squareTo, movePromote);
|
|
|
|
SCL_squareSetClear(model->moveHighlight);
|
|
SCL_squareSetAdd(model->moveHighlight, model->squareFrom);
|
|
SCL_squareSetAdd(model->moveHighlight, model->squareTo);
|
|
} else if(moveType == FlipChessStatusMoveUndo) {
|
|
flipchess_shiftMessages(model);
|
|
|
|
if(model->paramPlayerW != 0 || model->paramPlayerB != 0)
|
|
SCL_gameUndoMove(&(model->game));
|
|
|
|
SCL_gameUndoMove(&(model->game));
|
|
SCL_squareSetClear(model->moveHighlight);
|
|
}
|
|
|
|
switch(model->game.state) {
|
|
case SCL_GAME_STATE_WHITE_WIN:
|
|
model->msg = "white wins";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_BLACK_WIN:
|
|
model->msg = "black wins";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_DRAW_STALEMATE:
|
|
model->msg = "stalemate";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_DRAW_REPETITION:
|
|
model->msg = "draw-repetition";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_DRAW_DEAD:
|
|
model->msg = "draw-dead pos.";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_DRAW:
|
|
model->msg = "draw";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
case SCL_GAME_STATE_DRAW_50:
|
|
model->msg = "draw-50 moves";
|
|
model->paramExit = FlipChessStatusReturn;
|
|
break;
|
|
|
|
default:
|
|
if(model->game.ply > 0) {
|
|
const uint8_t whitesTurn = SCL_boardWhitesTurn(model->game.board);
|
|
|
|
if(SCL_boardCheck(model->game.board, whitesTurn)) {
|
|
model->msg = (whitesTurn ? "black: check!" : "white: check!");
|
|
} else {
|
|
model->msg = (whitesTurn ? "black played" : "white played");
|
|
}
|
|
|
|
uint8_t s0, s1;
|
|
char p;
|
|
|
|
SCL_recordGetMove(model->game.record, model->game.ply - 1, &s0, &s1, &p);
|
|
SCL_moveToString(model->game.board, s0, s1, p, model->moveString);
|
|
}
|
|
break;
|
|
model->paramExit = moveType;
|
|
}
|
|
}
|
|
|
|
model->thinking = 0;
|
|
return model->paramExit;
|
|
}
|
|
|
|
void flipchess_scene_1_set_callback(
|
|
FlipChessScene1* instance,
|
|
FlipChessScene1Callback callback,
|
|
void* context) {
|
|
furi_assert(instance);
|
|
furi_assert(callback);
|
|
instance->callback = callback;
|
|
instance->context = context;
|
|
}
|
|
|
|
void flipchess_scene_1_draw(Canvas* canvas, FlipChessScene1Model* model) {
|
|
//UNUSED(model);
|
|
canvas_clear(canvas);
|
|
canvas_set_color(canvas, ColorBlack);
|
|
|
|
//canvas_draw_icon(canvas, 0, 0, &I_FLIPR_128x64);
|
|
|
|
// Frame
|
|
canvas_draw_frame(canvas, 0, 0, 66, 64);
|
|
|
|
// Message
|
|
canvas_set_font(canvas, FontSecondary);
|
|
if(model->thinking) {
|
|
canvas_draw_str(canvas, 68, 10, "thinking...");
|
|
} else {
|
|
canvas_draw_str(canvas, 68, 10, model->msg);
|
|
}
|
|
canvas_draw_str(canvas, 68, 19, model->moveString);
|
|
canvas_draw_str(canvas, 68, 31, model->msg2);
|
|
canvas_draw_str(canvas, 68, 40, model->moveString2);
|
|
canvas_draw_str(canvas, 68, 52, model->msg3);
|
|
canvas_draw_str(canvas, 68, 61, model->moveString3);
|
|
|
|
// Board
|
|
for(uint16_t y = 0; y < SCL_BOARD_PICTURE_WIDTH; y++) {
|
|
for(uint16_t x = 0; x < SCL_BOARD_PICTURE_WIDTH; x++) {
|
|
if(!picture[x + (y * SCL_BOARD_PICTURE_WIDTH)]) {
|
|
canvas_draw_dot(canvas, x + 1, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int flipchess_scene_1_model_init(
|
|
FlipChessScene1Model* const model,
|
|
const int white_mode,
|
|
const int black_mode,
|
|
char* import_game_text) {
|
|
model->paramPlayerW = white_mode;
|
|
model->paramPlayerB = black_mode;
|
|
|
|
model->paramAnalyze = 255; // depth of analysis
|
|
model->paramMoves = 0;
|
|
model->paramInfo = 1;
|
|
model->paramFlipBoard = 0;
|
|
model->paramExit = FlipChessStatusNone;
|
|
model->paramStep = 0;
|
|
model->paramFEN = import_game_text;
|
|
model->paramPGN = NULL;
|
|
model->clockSeconds = -1;
|
|
|
|
SCL_Board emptyStartState = SCL_BOARD_START_STATE;
|
|
memcpy(model->startState, &emptyStartState, sizeof(SCL_Board));
|
|
|
|
#if ENABLE_960
|
|
model->random960PosNumber = -1;
|
|
#endif
|
|
|
|
model->squareSelected = 255;
|
|
model->squareSelectedLast = 28; // start selector near middle
|
|
|
|
model->msg = "init";
|
|
model->moveString[0] = '\0';
|
|
model->msg2 = "";
|
|
model->moveString2[0] = '\0';
|
|
model->msg3 = "";
|
|
model->moveString3[0] = '\0';
|
|
model->thinking = 0;
|
|
|
|
SCL_SquareSet emptySquareSet = SCL_SQUARE_SET_EMPTY;
|
|
memcpy(model->moveHighlight, &emptySquareSet, sizeof(SCL_SquareSet));
|
|
model->squareFrom = 255;
|
|
model->squareTo = 255;
|
|
model->turnState = 0;
|
|
|
|
SCL_randomBetterSeed(furi_hal_random_get());
|
|
|
|
#if ENABLE_960
|
|
#if SCL_960_CASTLING
|
|
if(model->random960PosNumber < 0) model->random960PosNumber = SCL_randomBetter();
|
|
#endif
|
|
if(model->random960PosNumber >= 0) model->random960PosNumber %= 960;
|
|
#endif
|
|
|
|
if(model->paramFEN != NULL)
|
|
SCL_boardFromFEN(model->startState, model->paramFEN);
|
|
else if(model->paramPGN != NULL) {
|
|
SCL_Record record;
|
|
SCL_recordFromPGN(record, model->paramPGN);
|
|
SCL_boardInit(model->startState);
|
|
SCL_recordApply(record, model->startState, model->paramStep);
|
|
}
|
|
|
|
#if ENABLE_960
|
|
#if SCL_960_CASTLING
|
|
else
|
|
SCL_boardInit960(model->startState, model->random960PosNumber);
|
|
#endif
|
|
#endif
|
|
|
|
SCL_gameInit(&(model->game), model->startState);
|
|
|
|
if(model->paramAnalyze != 255) {
|
|
char p;
|
|
uint8_t move[] = {0, 0};
|
|
|
|
model->paramPlayerW = model->paramAnalyze;
|
|
model->paramPlayerB = model->paramAnalyze;
|
|
|
|
int16_t evaluation =
|
|
flipchess_makeAIMove(model->game.board, &(move[0]), &(move[1]), &p, model);
|
|
|
|
if(model->paramAnalyze == 0) evaluation = SCL_boardEvaluateStatic(model->game.board);
|
|
|
|
char moveStr[5];
|
|
moveStr[4] = 0;
|
|
|
|
SCL_squareToString(move[0], moveStr);
|
|
SCL_squareToString(move[1], moveStr + 2);
|
|
|
|
//printf("%lf (%d)\n", ((double)evaluation) / ((double)SCL_VALUE_PAWN), evaluation);
|
|
//puts(moveStr);
|
|
|
|
return evaluation;
|
|
}
|
|
|
|
if(model->paramMoves) {
|
|
char string[256];
|
|
|
|
for(int i = 0; i < 64; ++i)
|
|
if(model->game.board[i] != '.' &&
|
|
SCL_pieceIsWhite(model->game.board[i]) == SCL_boardWhitesTurn(model->game.board)) {
|
|
SCL_SquareSet possibleMoves = SCL_SQUARE_SET_EMPTY;
|
|
|
|
SCL_boardGetMoves(model->game.board, i, possibleMoves);
|
|
|
|
SCL_SQUARE_SET_ITERATE_BEGIN(possibleMoves)
|
|
SCL_moveToString(model->game.board, i, iteratedSquare, 'q', string);
|
|
//printf("%s ", string);
|
|
SCL_SQUARE_SET_ITERATE_END
|
|
}
|
|
|
|
return FlipChessStatusReturn;
|
|
}
|
|
|
|
model->msg = (SCL_boardWhitesTurn(model->game.board) ? "white to move" : "black to move");
|
|
|
|
// 0 = success
|
|
return FlipChessStatusNone;
|
|
}
|
|
|
|
bool flipchess_scene_1_input(InputEvent* event, void* context) {
|
|
furi_assert(context);
|
|
FlipChessScene1* instance = context;
|
|
FlipChess* app = instance->context;
|
|
|
|
if(event->type == InputTypeRelease) {
|
|
switch(event->key) {
|
|
case InputKeyBack:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(model->turnState == 1) {
|
|
model->turnState = 0;
|
|
SCL_squareSetClear(model->moveHighlight);
|
|
flipchess_drawBoard(model);
|
|
} else {
|
|
instance->callback(FlipChessCustomEventScene1Back, instance->context);
|
|
}
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyRight:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(model->squareSelectedLast != 255 && model->squareSelected == 255) {
|
|
model->squareSelected = model->squareSelectedLast;
|
|
} else {
|
|
model->squareSelected = (model->squareSelected + 1) % 64;
|
|
}
|
|
flipchess_drawBoard(model);
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyDown:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(model->squareSelectedLast != 255 && model->squareSelected == 255) {
|
|
model->squareSelected = model->squareSelectedLast;
|
|
} else {
|
|
model->squareSelected = (model->squareSelected + 56) % 64;
|
|
}
|
|
flipchess_drawBoard(model);
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyLeft:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(model->squareSelectedLast != 255 && model->squareSelected == 255) {
|
|
model->squareSelected = model->squareSelectedLast;
|
|
} else {
|
|
model->squareSelected = (model->squareSelected + 63) % 64;
|
|
}
|
|
flipchess_drawBoard(model);
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyUp:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(model->squareSelectedLast != 255 && model->squareSelected == 255) {
|
|
model->squareSelected = model->squareSelectedLast;
|
|
} else {
|
|
model->squareSelected = (model->squareSelected + 8) % 64;
|
|
}
|
|
flipchess_drawBoard(model);
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyOk:
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
// if(model->paramExit == FlipChessStatusReturn) {
|
|
// instance->callback(FlipChessCustomEventScene1Back, instance->context);
|
|
// break;
|
|
// }
|
|
if(!flipchess_isPlayerTurn(model)) {
|
|
model->thinking = 1;
|
|
}
|
|
},
|
|
true);
|
|
furi_thread_flags_wait(0, FuriFlagWaitAny, THREAD_WAIT_TIME);
|
|
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
// first turn of round, probably player but could be AI
|
|
if(flipchess_turn(model) == FlipChessStatusReturn) {
|
|
if(app->sound == 1) flipchess_voice_a_strange_game();
|
|
flipchess_play_long_bump(app);
|
|
}
|
|
flipchess_saveState(app, model);
|
|
flipchess_drawBoard(model);
|
|
},
|
|
true);
|
|
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
if(!flipchess_isPlayerTurn(model)) {
|
|
model->thinking = 1;
|
|
}
|
|
},
|
|
true);
|
|
furi_thread_flags_wait(0, FuriFlagWaitAny, THREAD_WAIT_TIME);
|
|
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
// if player played, let AI play
|
|
if(!flipchess_isPlayerTurn(model)) {
|
|
if(flipchess_turn(model) == FlipChessStatusReturn) {
|
|
if(app->sound == 1) flipchess_voice_a_strange_game();
|
|
flipchess_play_long_bump(app);
|
|
}
|
|
flipchess_saveState(app, model);
|
|
flipchess_drawBoard(model);
|
|
}
|
|
},
|
|
true);
|
|
break;
|
|
case InputKeyMAX:
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void flipchess_scene_1_exit(void* context) {
|
|
furi_assert(context);
|
|
FlipChessScene1* instance = (FlipChessScene1*)context;
|
|
|
|
with_view_model(
|
|
instance->view, FlipChessScene1Model * model, { model->paramExit = 0; }, true);
|
|
}
|
|
|
|
void flipchess_scene_1_enter(void* context) {
|
|
furi_assert(context);
|
|
FlipChessScene1* instance = (FlipChessScene1*)context;
|
|
FlipChess* app = instance->context;
|
|
|
|
flipchess_play_happy_bump(app);
|
|
|
|
with_view_model(
|
|
instance->view,
|
|
FlipChessScene1Model * model,
|
|
{
|
|
// load imported game if applicable
|
|
char* import_game_text = NULL;
|
|
if(app->import_game == 1 && strlen(app->import_game_text) > 0) {
|
|
import_game_text = app->import_game_text;
|
|
} else {
|
|
if(app->sound == 1) flipchess_voice_how_about_chess();
|
|
}
|
|
|
|
int init = flipchess_scene_1_model_init(
|
|
model, app->white_mode, app->black_mode, import_game_text);
|
|
|
|
if(init == FlipChessStatusNone) {
|
|
// perform initial turn, sets up and lets white
|
|
// AI play if applicable
|
|
const uint8_t turn = flipchess_turn(model);
|
|
if(turn == FlipChessStatusReturn) {
|
|
init = turn;
|
|
} else {
|
|
flipchess_saveState(app, model);
|
|
flipchess_drawBoard(model);
|
|
}
|
|
}
|
|
|
|
// if return status, return from scene immediately
|
|
// if(init == FlipChessStatusReturn) {
|
|
// instance->callback(FlipChessCustomEventScene1Back, instance->context);
|
|
// }
|
|
},
|
|
true);
|
|
}
|
|
|
|
FlipChessScene1* flipchess_scene_1_alloc() {
|
|
FlipChessScene1* instance = malloc(sizeof(FlipChessScene1));
|
|
instance->view = view_alloc();
|
|
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(FlipChessScene1Model));
|
|
view_set_context(instance->view, instance); // furi_assert crashes in events without this
|
|
view_set_draw_callback(instance->view, (ViewDrawCallback)flipchess_scene_1_draw);
|
|
view_set_input_callback(instance->view, flipchess_scene_1_input);
|
|
view_set_enter_callback(instance->view, flipchess_scene_1_enter);
|
|
view_set_exit_callback(instance->view, flipchess_scene_1_exit);
|
|
|
|
return instance;
|
|
}
|
|
|
|
void flipchess_scene_1_free(FlipChessScene1* instance) {
|
|
furi_assert(instance);
|
|
|
|
with_view_model(
|
|
instance->view, FlipChessScene1Model * model, { UNUSED(model); }, true);
|
|
|
|
view_free(instance->view);
|
|
free(instance);
|
|
}
|
|
|
|
View* flipchess_scene_1_get_view(FlipChessScene1* instance) {
|
|
furi_assert(instance);
|
|
return instance->view;
|
|
} |