Chess v1.8 (#355)

This commit is contained in:
WillyJL
2023-08-13 03:20:44 +02:00
committed by GitHub
28 changed files with 11161 additions and 0 deletions

21
applications/external/chess/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Struan Clark
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,19 @@
App(
appid="chess",
name="Chess",
apptype=FlipperAppType.EXTERNAL,
entry_point="flipchess_app",
requires=[
"gui",
],
stack_size=4 * 1024,
order=10,
fap_icon="flipchess_10px.png",
fap_icon_assets="icons",
fap_icon_assets_symbol="flipchess",
fap_category="Games",
fap_author="Struan Clark (xtruan)",
fap_weburl="https://github.com/xtruan/flipper-chess",
fap_version=(1, 8),
fap_description="Chess for Flipper",
)

File diff suppressed because it is too large Load Diff

179
applications/external/chess/flipchess.c vendored Normal file
View File

@@ -0,0 +1,179 @@
#include "flipchess.h"
#include "helpers/flipchess_haptic.h"
bool flipchess_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
FlipChess* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
void flipchess_tick_event_callback(void* context) {
furi_assert(context);
FlipChess* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
//leave app if back button pressed
bool flipchess_navigation_event_callback(void* context) {
furi_assert(context);
FlipChess* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void text_input_callback(void* context) {
furi_assert(context);
FlipChess* app = context;
bool handled = false;
// check that there is text in the input
if(strlen(app->input_text) > 0) {
if(app->input_state == FlipChessTextInputGame) {
if(app->import_game == 1) {
strncpy(app->import_game_text, app->input_text, TEXT_SIZE);
uint8_t status = FlipChessStatusNone;
if(status == FlipChessStatusNone) {
//notification_message(app->notification, &sequence_blink_cyan_100);
flipchess_play_happy_bump(app);
} else {
//notification_message(app->notification, &sequence_blink_red_100);
flipchess_play_long_bump(app);
}
}
// reset input state
app->input_state = FlipChessTextInputDefault;
handled = true;
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdMenu);
}
}
if(!handled) {
// reset input state
app->input_state = FlipChessTextInputDefault;
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdMenu);
}
}
FlipChess* flipchess_app_alloc() {
FlipChess* app = malloc(sizeof(FlipChess));
app->gui = furi_record_open(RECORD_GUI);
app->notification = furi_record_open(RECORD_NOTIFICATION);
//Turn backlight on, believe me this makes testing your app easier
notification_message(app->notification, &sequence_display_backlight_on);
//Scene additions
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
app->scene_manager = scene_manager_alloc(&flipchess_scene_handlers, app);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, flipchess_navigation_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, flipchess_tick_event_callback, 100);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, flipchess_custom_event_callback);
app->submenu = submenu_alloc();
// Settings
app->haptic = FlipChessHapticOn;
app->white_mode = FlipChessPlayerHuman;
app->black_mode = FlipChessPlayerAI1;
// Startscreen
app->sound = 0;
// Main menu
app->import_game = 0;
// Text input
app->input_state = FlipChessTextInputDefault;
view_dispatcher_add_view(
app->view_dispatcher, FlipChessViewIdMenu, submenu_get_view(app->submenu));
app->flipchess_startscreen = flipchess_startscreen_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
FlipChessViewIdStartscreen,
flipchess_startscreen_get_view(app->flipchess_startscreen));
app->flipchess_scene_1 = flipchess_scene_1_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
FlipChessViewIdScene1,
flipchess_scene_1_get_view(app->flipchess_scene_1));
app->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
FlipChessViewIdSettings,
variable_item_list_get_view(app->variable_item_list));
app->text_input = text_input_alloc();
text_input_set_result_callback(
app->text_input,
text_input_callback,
(void*)app,
app->input_text,
TEXT_BUFFER_SIZE,
//clear default text
true);
text_input_set_header_text(app->text_input, "Input");
view_dispatcher_add_view(
app->view_dispatcher, FlipChessViewIdTextInput, text_input_get_view(app->text_input));
//End Scene Additions
return app;
}
void flipchess_app_free(FlipChess* app) {
furi_assert(app);
// Scene manager
scene_manager_free(app->scene_manager);
text_input_free(app->text_input);
// View Dispatcher
view_dispatcher_remove_view(app->view_dispatcher, FlipChessViewIdMenu);
view_dispatcher_remove_view(app->view_dispatcher, FlipChessViewIdScene1);
view_dispatcher_remove_view(app->view_dispatcher, FlipChessViewIdSettings);
view_dispatcher_remove_view(app->view_dispatcher, FlipChessViewIdTextInput);
submenu_free(app->submenu);
view_dispatcher_free(app->view_dispatcher);
furi_record_close(RECORD_GUI);
app->gui = NULL;
app->notification = NULL;
//Remove whatever is left
//memzero(app, sizeof(FlipChess));
free(app);
}
int32_t flipchess_app(void* p) {
UNUSED(p);
FlipChess* app = flipchess_app_alloc();
// Disabled because causes exit on custom firmwares such as RM
/*if(!furi_hal_region_is_provisioned()) {
flipchess_app_free(app);
return 1;
}*/
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(
app->scene_manager, FlipChessSceneStartscreen); //Start with start screen
//scene_manager_next_scene(app->scene_manager, FlipChessSceneMenu); //if you want to directly start with Menu
furi_hal_random_init();
// furi_hal_power_suppress_charge_enter();
view_dispatcher_run(app->view_dispatcher);
// furi_hal_power_suppress_charge_exit();
flipchess_app_free(app);
return 0;
}

