mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-06 05:19:09 -07:00
Chess v1.8 (#355)
This commit is contained in:
21
applications/external/chess/LICENSE
vendored
Normal file
21
applications/external/chess/LICENSE
vendored
Normal 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.
|
||||
19
applications/external/chess/application.fam
vendored
Normal file
19
applications/external/chess/application.fam
vendored
Normal 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",
|
||||
)
|
||||
3492
applications/external/chess/chess/smallchesslib.h
vendored
Normal file
3492
applications/external/chess/chess/smallchesslib.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
179
applications/external/chess/flipchess.c
vendored
Normal file
179
applications/external/chess/flipchess.c
vendored
Normal 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
78
applications/external/chess/flipchess.h
vendored
Normal 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;
|
||||
BIN
applications/external/chess/flipchess_10px.png
vendored
Normal file
BIN
applications/external/chess/flipchess_10px.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
16
applications/external/chess/helpers/flipchess_custom_event.h
vendored
Normal file
16
applications/external/chess/helpers/flipchess_custom_event.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
FlipChessCustomEventStartscreenUp,
|
||||
FlipChessCustomEventStartscreenDown,
|
||||
FlipChessCustomEventStartscreenLeft,
|
||||
FlipChessCustomEventStartscreenRight,
|
||||
FlipChessCustomEventStartscreenOk,
|
||||
FlipChessCustomEventStartscreenBack,
|
||||
FlipChessCustomEventScene1Up,
|
||||
FlipChessCustomEventScene1Down,
|
||||
FlipChessCustomEventScene1Left,
|
||||
FlipChessCustomEventScene1Right,
|
||||
FlipChessCustomEventScene1Ok,
|
||||
FlipChessCustomEventScene1Back,
|
||||
} FlipChessCustomEvent;
|
||||
153
applications/external/chess/helpers/flipchess_file.c
vendored
Normal file
153
applications/external/chess/helpers/flipchess_file.c
vendored
Normal 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;
|
||||
}
|
||||
15
applications/external/chess/helpers/flipchess_file.h
vendored
Normal file
15
applications/external/chess/helpers/flipchess_file.h
vendored
Normal 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);
|
||||
35
applications/external/chess/helpers/flipchess_haptic.c
vendored
Normal file
35
applications/external/chess/helpers/flipchess_haptic.c
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
7
applications/external/chess/helpers/flipchess_haptic.h
vendored
Normal file
7
applications/external/chess/helpers/flipchess_haptic.h
vendored
Normal 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);
|
||||
37
applications/external/chess/helpers/flipchess_voice.cpp
vendored
Normal file
37
applications/external/chess/helpers/flipchess_voice.cpp
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
12
applications/external/chess/helpers/flipchess_voice.h
vendored
Normal file
12
applications/external/chess/helpers/flipchess_voice.h
vendored
Normal 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
|
||||
BIN
applications/external/chess/icons/Background_128x11.png
vendored
Normal file
BIN
applications/external/chess/icons/Background_128x11.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 446 B |
BIN
applications/external/chess/icons/FLIPR_128x64.png
vendored
Normal file
BIN
applications/external/chess/icons/FLIPR_128x64.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1017 B |
5703
applications/external/chess/sam/stm32_sam.cpp
vendored
Normal file
5703
applications/external/chess/sam/stm32_sam.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
96
applications/external/chess/sam/stm32_sam.h
vendored
Normal file
96
applications/external/chess/sam/stm32_sam.h
vendored
Normal 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
|
||||
30
applications/external/chess/scenes/flipchess_scene.c
vendored
Normal file
30
applications/external/chess/scenes/flipchess_scene.c
vendored
Normal 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,
|
||||
};
|
||||
29
applications/external/chess/scenes/flipchess_scene.h
vendored
Normal file
29
applications/external/chess/scenes/flipchess_scene.h
vendored
Normal 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
|
||||
4
applications/external/chess/scenes/flipchess_scene_config.h
vendored
Normal file
4
applications/external/chess/scenes/flipchess_scene_config.h
vendored
Normal 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)
|
||||
91
applications/external/chess/scenes/flipchess_scene_menu.c
vendored
Normal file
91
applications/external/chess/scenes/flipchess_scene_menu.c
vendored
Normal 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);
|
||||
}
|
||||
55
applications/external/chess/scenes/flipchess_scene_scene_1.c
vendored
Normal file
55
applications/external/chess/scenes/flipchess_scene_scene_1.c
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
102
applications/external/chess/scenes/flipchess_scene_settings.c
vendored
Normal file
102
applications/external/chess/scenes/flipchess_scene_settings.c
vendored
Normal 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);
|
||||
}
|
||||
67
applications/external/chess/scenes/flipchess_scene_startscreen.c
vendored
Normal file
67
applications/external/chess/scenes/flipchess_scene_startscreen.c
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
727
applications/external/chess/views/flipchess_scene_1.c
vendored
Normal file
727
applications/external/chess/views/flipchess_scene_1.c
vendored
Normal 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;
|
||||
}
|
||||
19
applications/external/chess/views/flipchess_scene_1.h
vendored
Normal file
19
applications/external/chess/views/flipchess_scene_1.h
vendored
Normal 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);
|
||||
155
applications/external/chess/views/flipchess_startscreen.c
vendored
Normal file
155
applications/external/chess/views/flipchess_startscreen.c
vendored
Normal 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;
|
||||
}
|
||||
19
applications/external/chess/views/flipchess_startscreen.h
vendored
Normal file
19
applications/external/chess/views/flipchess_startscreen.h
vendored
Normal 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);
|
||||
Reference in New Issue
Block a user