78
applications/external/chess/flipchess.h vendored Normal file
View File

@@ -0,0 +1,78 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_random.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <notification/notification_messages.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/submenu.h>
#include <gui/scene_manager.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/text_input.h>
#include "scenes/flipchess_scene.h"
#include "views/flipchess_startscreen.h"
#include "views/flipchess_scene_1.h"
#define FLIPCHESS_VERSION "v1.8.0"
#define TEXT_BUFFER_SIZE 96
#define TEXT_SIZE (TEXT_BUFFER_SIZE - 1)
typedef struct {
Gui* gui;
NotificationApp* notification;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
SceneManager* scene_manager;
VariableItemList* variable_item_list;
TextInput* text_input;
FlipChessStartscreen* flipchess_startscreen;
FlipChessScene1* flipchess_scene_1;
// Settings options
int haptic;
int white_mode;
int black_mode;
// Startscreen options
uint8_t sound;
// Main menu options
uint8_t import_game;
// Text input
uint8_t input_state;
char import_game_text[TEXT_BUFFER_SIZE];
char input_text[TEXT_BUFFER_SIZE];
} FlipChess;
typedef enum {
FlipChessViewIdStartscreen,
FlipChessViewIdMenu,
FlipChessViewIdScene1,
FlipChessViewIdSettings,
FlipChessViewIdTextInput,
} FlipChessViewId;
typedef enum {
FlipChessHapticOff,
FlipChessHapticOn,
} FlipChessHapticState;
typedef enum {
FlipChessPlayerHuman = 0,
FlipChessPlayerAI1 = 1,
FlipChessPlayerAI2 = 2,
FlipChessPlayerAI3 = 3,
} FlipChessPlayerMode;
typedef enum { FlipChessTextInputDefault, FlipChessTextInputGame } FlipChessTextInputState;
typedef enum {
FlipChessStatusNone = 0,
FlipChessStatusMovePlayer = 1,
FlipChessStatusMoveAI = 2,
FlipChessStatusMoveUndo = 3,
FlipChessStatusReturn = 10,
FlipChessStatusLoadError = 11,
FlipChessStatusSaveError = 12,
} FlipChessStatus;

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

View File

@@ -0,0 +1,16 @@
#pragma once
typedef enum {
FlipChessCustomEventStartscreenUp,
FlipChessCustomEventStartscreenDown,
FlipChessCustomEventStartscreenLeft,
FlipChessCustomEventStartscreenRight,
FlipChessCustomEventStartscreenOk,
FlipChessCustomEventStartscreenBack,
FlipChessCustomEventScene1Up,
FlipChessCustomEventScene1Down,
FlipChessCustomEventScene1Left,
FlipChessCustomEventScene1Right,
FlipChessCustomEventScene1Ok,
FlipChessCustomEventScene1Back,
} FlipChessCustomEvent;

View File

@@ -0,0 +1,153 @@
#include "flipchess_file.h"
#include <storage/storage.h>
#include <loader/loader.h>
// #define FLIPCHESS_APP_BASE_FOLDER APP_BOARDA_PATH("flipchess")
#define FLIPCHESS_APP_BASE_FOLDER EXT_PATH("apps_data/flipchess")
#define FLIPCHESS_APP_BASE_FOLDER_PATH(path) FLIPCHESS_APP_BASE_FOLDER "/" path
#define FLIPCHESS_BOARD_FILE_NAME "board_fen.txt"
#define FLIPCHESS_BOARD_FILE_NAME_BAK "board_fen.bak"
#define FLIPCHESS_BOARD_PATH FLIPCHESS_APP_BASE_FOLDER_PATH(FLIPCHESS_BOARD_FILE_NAME)
#define FLIPCHESS_BOARD_PATH_BAK FLIPCHESS_APP_BASE_FOLDER_PATH(FLIPCHESS_BOARD_FILE_NAME_BAK)
#define FILE_MAX_PATH_LEN 48
#define FILE_MAX_CHARS 94
bool flipchess_has_file(const FlipChessFile file_type, const char* file_name, const bool remove) {
bool ret = false;
const char* path;
if(file_type == FlipChessFileBoard) {
path = FLIPCHESS_BOARD_PATH;
} else {
char path_buf[FILE_MAX_PATH_LEN] = {0};
strcpy(path_buf, FLIPCHESS_APP_BASE_FOLDER); // 22
strcpy(path_buf + strlen(path_buf), "/");
strcpy(path_buf + strlen(path_buf), file_name);
path = path_buf;
}
Storage* fs_api = furi_record_open(RECORD_STORAGE);
if(remove) {
ret = storage_simply_remove(fs_api, path);
} else {
ret = storage_file_exists(fs_api, path);
}
furi_record_close(RECORD_STORAGE);
return ret;
}
bool flipchess_load_file(char* contents, const FlipChessFile file_type, const char* file_name) {
bool ret = false;
const char* path;
if(file_type == FlipChessFileBoard) {
path = FLIPCHESS_BOARD_PATH;
} else {
char path_buf[FILE_MAX_PATH_LEN] = {0};
strcpy(path_buf, FLIPCHESS_APP_BASE_FOLDER); // 22
strcpy(path_buf + strlen(path_buf), "/");
strcpy(path_buf + strlen(path_buf), file_name);
path = path_buf;
}
Storage* fs_api = furi_record_open(RECORD_STORAGE);
File* settings_file = storage_file_alloc(fs_api);
if(storage_file_open(settings_file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
char chr;
int i = 0;
while((storage_file_read(settings_file, &chr, 1) == 1) &&
!storage_file_eof(settings_file)) {
if(i < FILE_MAX_CHARS) {
contents[i] = chr;
}
i++;
}
ret = true;
} else {
contents[0] = '\0';
ret = false;
}
storage_file_close(settings_file);
storage_file_free(settings_file);
furi_record_close(RECORD_STORAGE);
if(strlen(contents) > 0) {
Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info;
FS_Error file_check_err = storage_common_stat(fs_api, path, &layout_file_info);
furi_record_close(RECORD_STORAGE);
if(file_check_err != FSE_OK) {
contents[0] = '\0';
ret = false;
}
// if(layout_file_info.size != 256) {
// memzero(settings, strlen(settings));
// settings[0] = '\0';
// }
}
return ret;
}
bool flipchess_save_file(
const char* settings,
const FlipChessFile file_type,
const char* file_name,
const bool append,
const bool overwrite) {
bool ret = false;
const char* path;
const char* path_bak;
if(file_type == FlipChessFileBoard) {
path = FLIPCHESS_BOARD_PATH;
path_bak = FLIPCHESS_BOARD_PATH_BAK;
} else {
char path_buf[FILE_MAX_PATH_LEN] = {0};
strcpy(path_buf, FLIPCHESS_APP_BASE_FOLDER); // 22
strcpy(path_buf + strlen(path_buf), "/");
strcpy(path_buf + strlen(path_buf), file_name);
path = path_buf;
path_bak = NULL;
}
int open_mode = FSOM_OPEN_ALWAYS;
if(append) {
open_mode = FSOM_OPEN_APPEND;
}
Storage* fs_api = furi_record_open(RECORD_STORAGE);
// try to create the folder
storage_simply_mkdir(fs_api, FLIPCHESS_APP_BASE_FOLDER);
if(overwrite) {
storage_simply_remove(fs_api, path);
}
File* settings_file = storage_file_alloc(fs_api);
if(storage_file_open(settings_file, path, FSAM_WRITE, open_mode)) {
storage_file_write(settings_file, settings, strlen(settings));
storage_file_write(settings_file, "\n", 1);
ret = true;
}
storage_file_close(settings_file);
storage_file_free(settings_file);
if(path_bak != NULL) {
if(overwrite) {
storage_simply_remove(fs_api, path_bak);
}
File* settings_file_bak = storage_file_alloc(fs_api);
if(storage_file_open(settings_file_bak, path_bak, FSAM_WRITE, open_mode)) {
storage_file_write(settings_file_bak, settings, strlen(settings));
storage_file_write(settings_file_bak, "\n", 1);
}
storage_file_close(settings_file_bak);
storage_file_free(settings_file_bak);
}
furi_record_close(RECORD_STORAGE);
return ret;
}

View File

@@ -0,0 +1,15 @@
#include <stdbool.h>
typedef enum {
FlipChessFileBoard,
FlipChessFileOther,
} FlipChessFile;
bool flipchess_has_file(const FlipChessFile file_type, const char* file_name, const bool remove);
bool flipchess_load_file(char* contents, const FlipChessFile file_type, const char* file_name);
bool flipchess_save_file(
const char* contents,
const FlipChessFile file_type,
const char* file_name,
const bool append,
const bool overwrite);

View File

@@ -0,0 +1,35 @@
#include "flipchess_haptic.h"
#include "../flipchess.h"
void flipchess_play_happy_bump(void* context) {
FlipChess* app = context;
if(app->haptic != 1) {
return;
}
notification_message(app->notification, &sequence_set_vibro_on);
furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
notification_message(app->notification, &sequence_reset_vibro);
}
void flipchess_play_bad_bump(void* context) {
FlipChess* app = context;
if(app->haptic != 1) {
return;
}
notification_message(app->notification, &sequence_set_vibro_on);
furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
notification_message(app->notification, &sequence_reset_vibro);
}
void flipchess_play_long_bump(void* context) {
FlipChess* app = context;
if(app->haptic != 1) {
return;
}
for(int i = 0; i < 4; i++) {
notification_message(app->notification, &sequence_set_vibro_on);
furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
notification_message(app->notification, &sequence_reset_vibro);
furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
}
}

View File

@@ -0,0 +1,7 @@
#include <notification/notification_messages.h>
void flipchess_play_happy_bump(void* context);
void flipchess_play_bad_bump(void* context);
void flipchess_play_long_bump(void* context);

View File

@@ -0,0 +1,37 @@
#include "flipchess_voice.h"
#include <furi.h>
#include <furi_hal.h>
#include "../sam/stm32_sam.h"
STM32SAM voice;
void flipchess_voice_shall_we_play() {
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("SHAAL WE PLAY AY GAME?");
furi_hal_speaker_release();
}
}
void flipchess_voice_which_side() {
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("WHICH SIDE DO YOU WANT?");
furi_hal_speaker_release();
}
}
void flipchess_voice_how_about_chess() {
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("HOW ABOUT A NICE GAME OF CHESS?");
furi_hal_speaker_release();
}
}
void flipchess_voice_a_strange_game() {
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(1000)) {
voice.begin();
voice.say("A STRANGE GAME... THE ONLY WINNING MOVE IS NOT TO PLAY.");
furi_hal_speaker_release();
}
}

View File

@@ -0,0 +1,12 @@
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
EXTERNC void flipchess_voice_shall_we_play();
EXTERNC void flipchess_voice_which_side();
EXTERNC void flipchess_voice_how_about_chess();
EXTERNC void flipchess_voice_a_strange_game();
#undef EXTERNC

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
#include <furi.h>
#ifndef __STM32SAM__
#define __STM32SAM__
// SAM Text-To-Speech (TTS), ported from https://github.com/s-macke/SAM
class STM32SAM {
public:
STM32SAM(uint32_t STM32SAM_SPEED);
STM32SAM();
void begin(void);
void
sam(const char* argv,
unsigned char phonetic,
unsigned char singmode,
unsigned char pitch,
unsigned char speed,
unsigned char mouth,
unsigned char throat);
void
sam(char* argv,
unsigned char phonetic,
unsigned char singmode,
unsigned char pitch,
unsigned char speed,
unsigned char mouth,
unsigned char throat);
void say(const char* argv);
void say(char* argv);
void sing(const char* argv);
void sing(char* argv);
void sayPhonetic(const char* argv);
void sayPhonetic(char* argv);
void singPhonetic(const char* argv);
void singPhonetic(char* argv);
void setVoice(
unsigned char _pitch = 64,
unsigned char _speed = 72,
unsigned char _mouth = 128,
unsigned char _throat = 128);
void setPitch(unsigned char _pitch = 64);
void setSpeed(unsigned char _speed = 72);
void setMouth(unsigned char _mouth = 128);
void setThroat(unsigned char _throat = 128);
private:
void SetAUDIO(unsigned char main_volume);
void Output8BitAry(int index, unsigned char ary[5]);
void Output8Bit(int index, unsigned char A);
unsigned char Read(unsigned char p, unsigned char Y);
void Write(unsigned char p, unsigned char Y, unsigned char value);
void RenderSample(unsigned char* mem66);
void Render();
void AddInflection(unsigned char mem48, unsigned char phase1);
void SetMouthThroat();
unsigned char trans(unsigned char mem39212, unsigned char mem39213);
void SetInput(char* _input);
void Init();
int SAMMain();
void PrepareOutput();
void Insert(
unsigned char position /*var57*/,
unsigned char mem60,
unsigned char mem59,
unsigned char mem58);
void InsertBreath();
void CopyStress();
int Parser1();
void SetPhonemeLength();
void Code41240();
void Parser2();
void AdjustLengths();
void Code47503(unsigned char mem52);
void Code37055(unsigned char mem59);
void Code37066(unsigned char mem58);
unsigned char GetRuleByte(unsigned short mem62, unsigned char Y);
int TextToPhonemes(unsigned char* input); // Code36484
uint32_t _STM32SAM_SPEED;
unsigned char speed;
unsigned char pitch;
unsigned char mouth;
unsigned char throat;
unsigned char phonetic;
unsigned char singmode;
}; // STM32SAM class
#endif

View File

@@ -0,0 +1,30 @@
#include "flipchess_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const flipchess_on_enter_handlers[])(void*) = {
#include "flipchess_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const flipchess_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "flipchess_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const flipchess_on_exit_handlers[])(void* context) = {
#include "flipchess_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers flipchess_scene_handlers = {
.on_enter_handlers = flipchess_on_enter_handlers,
.on_event_handlers = flipchess_on_event_handlers,
.on_exit_handlers = flipchess_on_exit_handlers,
.scene_num = FlipChessSceneNum,
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) FlipChessScene##id,
typedef enum {
#include "flipchess_scene_config.h"
FlipChessSceneNum,
} FlipChessScene;
#undef ADD_SCENE
extern const SceneManagerHandlers flipchess_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "flipchess_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "flipchess_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "flipchess_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,4 @@
ADD_SCENE(flipchess, startscreen, Startscreen)
ADD_SCENE(flipchess, menu, Menu)
ADD_SCENE(flipchess, scene_1, Scene_1)
ADD_SCENE(flipchess, settings, Settings)

View File

@@ -0,0 +1,91 @@
#include "../flipchess.h"
enum SubmenuIndex {
SubmenuIndexScene1New = 10,
SubmenuIndexScene1Resume,
SubmenuIndexScene1Import,
SubmenuIndexSettings,
};
void flipchess_scene_menu_submenu_callback(void* context, uint32_t index) {
FlipChess* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void flipchess_scene_menu_on_enter(void* context) {
FlipChess* app = context;
submenu_add_item(
app->submenu,
"New Game",
SubmenuIndexScene1New,
flipchess_scene_menu_submenu_callback,
app);
if(app->import_game == 1) {
submenu_add_item(
app->submenu,
"Resume Game",
SubmenuIndexScene1Resume,
flipchess_scene_menu_submenu_callback,
app);
}
// submenu_add_item(
// app->submenu,
// "Import Game",
// SubmenuIndexScene1Import,
// flipchess_scene_menu_submenu_callback,
// app);
submenu_add_item(
app->submenu, "Settings", SubmenuIndexSettings, flipchess_scene_menu_submenu_callback, app);
submenu_set_selected_item(
app->submenu, scene_manager_get_scene_state(app->scene_manager, FlipChessSceneMenu));
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdMenu);
}
bool flipchess_scene_menu_on_event(void* context, SceneManagerEvent event) {
FlipChess* app = context;
//UNUSED(app);
if(event.type == SceneManagerEventTypeBack) {
//exit app
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
return true;
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexScene1New) {
app->import_game = 0;
scene_manager_set_scene_state(
app->scene_manager, FlipChessSceneMenu, SubmenuIndexScene1New);
scene_manager_next_scene(app->scene_manager, FlipChessSceneScene_1);
return true;
}
if(event.event == SubmenuIndexScene1Resume) {
app->import_game = 1;
scene_manager_set_scene_state(
app->scene_manager, FlipChessSceneMenu, SubmenuIndexScene1Resume);
scene_manager_next_scene(app->scene_manager, FlipChessSceneScene_1);
return true;
} else if(event.event == SubmenuIndexScene1Import) {
app->import_game = 1;
app->input_state = FlipChessTextInputGame;
text_input_set_header_text(app->text_input, "Enter board FEN");
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdTextInput);
return true;
} else if(event.event == SubmenuIndexSettings) {
scene_manager_set_scene_state(
app->scene_manager, FlipChessSceneMenu, SubmenuIndexSettings);
scene_manager_next_scene(app->scene_manager, FlipChessSceneSettings);
return true;
}
}
return false;
}
void flipchess_scene_menu_on_exit(void* context) {
FlipChess* app = context;
submenu_reset(app->submenu);
}

View File

@@ -0,0 +1,55 @@
#include "../flipchess.h"
#include "../helpers/flipchess_file.h"
#include "../helpers/flipchess_custom_event.h"
#include "../views/flipchess_scene_1.h"
void flipchess_scene_1_callback(FlipChessCustomEvent event, void* context) {
furi_assert(context);
FlipChess* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void flipchess_scene_scene_1_on_enter(void* context) {
furi_assert(context);
FlipChess* app = context;
flipchess_scene_1_set_callback(app->flipchess_scene_1, flipchess_scene_1_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdScene1);
}
bool flipchess_scene_scene_1_on_event(void* context, SceneManagerEvent event) {
FlipChess* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case FlipChessCustomEventScene1Left:
case FlipChessCustomEventScene1Right:
break;
case FlipChessCustomEventScene1Up:
case FlipChessCustomEventScene1Down:
break;
case FlipChessCustomEventScene1Back:
notification_message(app->notification, &sequence_reset_red);
notification_message(app->notification, &sequence_reset_green);
notification_message(app->notification, &sequence_reset_blue);
if(!scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, FlipChessSceneMenu)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
consumed = true;
break;
}
}
return consumed;
}
void flipchess_scene_scene_1_on_exit(void* context) {
FlipChess* app = context;
if(app->import_game == 1 && strlen(app->import_game_text) > 0) {
flipchess_save_file(app->import_game_text, FlipChessFileBoard, NULL, false, true);
}
}

View File

@@ -0,0 +1,102 @@
#include "../flipchess.h"
#include "../helpers/flipchess_voice.h"
#include <lib/toolbox/value_index.h>
#define TEXT_LABEL_ON "ON"
#define TEXT_LABEL_OFF "OFF"
const char* const haptic_text[2] = {
TEXT_LABEL_OFF,
TEXT_LABEL_ON,
};
const uint32_t haptic_value[2] = {
FlipChessHapticOff,
FlipChessHapticOn,
};
const char* const player_mode_text[4] = {
"Human",
"CPU 1",
"CPU 2",
"CPU 3",
};
const uint32_t player_mode_value[4] = {
FlipChessPlayerHuman,
FlipChessPlayerAI1,
FlipChessPlayerAI2,
FlipChessPlayerAI3,
};
static void flipchess_scene_settings_set_haptic(VariableItem* item) {
FlipChess* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, haptic_text[index]);
app->haptic = haptic_value[index];
}
static void flipchess_scene_settings_set_white_mode(VariableItem* item) {
FlipChess* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, player_mode_text[index]);
app->white_mode = player_mode_value[index];
}
static void flipchess_scene_settings_set_black_mode(VariableItem* item) {
FlipChess* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, player_mode_text[index]);
app->black_mode = player_mode_value[index];
}
void flipchess_scene_settings_submenu_callback(void* context, uint32_t index) {
FlipChess* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void flipchess_scene_settings_on_enter(void* context) {
FlipChess* app = context;
VariableItem* item;
uint8_t value_index;
if(app->sound == 1) {
flipchess_voice_which_side();
}
// White mode
item = variable_item_list_add(
app->variable_item_list, "White:", 4, flipchess_scene_settings_set_white_mode, app);
value_index = value_index_uint32(app->white_mode, player_mode_value, 4);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, player_mode_text[value_index]);
// Black mode
item = variable_item_list_add(
app->variable_item_list, "Black:", 4, flipchess_scene_settings_set_black_mode, app);
value_index = value_index_uint32(app->black_mode, player_mode_value, 4);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, player_mode_text[value_index]);
// Vibro on/off
item = variable_item_list_add(
app->variable_item_list, "Vibro/Haptic:", 2, flipchess_scene_settings_set_haptic, app);
value_index = value_index_uint32(app->haptic, haptic_value, 2);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, haptic_text[value_index]);
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdSettings);
}
bool flipchess_scene_settings_on_event(void* context, SceneManagerEvent event) {
FlipChess* app = context;
UNUSED(app);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
}
return consumed;
}
void flipchess_scene_settings_on_exit(void* context) {
FlipChess* app = context;
variable_item_list_set_selected_item(app->variable_item_list, 0);
variable_item_list_reset(app->variable_item_list);
}

View File

@@ -0,0 +1,67 @@
#include "../flipchess.h"
#include "../helpers/flipchess_voice.h"
#include "../helpers/flipchess_file.h"
#include "../helpers/flipchess_custom_event.h"
#include "../views/flipchess_startscreen.h"
void flipchess_scene_startscreen_callback(FlipChessCustomEvent event, void* context) {
furi_assert(context);
FlipChess* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, event);
}
void flipchess_scene_startscreen_on_enter(void* context) {
furi_assert(context);
FlipChess* app = context;
if(flipchess_has_file(FlipChessFileBoard, NULL, false)) {
if(flipchess_load_file(app->import_game_text, FlipChessFileBoard, NULL)) {
app->import_game = 1;
}
}
flipchess_startscreen_set_callback(
app->flipchess_startscreen, flipchess_scene_startscreen_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, FlipChessViewIdStartscreen);
}
bool flipchess_scene_startscreen_on_event(void* context, SceneManagerEvent event) {
FlipChess* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case FlipChessCustomEventStartscreenLeft:
case FlipChessCustomEventStartscreenRight:
break;
case FlipChessCustomEventStartscreenUp:
case FlipChessCustomEventStartscreenDown:
break;
case FlipChessCustomEventStartscreenOk:
scene_manager_next_scene(app->scene_manager, FlipChessSceneMenu);
consumed = true;
break;
case FlipChessCustomEventStartscreenBack:
notification_message(app->notification, &sequence_reset_red);
notification_message(app->notification, &sequence_reset_green);
notification_message(app->notification, &sequence_reset_blue);
if(!scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, FlipChessSceneStartscreen)) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
consumed = true;
break;
}
}
return consumed;
}
void flipchess_scene_startscreen_on_exit(void* context) {
FlipChess* app = context;
if(app->sound == 1) {
flipchess_voice_shall_we_play();
}
}

View File

@@ -0,0 +1,727 @@
#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;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <gui/view.h>
#include "../helpers/flipchess_custom_event.h"
typedef struct FlipChessScene1 FlipChessScene1;
typedef void (*FlipChessScene1Callback)(FlipChessCustomEvent event, void* context);
void flipchess_scene_1_set_callback(
FlipChessScene1* flipchess_scene_1,
FlipChessScene1Callback callback,
void* context);
View* flipchess_scene_1_get_view(FlipChessScene1* flipchess_static);
FlipChessScene1* flipchess_scene_1_alloc();
void flipchess_scene_1_free(FlipChessScene1* flipchess_static);

View File

@@ -0,0 +1,155 @@
#include "../flipchess.h"
#include <furi.h>
#include <furi_hal.h>
#include <input/input.h>
#include <gui/elements.h>
#include "flipchess_icons.h"
struct FlipChessStartscreen {
View* view;
FlipChessStartscreenCallback callback;
void* context;
};
typedef struct {
int some_value;
} FlipChessStartscreenModel;
void flipchess_startscreen_set_callback(
FlipChessStartscreen* instance,
FlipChessStartscreenCallback callback,
void* context) {
furi_assert(instance);
furi_assert(callback);
instance->callback = callback;
instance->context = context;
}
void flipchess_startscreen_draw(Canvas* canvas, FlipChessStartscreenModel* model) {
UNUSED(model);
canvas_clear(canvas);
canvas_set_color(canvas, ColorBlack);
canvas_draw_icon(canvas, 0, 0, &I_FLIPR_128x64);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 4, 11, "Chess");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 62, 11, FLIPCHESS_VERSION);
//canvas_set_font(canvas, FontSecondary);
//canvas_draw_str(canvas, 10, 11, "How about a nice game of...");
//canvas_draw_str(canvas, 99, 40, FLIPCHESS_VERSION);
//canvas_set_font(canvas, FontPrimary);
//canvas_draw_str(canvas, 10, 23, "Chess");
//canvas_draw_icon(canvas, 0, 40, &I_Background_128x11);
//canvas_draw_str(canvas, 10, 61, "FLIPR");
elements_button_left(canvas, "Sound");
elements_button_right(canvas, "Silent");
}
static void flipchess_startscreen_model_init(FlipChessStartscreenModel* const model) {
model->some_value = 1;
}
bool flipchess_startscreen_input(InputEvent* event, void* context) {
furi_assert(context);
FlipChessStartscreen* instance = context;
FlipChess* app = instance->context;
if(event->type == InputTypeRelease) {
switch(event->key) {
case InputKeyBack:
with_view_model(
instance->view,
FlipChessStartscreenModel * model,
{
UNUSED(model);
instance->callback(FlipChessCustomEventStartscreenBack, instance->context);
},
true);
break;
case InputKeyLeft:
// sound on, haptic off
app->sound = 1;
app->haptic = FlipChessHapticOff;
with_view_model(
instance->view,
FlipChessStartscreenModel * model,
{
UNUSED(model);
instance->callback(FlipChessCustomEventStartscreenOk, instance->context);
},
true);
break;
case InputKeyRight:
// sound off, haptic on
app->sound = 0;
app->haptic = FlipChessHapticOn;
with_view_model(
instance->view,
FlipChessStartscreenModel * model,
{
UNUSED(model);
instance->callback(FlipChessCustomEventStartscreenOk, instance->context);
},
true);
break;
case InputKeyUp:
case InputKeyDown:
case InputKeyOk:
case InputKeyMAX:
break;
}
}
return true;
}
void flipchess_startscreen_exit(void* context) {
furi_assert(context);
}
void flipchess_startscreen_enter(void* context) {
furi_assert(context);
FlipChessStartscreen* instance = (FlipChessStartscreen*)context;
with_view_model(
instance->view,
FlipChessStartscreenModel * model,
{ flipchess_startscreen_model_init(model); },
true);
}
FlipChessStartscreen* flipchess_startscreen_alloc() {
FlipChessStartscreen* instance = malloc(sizeof(FlipChessStartscreen));
instance->view = view_alloc();
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(FlipChessStartscreenModel));
view_set_context(instance->view, instance); // furi_assert crashes in events without this
view_set_draw_callback(instance->view, (ViewDrawCallback)flipchess_startscreen_draw);
view_set_input_callback(instance->view, flipchess_startscreen_input);
//view_set_enter_callback(instance->view, flipchess_startscreen_enter);
//view_set_exit_callback(instance->view, flipchess_startscreen_exit);
with_view_model(
instance->view,
FlipChessStartscreenModel * model,
{ flipchess_startscreen_model_init(model); },
true);
return instance;
}
void flipchess_startscreen_free(FlipChessStartscreen* instance) {
furi_assert(instance);
with_view_model(
instance->view, FlipChessStartscreenModel * model, { UNUSED(model); }, true);
view_free(instance->view);
free(instance);
}
View* flipchess_startscreen_get_view(FlipChessStartscreen* instance) {
furi_assert(instance);
return instance->view;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <gui/view.h>
#include "../helpers/flipchess_custom_event.h"
typedef struct FlipChessStartscreen FlipChessStartscreen;
typedef void (*FlipChessStartscreenCallback)(FlipChessCustomEvent event, void* context);
void flipchess_startscreen_set_callback(
FlipChessStartscreen* flipchess_startscreen,
FlipChessStartscreenCallback callback,
void* context);
View* flipchess_startscreen_get_view(FlipChessStartscreen* flipchess_static);
FlipChessStartscreen* flipchess_startscreen_alloc();
void flipchess_startscreen_free(FlipChessStartscreen* flipchess_static);