summaryrefslogtreecommitdiff
path: root/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games
diff options
context:
space:
mode:
authorkrolyxon <me@krolyxon.com>2026-06-08 23:10:46 +0530
committerkrolyxon <me@krolyxon.com>2026-06-08 23:10:46 +0530
commit3120783000d0025b183b0397acaa8b769499eb38 (patch)
tree1c4f93be213f1b1d48f59e554562d847b4e7c25e /.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games
Initial gh-pages firmware hosting
Diffstat (limited to '.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games')
-rw-r--r--.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/LittleRookChess/LittleRookChess.ino2347
-rw-r--r--.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/SpaceTrash/SpaceTrash.ino1857
2 files changed, 4204 insertions, 0 deletions
diff --git a/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/LittleRookChess/LittleRookChess.ino b/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/LittleRookChess/LittleRookChess.ino
new file mode 100644
index 0000000..3a4aca9
--- /dev/null
+++ b/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/LittleRookChess/LittleRookChess.ino
@@ -0,0 +1,2347 @@
+/*
+
+ LittleRookChess.ino
+
+ A Simple Chess Engine (ported from U8glib)
+
+ Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+ Copyright (c) 2016, olikraus@gmail.com
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list
+ of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Current Rule Limitation
+ - no minor promotion, only "Queening" of the pawn
+ - threefold repetition is not detected (same board situation appears three times)
+ Note: Could be implemented, but requires tracking of the complete game
+ - Fifty-move rule is not checked (no pawn move, no capture within last 50 moves)
+
+ Words
+ Ply a half move
+
+ General Links
+ http://chessprogramming.wikispaces.com/
+
+ Arduino specific
+ http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1260055596
+
+ Prefixes
+ chess_ Generic Chess Application Interface
+ ce_ Chess engine, used internally, these function should not be called directly
+ cu_ Chess utility function
+ stack_ Internal function for stack handling
+
+ Issues
+ 10.01.2011
+ - castling to the right does not move the rook
+ --> done
+ - castling to the left: King can only move two squares
+ --> done
+
+ 11.01.2011
+ Next Steps:
+ - replace stack_NextCurrentPos with cu_NextPos, cleanup code according to the loop variable
+ --> done
+ - Castling: Need to check for fields under attack
+ --> done
+
+ - Check for WIN / LOOSE situation, perhaps call ce_Eval() once on the top-level board setup
+ just after the real move
+ - cleanup cu_Move
+ --> almost done
+ - add some heuristics to the eval procedure
+ - add right side menu
+ --> done
+ - clean up chess_ManualMove
+ --> done
+ - finish menu (consider is_game_end, undo move)
+ - end condition: if KING is under attack and if KING can not move to a field which is under attack...
+ then the game is lost. What will be returned by the Eval procedure? is it -INF?
+ --> finished
+
+ - reduce the use of variable color, all should be reduced to board_orientation and ply&1
+
+ - chess_GetNextMarked shoud make use of cu_NextPos
+ --> done
+ - chess_ManualMove: again cleanup, solve draw issue (KING is not in check and no legal moves are available)
+ --> done
+ 22.01.2011
+ - simplify eval_t ce_Eval(void)
+ - position eval does not work, still moves side pawn :-(
+ maybe because all pieces are considered
+ --> done
+
+ 17. June 2016
+ U8g2/Arduboy Port
+*/
+
+#include <Arduino.h>
+#include <U8g2lib.h>
+
+#ifdef U8X8_HAVE_HW_SPI
+#include <SPI.h>
+#endif
+#ifdef U8X8_HAVE_HW_I2C
+#include <Wire.h>
+#endif
+
+
+/*
+ U8glib Example Overview:
+ Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption
+ Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards.
+ U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only.
+
+ This is a page buffer example.
+*/
+
+void chess_Init(u8g2_t *u8g, uint8_t body_color);
+
+#define ARDUBOY
+//#define PI_SHIELD
+
+#ifdef ARDUBOY
+/*=== ARDUBOY Production, Kickstarter Edition ===*/
+U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6); // Arduboy (Production, Kickstarter Edition)
+void setup(void) {
+ //u8g2.begin(/*Select=*/ A0, /*Right/Next=*/ 5, /*Left/Prev=*/ 9, /*Up=*/ 8, /*Down=*/ 10, /*Home/Cancel=*/ A1); // Arduboy DevKit
+ u8g2.begin(/*Select=*/ 7, /*Right/Next=*/ A1, /*Left/Prev=*/ A2, /*Up=*/ A0, /*Down=*/ A3, /*Home/Cancel=*/ 8); // Arduboy 10 (Production)
+ chess_Init(u8g2.getU8g2(), 1); /* assuming Arduboy OLED here, so make the body_color be 1 for the white OLED pixel */
+}
+#endif
+
+#ifdef PI_SHIELD
+/*=== Pax Instruments Shield ===*/
+U8G2_ST7567_PI_132X64_1_4W_HW_SPI u8g2(U8G2_R2, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8); // Pax Instruments Shield, LCD_BL=6
+void setup(void) {
+ u8g2.begin(/*Select=*/ 4, /*Right/Next=*/ 5, /*Left/Prev=*/ A1, /*Up=*/ U8X8_PIN_NONE, /*Down=*/ U8X8_PIN_NONE, /*Home/Cancel=*/ A2); // Pax Instrument Shield
+
+ /* U8g2 Project: Pax Instruments Shield: Enable Backlight */
+ pinMode(6, OUTPUT);
+ digitalWrite(6, 0);
+
+ chess_Init(u8g2.getU8g2(), 0); /* assuming Arduboy OLED here, so make the body_color be 1 for the white OLED pixel */
+}
+#endif
+
+/* Ignore PROGMEM for now */
+#define CHESS_PROGMEM
+#define chess_pgm_read(p) (*(p))
+#define CHESS_PSTR(s) (s)
+#define u8g2_DrawStrP u8g2_DrawStr
+
+/* backward compatibility */
+#define u8g2_SetDefaultBackgroundColor(u8g2) \
+ u8g2_SetDrawColor(u8g2, 0)
+#define u8g2_SetDefaultForegroundColor(u8g2) \
+ u8g2_SetDrawColor(u8g2, 1)
+
+
+/* menu button definitions: mapped to the u8g2 menu events */
+
+#define CHESS_KEY_NONE 0
+#define CHESS_KEY_NEXT U8X8_MSG_GPIO_MENU_NEXT
+#define CHESS_KEY_PREV U8X8_MSG_GPIO_MENU_PREV
+#define CHESS_KEY_SELECT U8X8_MSG_GPIO_MENU_SELECT
+#define CHESS_KEY_BACK U8X8_MSG_GPIO_MENU_HOME
+
+
+/*
+SAN identifies each piece by a single upper case letter. The standard English
+values: pawn = "P", knight = "N", bishop = "B", rook = "R", queen = "Q", and
+king = "K".
+*/
+
+/* numbers for the various pieces */
+#define PIECE_NONE 0
+#define PIECE_PAWN 1
+#define PIECE_KNIGHT 2
+#define PIECE_BISHOP 3
+#define PIECE_ROOK 4
+#define PIECE_QUEEN 5
+#define PIECE_KING 6
+
+/* color definitions */
+#define COLOR_WHITE 0
+#define COLOR_BLACK 1
+
+/* a mask, which includes COLOR and PIECE number */
+#define COLOR_PIECE_MASK 0x01f
+
+#define CP_MARK_MASK 0x20
+
+#define ILLEGAL_POSITION 255
+
+/* This is the build in upper limit of the search stack */
+/* This value defines the amount of memory allocated for the search stack */
+/* The search depth of this chess engine can never exceed this value */
+#define STACK_MAX_SIZE 5
+
+/* chess half move stack: twice the number of undo's, a user can do */
+#define CHM_USER_SIZE 6
+
+/* the CHM_LIST_SIZE must be larger than the maximum search depth */
+/* the overall size of ste half move stack */
+#define CHM_LIST_SIZE (STACK_MAX_SIZE+CHM_USER_SIZE+2)
+
+typedef int16_t eval_t; /* a variable type to store results from the evaluation */
+//#define EVAL_T_LOST -32768
+#define EVAL_T_MIN -32767
+#define EVAL_T_MAX 32767
+//#define EVAL_T_WIN 32767
+
+/* for maintainance of our own stack: this is the definition of one element on the stack */
+struct _stack_element_struct
+{
+ /* the current source position which is investigated */
+ uint8_t current_pos;
+ uint8_t current_cp;
+ uint8_t current_color; /* COLOR_WHITE or COLOR_BLACK: must be predefines */
+
+ /* the move which belongs to that value, both values are game positions */
+ uint8_t best_from_pos;
+ uint8_t best_to_pos;
+ /* the best value, which has been dicovered so far */
+ eval_t best_eval;
+};
+typedef struct _stack_element_struct stack_element_t;
+typedef struct _stack_element_struct *stack_element_p;
+
+/* chess half move history */
+struct _chm_struct
+{
+ uint8_t main_cp; /* the main piece, which is moved */
+ uint8_t main_src; /* the source position of the main piece */
+ uint8_t main_dest; /* the destination of the main piece */
+
+ uint8_t other_cp; /* another piece: the captured one, the ROOK in case of castling or PIECE_NONE */
+ uint8_t other_src; /* the delete position of other_cp. Often identical to main_dest except for e.p. and castling */
+ uint8_t other_dest; /* only used for castling: ROOK destination pos */
+
+ /* the position of the last pawn, which did a double move forward */
+ /* this is required to check en passant conditions */
+ /* this array can be indexed by the color of the current player */
+ /* this is the condition BEFORE the move was done */
+ uint8_t pawn_dbl_move[2];
+
+ /* flags for the movement of rook and king; required for castling */
+ /* a 1 means: castling is (still) possible */
+ /* a 0 means: castling not possible */
+ /* bit 0 left side white */
+ /* bit 1 right side white */
+ /* bit 2 left side black */
+ /* bit 3 right side black */
+ /* this is the condition BEFORE the move was done */
+ uint8_t castling_possible;
+};
+
+typedef struct _chm_struct chm_t;
+typedef struct _chm_struct *chm_p;
+
+/* little rook chess, main structure */
+struct _lrc_struct
+{
+ /* half-move (ply) counter: Counts the number of half-moves so far. Starts with 0 */
+ /* the lowest bit is used to derive the color of the current player */
+ /* will be set to zero in chess_SetupBoard() */
+ uint8_t ply_count;
+
+ /* the half move stack position counter, counts the number of elements in chm_list */
+ uint8_t chm_pos;
+
+ /* each element contains a colored piece, empty fields have value 0 */
+ /* the field with index 0 is black (lower left) */
+ uint8_t board[64];
+ /* the position of the last pawn, which did a double move forward */
+ /* this is required to check en passant conditions */
+ /* this array can be indexed by the color of the current player */
+ uint8_t pawn_dbl_move[2];
+
+ /* flags for the movement of rook and king; required for castling */
+ /* a 1 means: castling is (still) possible */
+ /* a 0 means: castling not possible */
+ /* bit 0 left side white */
+ /* bit 1 right side white */
+ /* bit 2 left side black */
+ /* bit 3 right side black */
+ uint8_t castling_possible;
+
+ /* board orientation */
+ /* 0: white is below COLOR_WHITE */
+ /* 1: black is below COLOR_BLACK */
+ /* bascially, this can be used as a color */
+ uint8_t orientation;
+
+ /* exchange colors of the pieces */
+ /* 0: white has an empty body, use this for bright background color */
+ /* 1: black has an empty body, use this for dark backround color */
+ uint8_t strike_out_color;
+
+ /* 0, when the game is ongoing */
+ /* 1, when the game is stopped (lost or draw) */
+ uint8_t is_game_end;
+ /* the color of the side which lost the game */
+ /* this value is only valid, when is_game_end is not 0 */
+ /* values 0 and 1 represent WHITE and BLACK, 2 means a draw */
+ uint8_t lost_side_color;
+
+
+
+ /* checks are executed in ce_LoopRecur */
+ /* these checks will put some marks on the board */
+ /* this will be used by the interface to find out */
+ /* legal moves */
+ uint8_t check_src_pos;
+ uint8_t check_mode; /* CHECK_MODE_NONE, CHECK_MODE_MOVEABLE, CHECK_MODE_TARGET_MOVE */
+
+
+ /* count of the attacking pieces, indexed by color */
+ uint8_t find_piece_cnt[2];
+
+ /* sum of the attacking pieces, indexed by color */
+ uint8_t find_piece_weight[2];
+
+ /* points to the current element of the search stack */
+ /* this stack is NEVER empty. The value 0 points to the first element of the stack */
+ /* actually "curr_depth" represent half-moves (plies) */
+ uint8_t curr_depth;
+ uint8_t max_depth;
+ stack_element_p curr_element;
+
+ /* allocated memory for the search stack */
+ stack_element_t stack_memory[STACK_MAX_SIZE];
+
+ /* the half move stack, used for move undo and depth search, size is stored in chm_pos */
+ chm_t chm_list[CHM_LIST_SIZE];
+};
+typedef struct _lrc_struct lrc_t;
+
+#define CHECK_MODE_NONE 0
+#define CHECK_MODE_MOVEABLE 1
+#define CHECK_MODE_TARGET_MOVE 2
+
+
+
+/*==============================================================*/
+/* global variables */
+/*==============================================================*/
+
+lrc_t lrc_obj;
+u8g2_t *lrc_u8g; /* pointer to the C object of u8g2 lib, this is used by the chess engine */
+
+
+/*==============================================================*/
+/* forward declarations */
+/*==============================================================*/
+
+/*
+ apply no inline to some of the functions:
+ avr-gcc very often inlines functions, however not inline saves a lot of program memory!
+ On the other hand there are some really short procedures which should be inlined (like cp_GetColor)
+ These procedures are marked static to prevent the generation of the expanded procedure, which
+ also saves space.
+*/
+
+uint8_t stack_Push(uint8_t color) U8G2_NOINLINE;
+void stack_Pop(void) U8G2_NOINLINE;
+void stack_InitCurrElement(void) U8G2_NOINLINE;
+void stack_Init(uint8_t max) U8G2_NOINLINE;
+void stack_SetMove(eval_t val, uint8_t to_pos) U8G2_NOINLINE;
+uint8_t cu_NextPos(uint8_t pos) U8G2_NOINLINE;
+static uint8_t cu_gpos2bpos(uint8_t gpos);
+static uint8_t cp_Construct(uint8_t color, uint8_t piece);
+static uint8_t cp_GetPiece(uint8_t cp);
+static uint8_t cp_GetColor(uint8_t cp);
+uint8_t cp_GetFromBoard(uint8_t pos) U8G2_NOINLINE;
+void cp_SetOnBoard(uint8_t pos, uint8_t cp) U8G2_NOINLINE;
+
+void cu_ClearBoard(void) U8G2_NOINLINE;
+void chess_SetupBoard(void) U8G2_NOINLINE;
+eval_t ce_Eval(void);
+
+void cu_ClearMoveHistory(void) U8G2_NOINLINE;
+void cu_ReduceHistoryByFullMove(void) U8G2_NOINLINE;
+void cu_UndoHalfMove(void) U8G2_NOINLINE;
+chm_p cu_PushHalfMove(void) U8G2_NOINLINE;
+
+
+void ce_CalculatePositionWeight(uint8_t pos);
+uint8_t ce_GetPositionAttackWeight(uint8_t pos, uint8_t color);
+
+void chess_Thinking(void);
+void ce_LoopPieces(void);
+
+
+/*==============================================================*/
+/* search stack */
+/*==============================================================*/
+
+/* get current element from stack */
+struct _stack_element_struct *stack_GetCurrElement(void)
+{
+ return lrc_obj.curr_element;
+}
+
+uint8_t stack_Push(uint8_t color)
+{
+ if ( lrc_obj.curr_depth == lrc_obj.max_depth )
+ return 0;
+ lrc_obj.curr_depth++;
+ lrc_obj.curr_element = lrc_obj.stack_memory+lrc_obj.curr_depth;
+
+ /* change view for the evaluation */
+ color ^= 1;
+ stack_GetCurrElement()->current_color = color;
+
+ return 1;
+}
+
+void stack_Pop(void)
+{
+ lrc_obj.curr_depth--;
+ lrc_obj.curr_element = lrc_obj.stack_memory+lrc_obj.curr_depth;
+}
+
+/* reset the current element on the stack */
+void stack_InitCurrElement(void)
+{
+ stack_element_p e = stack_GetCurrElement();
+ e->best_eval = EVAL_T_MIN;
+ e->best_from_pos = ILLEGAL_POSITION;
+ e->best_to_pos = ILLEGAL_POSITION;
+}
+
+/* resets the search stack (and the check mode) */
+void stack_Init(uint8_t max)
+{
+ lrc_obj.curr_depth = 0;
+ lrc_obj.curr_element = lrc_obj.stack_memory;
+ lrc_obj.max_depth = max;
+ lrc_obj.check_mode = CHECK_MODE_NONE;
+ stack_InitCurrElement();
+ stack_GetCurrElement()->current_color = lrc_obj.ply_count;
+ stack_GetCurrElement()->current_color &= 1;
+}
+
+/* assign evaluation value and store the move, if this is the best move */
+/* assumes, that current_pos contains the source position */
+void stack_SetMove(eval_t val, uint8_t to_pos)
+{
+ stack_element_p e = stack_GetCurrElement();
+ if ( e->best_eval < val )
+ {
+ e->best_eval = val;
+ e->best_from_pos = e->current_pos;
+ e->best_to_pos = to_pos;
+ }
+}
+
+/*
+ calculate next position on a 0x88 board
+ loop is constructed in this way:
+ i = 0;
+ do
+ {
+ ...
+ i = cu_NextPos(i);
+ } while( i != 0 );
+
+ next pos might be started with an illegal position like 255
+*/
+uint8_t cu_NextPos(uint8_t pos)
+{
+ /* calculate next gpos */
+ pos++;
+ if ( ( pos & 0x08 ) != 0 )
+ {
+ pos+= 0x10;
+ pos&= 0xf0;
+ }
+ if ( ( pos & 0x80 ) != 0 )
+ pos = 0;
+ return pos;
+}
+
+uint8_t cu_PrevPos(uint8_t pos)
+{
+ /* calculate prev gpos */
+ pos--;
+ if ( ( pos & 0x80 ) != 0 )
+ pos = 0x077;
+ else if ( ( pos & 0x08 ) != 0 )
+ {
+ pos &= 0xf0;
+ pos |= 0x07;
+ }
+ return pos;
+}
+
+
+/*==============================================================*/
+/* position transltion */
+/*==============================================================*/
+/*
+ there are two positions
+ 1. game position (gpos): BCD encoded x-y values
+ 2. board position (bpos): a number between 0 and 63, only used to access the board.
+*/
+/*
+ gpos: game position value
+ returns: board position
+ note: does not do any checks
+*/
+static uint8_t cu_gpos2bpos(uint8_t gpos)
+{
+ uint8_t bpos = gpos;
+ bpos &= 0xf0;
+ bpos >>= 1;
+ gpos &= 0x0f;
+ bpos |= gpos;
+ return bpos;
+}
+
+#define gpos_IsIllegal(gpos) ((gpos) & 0x088)
+
+
+/*==============================================================*/
+/* colored piece handling */
+/*==============================================================*/
+
+#define cp_IsMarked(cp) ((cp) & CP_MARK_MASK)
+
+
+/*
+ piece: one of PIECE_xxx
+ color: COLOR_WHITE or COLOR_BLACK
+
+ returns: A colored piece
+*/
+static uint8_t cp_Construct(uint8_t color, uint8_t piece)
+{
+ color <<= 4;
+ color |= piece;
+ return color;
+}
+
+/* inline is better than a macro */
+static uint8_t cp_GetPiece(uint8_t cp)
+{
+ cp &= 0x0f;
+ return cp;
+}
+
+/*
+ we could use a macro:
+ #define cp_GetColor(cp) (((cp) >> 4)&1)
+ however, inlined functions are sometimes much better
+*/
+static uint8_t cp_GetColor(uint8_t cp)
+{
+ cp >>= 4;
+ cp &= 1;
+ return cp;
+}
+
+/*
+ pos: game position
+ returns the colored piece at the given position
+*/
+uint8_t cp_GetFromBoard(uint8_t pos)
+{
+ return lrc_obj.board[cu_gpos2bpos(pos)];
+}
+
+/*
+ pos: game position
+ cp: colored piece
+*/
+void cp_SetOnBoard(uint8_t pos, uint8_t cp)
+{
+ /*printf("cp_SetOnBoard gpos:%02x cp:%02x\n", pos, cp);*/
+ lrc_obj.board[cu_gpos2bpos(pos)] = cp;
+}
+
+/*==============================================================*/
+/* global board access */
+/*==============================================================*/
+
+void cu_ClearBoard(void)
+{
+ uint8_t i;
+ /* clear the board */
+ for( i = 0; i < 64; i++ )
+ lrc_obj.board[i] = PIECE_NONE;
+
+ lrc_obj.ply_count = 0;
+ lrc_obj.orientation = COLOR_WHITE;
+
+ lrc_obj.pawn_dbl_move[0] = ILLEGAL_POSITION;
+ lrc_obj.pawn_dbl_move[1] = ILLEGAL_POSITION;
+
+ lrc_obj.castling_possible = 0x0f;
+
+ lrc_obj.is_game_end = 0;
+ lrc_obj.lost_side_color = 0;
+
+ /* clear half move history */
+ cu_ClearMoveHistory();
+
+}
+
+/*
+ test setup
+ white wins in one move
+*/
+void chess_SetupBoardTest01(void)
+{
+ cu_ClearBoard();
+ lrc_obj.board[7+7*8] = cp_Construct(COLOR_BLACK, PIECE_KING);
+ lrc_obj.board[7+5*8] = cp_Construct(COLOR_WHITE, PIECE_PAWN);
+ lrc_obj.board[3] = cp_Construct(COLOR_WHITE, PIECE_KING);
+ lrc_obj.board[0+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK);
+ lrc_obj.board[6] = cp_Construct(COLOR_WHITE, PIECE_QUEEN);
+}
+
+/* setup the global board */
+void chess_SetupBoard(void)
+{
+ uint8_t i;
+ register uint8_t bp, wp;
+
+ /* clear the board */
+ cu_ClearBoard();
+
+ /* precronstruct pawns */
+ wp = cp_Construct(COLOR_WHITE, PIECE_PAWN);
+ bp = cp_Construct(COLOR_BLACK, PIECE_PAWN);
+
+ /* setup pawn */
+ for( i = 0; i < 8; i++ )
+ {
+ lrc_obj.board[i+8] = wp;
+ lrc_obj.board[i+6*8] = bp;
+ }
+
+ /* assign remaining pieces */
+
+ lrc_obj.board[0] = cp_Construct(COLOR_WHITE, PIECE_ROOK);
+ lrc_obj.board[1] = cp_Construct(COLOR_WHITE, PIECE_KNIGHT);
+ lrc_obj.board[2] = cp_Construct(COLOR_WHITE, PIECE_BISHOP);
+ lrc_obj.board[3] = cp_Construct(COLOR_WHITE, PIECE_QUEEN);
+ lrc_obj.board[4] = cp_Construct(COLOR_WHITE, PIECE_KING);
+ lrc_obj.board[5] = cp_Construct(COLOR_WHITE, PIECE_BISHOP);
+ lrc_obj.board[6] = cp_Construct(COLOR_WHITE, PIECE_KNIGHT);
+ lrc_obj.board[7] = cp_Construct(COLOR_WHITE, PIECE_ROOK);
+
+ lrc_obj.board[0+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK);
+ lrc_obj.board[1+7*8] = cp_Construct(COLOR_BLACK, PIECE_KNIGHT);
+ lrc_obj.board[2+7*8] = cp_Construct(COLOR_BLACK, PIECE_BISHOP);
+ lrc_obj.board[3+7*8] = cp_Construct(COLOR_BLACK, PIECE_QUEEN);
+ lrc_obj.board[4+7*8] = cp_Construct(COLOR_BLACK, PIECE_KING);
+ lrc_obj.board[5+7*8] = cp_Construct(COLOR_BLACK, PIECE_BISHOP);
+ lrc_obj.board[6+7*8] = cp_Construct(COLOR_BLACK, PIECE_KNIGHT);
+ lrc_obj.board[7+7*8] = cp_Construct(COLOR_BLACK, PIECE_ROOK);
+
+ //chess_SetupBoardTest01();
+
+}
+
+
+
+/*==============================================================*/
+/* checks */
+/*==============================================================*/
+
+/*
+ checks if the position is somehow illegal
+*/
+uint8_t cu_IsIllegalPosition(uint8_t pos, uint8_t my_color)
+{
+ uint8_t board_cp;
+ /* check, if the position is offboard */
+ if ( gpos_IsIllegal(pos) != 0 )
+ return 1;
+ /* get the piece from the board */
+ board_cp = cp_GetFromBoard(pos);
+ /* check if hit our own pieces */
+ if ( board_cp != 0 )
+ if ( cp_GetColor(board_cp) == my_color )
+ return 1;
+ /* all ok, we could go to this position */
+ return 0;
+}
+
+/*==============================================================*/
+/* evaluation procedure */
+/*==============================================================*/
+
+/*
+ basic idea is to return a value between EVAL_T_MIN and EVAL_T_MAX
+*/
+
+/*
+ the weight table uses the PIECE number as index:
+ #define PIECE_NONE 0
+ #define PIECE_PAWN 1
+ #define PIECE_KNIGHT 2
+ #define PIECE_BISHOP 3
+ #define PIECE_ROOK 4
+ #define PIECE_QUEEN 5
+ #define PIECE_KING 6
+ the king itself is not counted
+*/
+uint8_t ce_piece_weight[] = { 0, 1, 3, 3, 5, 9, 0 };
+uint8_t ce_pos_weight[] = { 0, 1, 1, 2, 2, 1, 1, 0};
+/*
+ evaluate the current situation on the global board
+*/
+eval_t ce_Eval(void)
+{
+ uint8_t cp;
+ uint8_t is_my_king_present = 0;
+ uint8_t is_opposit_king_present = 0;
+ eval_t material_my_color = 0;
+ eval_t material_opposit_color = 0;
+ eval_t position_my_color = 0;
+ eval_t position_opposit_color = 0;
+ eval_t result;
+ uint8_t pos;
+
+ pos = 0;
+ do
+ {
+ /* get colored piece from the board */
+ cp = cp_GetFromBoard(pos);
+
+ if ( cp_GetPiece(cp) != PIECE_NONE )
+ {
+ if ( stack_GetCurrElement()->current_color == cp_GetColor(cp) )
+ {
+ /* this is our color */
+ /* check if we found our king */
+ if ( cp_GetPiece(cp) == PIECE_KING )
+ is_my_king_present = 1;
+ material_my_color += ce_piece_weight[cp_GetPiece(cp)];
+ if ( cp_GetPiece(cp) == PIECE_PAWN || cp_GetPiece(cp) == PIECE_KNIGHT )
+ {
+ position_my_color += ce_pos_weight[pos&7]*ce_pos_weight[(pos>>4)&7];
+ }
+ }
+ else
+ {
+ /* this is the opposit color */
+ if ( cp_GetPiece(cp) == PIECE_KING )
+ is_opposit_king_present = 1;
+ material_opposit_color += ce_piece_weight[cp_GetPiece(cp)];
+ if ( cp_GetPiece(cp) == PIECE_PAWN || cp_GetPiece(cp) == PIECE_KNIGHT )
+ {
+ position_opposit_color += ce_pos_weight[pos&7]*ce_pos_weight[(pos>>4)&7];
+ }
+ }
+ }
+ pos = cu_NextPos(pos);
+ } while( pos != 0 );
+
+
+ /* decide if we lost or won the game */
+ if ( is_my_king_present == 0 )
+ return EVAL_T_MIN; /*_LOST*/
+ if ( is_opposit_king_present == 0 )
+ return EVAL_T_MAX; /*_WIN*/
+
+ /* here is the evaluation function */
+
+ result = material_my_color - material_opposit_color;
+ result <<= 3;
+ result += position_my_color - position_opposit_color;
+ return result;
+}
+
+/*==============================================================*/
+/* move backup and restore */
+/*==============================================================*/
+
+
+/* this procedure must be called to keep the size as low as possible */
+/* if the chm_list is large enough, it could hold the complete history */
+/* but for an embedded controler... it is deleted for every engine search */
+void cu_ClearMoveHistory(void)
+{
+ lrc_obj.chm_pos = 0;
+}
+
+void cu_ReduceHistoryByFullMove(void)
+{
+ uint8_t i;
+ while( lrc_obj.chm_pos > CHM_USER_SIZE )
+ {
+ i = 0;
+ for(;;)
+ {
+ if ( i+2 >= lrc_obj.chm_pos )
+ break;
+ lrc_obj.chm_list[i] = lrc_obj.chm_list[i+2];
+ i++;
+ }
+ lrc_obj.chm_pos -= 2;
+ }
+}
+
+void cu_UndoHalfMove(void)
+{
+ chm_p chm;
+
+ if ( lrc_obj.chm_pos == 0 )
+ return;
+
+ lrc_obj.chm_pos--;
+
+ chm = lrc_obj.chm_list+lrc_obj.chm_pos;
+
+ lrc_obj.pawn_dbl_move[0] = chm->pawn_dbl_move[0];
+ lrc_obj.pawn_dbl_move[1] = chm->pawn_dbl_move[1];
+ lrc_obj.castling_possible = chm->castling_possible;
+
+ cp_SetOnBoard(chm->main_src, chm->main_cp);
+ cp_SetOnBoard(chm->main_dest, PIECE_NONE);
+
+ if ( chm->other_src != ILLEGAL_POSITION )
+ cp_SetOnBoard(chm->other_src, chm->other_cp);
+ if ( chm->other_dest != ILLEGAL_POSITION )
+ cp_SetOnBoard(chm->other_dest, PIECE_NONE);
+
+}
+
+/*
+ assumes, that the following members of the returned chm structure are filled
+ uint8_t main_cp; the main piece, which is moved
+ uint8_t main_src; the source position of the main piece
+ uint8_t main_dest; the destination of the main piece
+
+ uint8_t other_cp; another piece: the captured one, the ROOK in case of castling or PIECE_NONE
+ uint8_t other_src; the delete position of other_cp. Often identical to main_dest except for e.p. and castling
+ uint8_t other_dest; only used for castling: ROOK destination pos
+
+*/
+chm_p cu_PushHalfMove(void)
+{
+ chm_p chm;
+
+ chm = lrc_obj.chm_list+lrc_obj.chm_pos;
+ if ( lrc_obj.chm_pos < CHM_LIST_SIZE-1)
+ lrc_obj.chm_pos++;
+
+ chm->pawn_dbl_move[0] = lrc_obj.pawn_dbl_move[0];
+ chm->pawn_dbl_move[1] = lrc_obj.pawn_dbl_move[1];
+ chm->castling_possible = lrc_obj.castling_possible;
+ return chm;
+}
+
+
+char chess_piece_to_char[] = "NBRQK";
+
+/*
+ simple moves on empty field: Ka1-b2
+ capture moves: Ka1xb2
+ castling: 0-0 or 0-0-0
+*/
+
+static void cu_add_pos(char *s, uint8_t pos) U8G2_NOINLINE;
+
+static void cu_add_pos(char *s, uint8_t pos)
+{
+ *s = pos;
+ *s &= 15;
+ *s += 'a';
+ s++;
+ *s = pos;
+ *s >>= 4;
+ *s += '1';
+}
+
+const char *cu_GetHalfMoveStr(uint8_t idx)
+{
+ chm_p chm;
+ static char buf[7]; /*Ka1-b2*/
+ char *p = buf;
+ chm = lrc_obj.chm_list+idx;
+
+ if ( cp_GetPiece(chm->main_cp) != PIECE_NONE )
+ {
+ if ( cp_GetPiece(chm->main_cp) > PIECE_PAWN )
+ {
+ *p++ = chess_piece_to_char[cp_GetPiece(chm->main_cp)-2];
+ }
+ cu_add_pos(p, chm->main_src);
+ p+=2;
+ if ( cp_GetPiece(chm->other_cp) == PIECE_NONE )
+ *p++ = '-';
+ else
+ *p++ = 'x';
+ cu_add_pos(p, chm->main_dest);
+ p+=2;
+ }
+ *p = '\0';
+ return buf;
+}
+
+
+
+
+
+/*==============================================================*/
+/* move */
+/*==============================================================*/
+
+/*
+ Move a piece from source position to a destination on the board
+ This function
+ - does not perform any checking
+ - however it processes "en passant" and casteling
+ - backup the move and allow 1x undo
+
+ 2011-02-05:
+ - fill pawn_dbl_move[] for double pawn moves
+ --> done
+ - Implement casteling
+ --> done
+ - en passant
+ --> done
+ - pawn conversion/promotion
+ --> done
+ - half-move backup
+ --> done
+ - cleanup everything, minimize variables
+ --> done
+*/
+
+void cu_Move(uint8_t src, uint8_t dest)
+{
+ /* start backup structure */
+ chm_p chm = cu_PushHalfMove();
+
+ /* these are the values from the board at the positions, provided as arguments to this function */
+ uint8_t cp_src, cp_dest;
+
+ /* Maybe a second position is cleared and one additional location is set */
+ uint8_t clr_pos2;
+ uint8_t set_pos2;
+ uint8_t set_cp2;
+
+ /* get values from board */
+ cp_src = cp_GetFromBoard(src);
+ cp_dest = cp_GetFromBoard(dest);
+
+ /* fill backup structure */
+
+ chm->main_cp = cp_src;
+ chm->main_src = src;
+ chm->main_dest = dest;
+
+ chm->other_cp = cp_dest; /* prepace capture backup */
+ chm->other_src = dest;
+ chm->other_dest = ILLEGAL_POSITION;
+
+ /* setup results as far as possible with some suitable values */
+
+ clr_pos2 = ILLEGAL_POSITION; /* for en passant and castling, two positions might be cleared */
+ set_pos2 = ILLEGAL_POSITION; /* only used for castling */
+ set_cp2 = PIECE_NONE; /* ROOK for castling */
+
+ /* check for PAWN */
+ if ( cp_GetPiece(cp_src) == PIECE_PAWN )
+ {
+
+ /* double step: is the distance 2 rows */
+ if ( (src - dest == 32) || ( dest - src == 32 ) )
+ {
+ /* remember the destination position */
+ lrc_obj.pawn_dbl_move[cp_GetColor(cp_src)] = dest;
+ }
+
+ /* check if the PAWN is able to promote */
+ else if ( (dest>>4) == 0 || (dest>>4) == 7 )
+ {
+ /* do simple "queening" */
+ cp_src &= ~PIECE_PAWN;
+ cp_src |= PIECE_QUEEN;
+ }
+
+ /* is it en passant capture? */
+ /* check for side move */
+ else if ( ((src + dest) & 1) != 0 )
+ {
+ /* check, if target field is empty */
+ if ( cp_GetPiece(cp_dest) == PIECE_NONE )
+ {
+ /* this is en passant */
+ /* no further checking required, because legal moves are assumed here */
+ /* however... the captured pawn position must be valid */
+ clr_pos2 = lrc_obj.pawn_dbl_move[cp_GetColor(cp_src) ^ 1];
+ chm->other_src = clr_pos2;
+ chm->other_cp = cp_GetFromBoard(clr_pos2);
+ }
+ }
+ }
+
+ /* check for the KING */
+ else if ( cp_GetPiece(cp_src) == PIECE_KING )
+ {
+ /* disallow castling, if the KING has moved */
+ if ( cp_GetColor(cp_src) == COLOR_WHITE )
+ {
+ /* if white KING has moved, disallow castling for white */
+ lrc_obj.castling_possible &= 0x0c;
+ }
+ else
+ {
+ /* if black KING has moved, disallow castling for black */
+ lrc_obj.castling_possible &= 0x03;
+ }
+
+ /* has it been castling to the left? */
+ if ( src - dest == 2 )
+ {
+ /* let the ROOK move to pos2 */
+ set_pos2 = src-1;
+ set_cp2 = cp_GetFromBoard(src-4);
+
+ /* the ROOK must be cleared from the original position */
+ clr_pos2 = src-4;
+
+ chm->other_cp = set_cp2;
+ chm->other_src = clr_pos2;
+ chm->other_dest = set_pos2;
+ }
+
+ /* has it been castling to the right? */
+ else if ( dest - src == 2 )
+ {
+ /* let the ROOK move to pos2 */
+ set_pos2 = src+1;
+ set_cp2 = cp_GetFromBoard(src+3);
+
+ /* the ROOK must be cleared from the original position */
+ clr_pos2 = src+3;
+
+ chm->other_cp = set_cp2;
+ chm->other_src = clr_pos2;
+ chm->other_dest = set_pos2;
+
+ }
+
+ }
+
+ /* check for the ROOK */
+ else if ( cp_GetPiece(cp_src) == PIECE_ROOK )
+ {
+ /* disallow white left castling */
+ if ( src == 0x00 )
+ lrc_obj.castling_possible &= ~0x01;
+ /* disallow white right castling */
+ if ( src == 0x07 )
+ lrc_obj.castling_possible &= ~0x02;
+ /* disallow black left castling */
+ if ( src == 0x70 )
+ lrc_obj.castling_possible &= ~0x04;
+ /* disallow black right castling */
+ if ( src == 0x77 )
+ lrc_obj.castling_possible &= ~0x08;
+ }
+
+
+ /* apply new board situation */
+
+ cp_SetOnBoard(dest, cp_src);
+
+ if ( set_pos2 != ILLEGAL_POSITION )
+ cp_SetOnBoard(set_pos2, set_cp2);
+
+ cp_SetOnBoard(src, PIECE_NONE);
+
+ if ( clr_pos2 != ILLEGAL_POSITION )
+ cp_SetOnBoard(clr_pos2, PIECE_NONE);
+
+
+}
+
+/*
+ this subprocedure decides for evaluation of the current board situation or further (deeper) investigation
+ Argument pos is the new target position if the current piece
+
+*/
+uint8_t ce_LoopRecur(uint8_t pos)
+{
+ eval_t eval;
+
+ /* 1. check if target position is occupied by the same player (my_color) */
+ /* of if pos is somehow illegal or not valid */
+ if ( cu_IsIllegalPosition(pos, stack_GetCurrElement()->current_color) != 0 )
+ return 0;
+
+ /* 2. move piece to the specified position, capture opponent piece if required */
+ cu_Move(stack_GetCurrElement()->current_pos, pos);
+
+
+ /* 3. */
+ /* if depth reached: evaluate */
+ /* else: go down next level */
+ /* no eval if there had been any valid half-moves, so the default value (MIN) will be returned. */
+ if ( stack_Push(stack_GetCurrElement()->current_color) == 0 )
+ {
+ eval = ce_Eval();
+ }
+ else
+ {
+ /* init the element, which has been pushed */
+ stack_InitCurrElement();
+ /* start over with ntext level */
+ ce_LoopPieces();
+ /* get the best move from opponents view, so invert the result */
+ eval = -stack_GetCurrElement()->best_eval;
+ stack_Pop();
+ }
+
+ /* 4. store result */
+ stack_SetMove(eval, pos);
+
+ /* 5. undo the move */
+ cu_UndoHalfMove();
+
+ /* 6. check special modes */
+ /* the purpose of these checks is to mark special pieces and positions on the board */
+ /* these marks can be checked by the user interface to highlight special positions */
+ if ( lrc_obj.check_mode != 0 )
+ {
+ stack_element_p e = stack_GetCurrElement();
+ if ( lrc_obj.check_mode == CHECK_MODE_MOVEABLE )
+ {
+ cp_SetOnBoard(e->current_pos, e->current_cp | CP_MARK_MASK );
+ }
+ else if ( lrc_obj.check_mode == CHECK_MODE_TARGET_MOVE )
+ {
+ if ( e->current_pos == lrc_obj.check_src_pos )
+ {
+ cp_SetOnBoard(pos, cp_GetFromBoard(pos) | CP_MARK_MASK );
+ }
+ }
+ }
+ return 1;
+}
+
+/*==============================================================*/
+/* move pieces which can move one or more steps into a direction */
+/*==============================================================*/
+
+/*
+ subprocedure to generate various target positions for some pieces
+ special cases are handled in the piece specific sub-procedure
+
+ Arguments:
+ d: a list of potential directions
+ is_multi_step: if the piece can only do one step (zero for KING and KNIGHT)
+*/
+static const uint8_t ce_dir_offset_rook[] CHESS_PROGMEM = { 1, 16, (uint8_t)-16, (uint8_t)-1, 0 };
+static const uint8_t ce_dir_offset_bishop[] CHESS_PROGMEM = { 15, 17, (uint8_t)-17, (uint8_t)-15, 0 };
+static const uint8_t ce_dir_offset_queen[] CHESS_PROGMEM = { 1, 16, (uint8_t)-16, (uint8_t)-1, 15, 17, (uint8_t)-17, (uint8_t)-15, 0 };
+static const uint8_t ce_dir_offset_knight[] CHESS_PROGMEM = {14, (uint8_t)-14, 18, (uint8_t)-18, 31, (uint8_t)-31, 33, (uint8_t)-33, 0};
+
+void ce_LoopDirsSingleMultiStep(const uint8_t *d, uint8_t is_multi_step)
+{
+ uint8_t loop_pos;
+
+ /* with all directions */
+ for(;;)
+ {
+ if ( chess_pgm_read(d) == 0 )
+ break;
+
+ /* start again from the initial position */
+ loop_pos = stack_GetCurrElement()->current_pos;
+
+ /* check direction */
+ do
+ {
+ /* check next position into one direction */
+ loop_pos += chess_pgm_read(d);
+
+ /*
+ go further to ce_LoopRecur()
+ 0 will be returned if the target position is illegal or a piece of the own color
+ this is used to stop walking into one direction
+ */
+ if ( ce_LoopRecur(loop_pos) == 0 )
+ break;
+
+ /* stop if we had hit another piece */
+ if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) != PIECE_NONE )
+ break;
+ } while( is_multi_step );
+ d++;
+ }
+}
+
+void ce_LoopRook(void)
+{
+ ce_LoopDirsSingleMultiStep(ce_dir_offset_rook, 1);
+}
+
+void ce_LoopBishop(void)
+{
+ ce_LoopDirsSingleMultiStep(ce_dir_offset_bishop, 1);
+}
+
+void ce_LoopQueen(void)
+{
+ ce_LoopDirsSingleMultiStep(ce_dir_offset_queen, 1);
+}
+
+void ce_LoopKnight(void)
+{
+ ce_LoopDirsSingleMultiStep(ce_dir_offset_knight, 0);
+}
+
+
+
+/*==============================================================*/
+/* move king */
+/*==============================================================*/
+
+uint8_t cu_IsKingCastling(uint8_t mask, int8_t direction, uint8_t cnt) U8G2_NOINLINE;
+
+/*
+ checks, if the king can do castling
+
+ Arguments:
+ mask: the bit-mask for the global "castling possible" flag
+ direction: left castling: -1, right castling 1
+ cnt: number of fields to be checked: 3 or 2
+*/
+uint8_t cu_IsKingCastling(uint8_t mask, int8_t direction, uint8_t cnt)
+{
+ uint8_t pos;
+ uint8_t opponent_color;
+
+ /* check if the current board state allows castling */
+ if ( (lrc_obj.castling_possible & mask) == 0 )
+ return 0; /* castling not allowed */
+
+ /* get the position of the KING, could be white or black king */
+ pos = stack_GetCurrElement()->current_pos;
+
+ /* calculate the color of the opponent */
+ opponent_color = 1;
+ opponent_color -= stack_GetCurrElement()->current_color;
+
+ /* if the KING itself is given check... */
+ if ( ce_GetPositionAttackWeight(pos, opponent_color) > 0 )
+ return 0;
+
+
+ /* check if fields in the desired direction are emtpy */
+ for(;;)
+ {
+ /* go to the next field */
+ pos += direction;
+ /* check for a piece */
+ if ( cp_GetPiece(cp_GetFromBoard(pos)) != PIECE_NONE )
+ return 0; /* castling not allowed */
+
+ /* if some of the fields are under attack */
+ if ( ce_GetPositionAttackWeight(pos, opponent_color) > 0 )
+ return 0;
+
+ cnt--;
+ if ( cnt == 0 )
+ break;
+ }
+ return 1; /* castling allowed */
+}
+
+void ce_LoopKing(void)
+{
+ /*
+ there is an interessting timing problem in this procedure
+ it must be checked for castling first and as second step the normal
+ KING movement. If we would first check for normal moves, than
+ any marks might be overwritten by the ROOK in the case of castling.
+ */
+
+ /* castling (this must be done before checking normal moves (see above) */
+ if ( stack_GetCurrElement()->current_color == COLOR_WHITE )
+ {
+ /* white left castling */
+ if ( cu_IsKingCastling(1, -1, 3) != 0 )
+ {
+ /* check for attacked fields */
+ ce_LoopRecur(stack_GetCurrElement()->current_pos-2);
+ }
+ /* white right castling */
+ if ( cu_IsKingCastling(2, 1, 2) != 0 )
+ {
+ /* check for attacked fields */
+ ce_LoopRecur(stack_GetCurrElement()->current_pos+2);
+ }
+ }
+ else
+ {
+ /* black left castling */
+ if ( cu_IsKingCastling(4, -1, 3) != 0 )
+ {
+ /* check for attacked fields */
+ ce_LoopRecur(stack_GetCurrElement()->current_pos-2);
+ }
+ /* black right castling */
+ if ( cu_IsKingCastling(8, 1, 2) != 0 )
+ {
+ /* check for attacked fields */
+ ce_LoopRecur(stack_GetCurrElement()->current_pos+2);
+ }
+ }
+
+ /* reuse queen directions */
+ ce_LoopDirsSingleMultiStep(ce_dir_offset_queen, 0);
+}
+
+
+/*==============================================================*/
+/* move pawn */
+/*==============================================================*/
+
+/*
+ doppelschritt: nur von der grundlinie aus, beide (!) felder vor dem bauern m�ssen frei sein
+ en passant: nur unmittelbar nachdem ein doppelschritt ausgef�hrt wurde.
+*/
+void ce_LoopPawnSideCapture(uint8_t loop_pos)
+{
+ if ( gpos_IsIllegal(loop_pos) == 0 )
+ {
+ /* get the piece from the board */
+ /* if the field is NOT empty */
+ if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) != PIECE_NONE )
+ {
+ /* normal capture */
+ ce_LoopRecur(loop_pos);
+ /* TODO: check for pawn conversion/promotion */
+ }
+ else
+ {
+ /* check conditions for en passant capture */
+ if ( stack_GetCurrElement()->current_color == COLOR_WHITE )
+ {
+ if ( lrc_obj.pawn_dbl_move[COLOR_BLACK]+16 == loop_pos )
+ {
+ ce_LoopRecur(loop_pos);
+ /* note: pawn conversion/promotion can not occur */
+ }
+ }
+ else
+ {
+ if ( lrc_obj.pawn_dbl_move[COLOR_WHITE] == loop_pos+16 )
+ {
+ ce_LoopRecur(loop_pos);
+ /* note: pawn conversion/promotion can not occur */
+ }
+ }
+ }
+ }
+}
+
+void ce_LoopPawn(void)
+{
+ uint8_t initial_pos = stack_GetCurrElement()->current_pos;
+ uint8_t my_color = stack_GetCurrElement()->current_color;
+
+ uint8_t loop_pos;
+ uint8_t line;
+
+ /* one step forward */
+
+ loop_pos = initial_pos;
+ line = initial_pos;
+ line >>= 4;
+ if ( my_color == COLOR_WHITE )
+ loop_pos += 16;
+ else
+ loop_pos -= 16;
+ if ( gpos_IsIllegal(loop_pos) == 0 )
+ {
+ /* if the field is empty */
+ if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) == PIECE_NONE )
+ {
+ /* TODO: check for and loop through piece conversion/promotion */
+ ce_LoopRecur(loop_pos);
+
+ /* second step forward */
+
+ /* if pawn is on his starting line */
+ if ( (my_color == COLOR_WHITE && line == 1) || (my_color == COLOR_BLACK && line == 6 ) )
+ {
+ /* the place before the pawn is not occupied, so we can do double moves, see above */
+
+ if ( my_color == COLOR_WHITE )
+ loop_pos += 16;
+ else
+ loop_pos -= 16;
+ if ( cp_GetPiece(cp_GetFromBoard(loop_pos)) == PIECE_NONE )
+ {
+ /* this is a special case, other promotions of the pawn can not occur */
+ ce_LoopRecur(loop_pos);
+ }
+ }
+ }
+ }
+
+ /* capture */
+
+ loop_pos = initial_pos;
+ if ( my_color == COLOR_WHITE )
+ loop_pos += 15;
+ else
+ loop_pos -= 15;
+ ce_LoopPawnSideCapture(loop_pos);
+
+
+ loop_pos = initial_pos;
+ if ( my_color == COLOR_WHITE )
+ loop_pos += 17;
+ else
+ loop_pos -= 17;
+ ce_LoopPawnSideCapture(loop_pos);
+}
+
+/*==============================================================*/
+/* attacked */
+/*==============================================================*/
+
+/*
+ from a starting position, search for a piece, that might jump to that postion.
+ return:
+ the two global variables
+ lrc_obj.find_piece_weight[0];
+ lrc_obj.find_piece_weight[1];
+ will be increased by the weight of the attacked pieces of that color.
+ it is usually required to reset these global variables to zero, before using
+ this function.
+*/
+
+void ce_FindPieceByStep(uint8_t start_pos, uint8_t piece, const uint8_t *d, uint8_t is_multi_step)
+{
+ uint8_t loop_pos, cp;
+
+ /* with all directions */
+ for(;;)
+ {
+ if ( chess_pgm_read(d) == 0 )
+ break;
+
+ /* start again from the initial position */
+ loop_pos = start_pos;
+
+ /* check direction */
+ do
+ {
+ /* check next position into one direction */
+ loop_pos += chess_pgm_read(d);
+
+ /* check if the board boundary has been crossed */
+ if ( (loop_pos & 0x088) != 0 )
+ break;
+
+ /* get the colored piece from the board */
+ cp = cp_GetFromBoard(loop_pos);
+
+ /* stop if we had hit another piece */
+ if ( cp_GetPiece(cp) != PIECE_NONE )
+ {
+ /* if it is the piece we are looking for, then add the weight */
+ if ( cp_GetPiece(cp) == piece )
+ {
+ lrc_obj.find_piece_weight[cp_GetColor(cp)] += ce_piece_weight[piece];
+ lrc_obj.find_piece_cnt[cp_GetColor(cp)]++;
+ }
+ /* in any case, break out of the inner loop */
+ break;
+ }
+ } while( is_multi_step );
+ d++;
+ }
+}
+
+void ce_FindPawnPiece(uint8_t dest_pos, uint8_t color)
+{
+ uint8_t cp;
+ /* check if the board boundary has been crossed */
+ if ( (dest_pos & 0x088) == 0 )
+ {
+ /* get the colored piece from the board */
+ cp = cp_GetFromBoard(dest_pos);
+ /* only if there is a pawn of the matching color */
+ if ( cp_GetPiece(cp) == PIECE_PAWN )
+ {
+ if ( cp_GetColor(cp) == color )
+ {
+ /* the weight of the PAWN */
+ lrc_obj.find_piece_weight[color] += 1;
+ lrc_obj.find_piece_cnt[color]++;
+ }
+ }
+ }
+}
+
+
+/*
+ find out, which pieces do attack a specified field
+ used to
+ - check if the KING can do castling
+ - check if the KING must move
+
+ may be used in the eval procedure ... once...
+
+ the result is stored in the global array
+ uint8_t lrc_obj.find_piece_weight[2];
+ which is indexed with the color.
+ lrc_obj.find_piece_weight[COLOR_WHITE] is the sum of all white pieces
+ which can directly move to this field.
+
+ example:
+ if the black KING is at "pos" and lrc_obj.find_piece_weight[COLOR_WHITE] is not zero
+ (after executing ce_CalculatePositionWeight(pos)) then the KING must be protected or moveed, because
+ the KING was given check.
+*/
+
+void ce_CalculatePositionWeight(uint8_t pos)
+{
+
+ lrc_obj.find_piece_weight[0] = 0;
+ lrc_obj.find_piece_weight[1] = 0;
+ lrc_obj.find_piece_cnt[0] = 0;
+ lrc_obj.find_piece_cnt[1] = 0;
+
+ if ( (pos & 0x088) != 0 )
+ return;
+
+ ce_FindPieceByStep(pos, PIECE_ROOK, ce_dir_offset_rook, 1);
+ ce_FindPieceByStep(pos, PIECE_BISHOP, ce_dir_offset_bishop, 1);
+ ce_FindPieceByStep(pos, PIECE_QUEEN, ce_dir_offset_queen, 1);
+ ce_FindPieceByStep(pos, PIECE_KNIGHT, ce_dir_offset_knight, 0);
+ ce_FindPieceByStep(pos, PIECE_KING, ce_dir_offset_queen, 0);
+
+ ce_FindPawnPiece(pos+17, COLOR_BLACK);
+ ce_FindPawnPiece(pos+15, COLOR_BLACK);
+ ce_FindPawnPiece(pos-17, COLOR_WHITE);
+ ce_FindPawnPiece(pos-15, COLOR_WHITE);
+}
+
+/*
+ calculate the summed weight of pieces with specified color which can move to a specified position
+
+ argument:
+ pos: the position which should be analysed
+ color: the color of those pieces which should be analysed
+ e.g. if a black piece is at 'pos' and 'color' is white then this procedure returns the white atting count
+*/
+uint8_t ce_GetPositionAttackWeight(uint8_t pos, uint8_t color)
+{
+ ce_CalculatePositionWeight(pos);
+ return lrc_obj.find_piece_weight[color];
+}
+
+uint8_t ce_GetPositionAttackCount(uint8_t pos, uint8_t color)
+{
+ ce_CalculatePositionWeight(pos);
+ return lrc_obj.find_piece_cnt[color];
+}
+
+
+/*==============================================================*/
+/* depth search starts here: loop over all pieces of the current color on the board */
+/*==============================================================*/
+
+void ce_LoopPieces(void)
+{
+ stack_element_p e = stack_GetCurrElement();
+ /* start with lower left position (A1) */
+ e->current_pos = 0;
+ do
+ {
+ e->current_cp = cp_GetFromBoard(e->current_pos);
+ /* check if the position on the board is empty */
+ if ( e->current_cp != 0 )
+ {
+ /* only generate moves for the current color */
+ if ( e->current_color == cp_GetColor(e->current_cp) )
+ {
+ chess_Thinking();
+
+ /* find out which piece is used */
+ switch(cp_GetPiece(e->current_cp))
+ {
+ case PIECE_NONE:
+ break;
+ case PIECE_PAWN:
+ ce_LoopPawn();
+ break;
+ case PIECE_KNIGHT:
+ ce_LoopKnight();
+ break;
+ case PIECE_BISHOP:
+ ce_LoopBishop();
+ break;
+ case PIECE_ROOK:
+ ce_LoopRook();
+ break;
+ case PIECE_QUEEN:
+ ce_LoopQueen();
+ break;
+ case PIECE_KING:
+ ce_LoopKing();
+ break;
+ }
+ }
+ }
+ e->current_pos = cu_NextPos(e->current_pos);
+ } while( e->current_pos != 0 );
+}
+
+/*==============================================================*/
+/* user interface */
+/*==============================================================*/
+
+/*
+eval_t chess_EvalCurrBoard(uint8_t color)
+{
+ stack_Init(0);
+ stack_GetCurrElement()->current_color = color;
+ ce_LoopPieces();
+ return stack_GetCurrElement()->best_eval;
+}
+*/
+
+/* clear any marks on the board */
+void chess_ClearMarks(void)
+{
+ uint8_t i;
+ for( i = 0; i < 64; i++ )
+ lrc_obj.board[i] &= ~CP_MARK_MASK;
+}
+
+/*
+ Mark all pieces which can do moves. This is done by setting flags on the global board
+*/
+void chess_MarkMovable(void)
+{
+ stack_Init(0);
+ //stack_GetCurrElement()->current_color = color;
+ lrc_obj.check_mode = CHECK_MODE_MOVEABLE;
+ ce_LoopPieces();
+}
+
+/*
+ Checks, if the piece can move from src_pos to dest_pos
+
+ src_pos: The game position of a piece on the chess board
+*/
+void chess_MarkTargetMoves(uint8_t src_pos)
+{
+ stack_Init(0);
+ stack_GetCurrElement()->current_color = cp_GetColor(cp_GetFromBoard(src_pos));
+ lrc_obj.check_src_pos = src_pos;
+ lrc_obj.check_mode = CHECK_MODE_TARGET_MOVE;
+ ce_LoopPieces();
+}
+
+/*
+ first call should start with 255
+ this procedure will return 255 if
+ - there are no marks at all
+ - it has looped over all marks once
+*/
+uint8_t chess_GetNextMarked(uint8_t arg, uint8_t is_prev)
+{
+ uint8_t i;
+ uint8_t pos = arg;
+ for(i = 0; i < 64; i++)
+ {
+ if ( is_prev != 0 )
+ pos = cu_PrevPos(pos);
+ else
+ pos = cu_NextPos(pos);
+ if ( arg != 255 && pos == 0 )
+ return 255;
+ if ( cp_IsMarked(cp_GetFromBoard(pos)) )
+ return pos;
+ }
+ return 255;
+}
+
+
+/* make a manual move: this is a little bit more than cu_Move() */
+void chess_ManualMove(uint8_t src, uint8_t dest)
+{
+ uint8_t cp;
+
+ /* printf("chess_ManualMove %02x -> %02x\n", src, dest); */
+
+ /* if all other things fail, this is the place where the game is to be decided: */
+ /* ... if the KING is captured */
+ cp = cp_GetFromBoard(dest);
+ if ( cp_GetPiece(cp) == PIECE_KING )
+ {
+ lrc_obj.is_game_end = 1;
+ lrc_obj.lost_side_color = cp_GetColor(cp);
+ }
+
+ /* clear ply history here, to avoid memory overflow */
+ /* may be the last X moves can be kept here */
+ cu_ReduceHistoryByFullMove();
+ /* perform the move on the board */
+ cu_Move(src, dest);
+
+ /* update en passant double move positions: en passant position is removed after two half moves */
+ lrc_obj.pawn_dbl_move[lrc_obj.ply_count&1] = ILLEGAL_POSITION;
+
+ /* update the global half move counter */
+ lrc_obj.ply_count++;
+
+
+ /* make a small check about the end of the game */
+ /* use at least depth 1, because we must know if the king can still move */
+ /* this is: King moves at level 0 and will be captured at level 1 */
+ /* so we check if the king can move and will not be captured at search level 1 */
+
+ stack_Init(1);
+ ce_LoopPieces();
+
+ /* printf("chess_ManualMove/analysis best_from_pos %02x -> best_to_pos %02x\n", stack_GetCurrElement()->best_from_pos, stack_GetCurrElement()->best_to_pos); */
+
+ /* analyse the eval result */
+
+ /* check if the other player has any moves left */
+ if ( stack_GetCurrElement()->best_from_pos == ILLEGAL_POSITION )
+ {
+ uint8_t color;
+ /* conditions: */
+ /* 1. no King, should never happen, opposite color has won */
+ /* this is already checked above at the beginning if this procedure */
+ /* 2. King is under attack, opposite color has won */
+ /* 3. King is not under attack, game is a draw */
+
+ uint8_t i = 0;
+ color = lrc_obj.ply_count;
+ color &= 1;
+ do
+ {
+ cp = cp_GetFromBoard(i);
+ /* look for the King */
+ if ( cp_GetPiece(cp) == PIECE_KING )
+ {
+ if ( cp_GetColor(cp) == color )
+ {
+ /* check if KING is attacked */
+ if ( ce_GetPositionAttackCount(i, color^1) != 0 )
+ {
+ /* KING is under attack (check) and can not move: Game is lost */
+ lrc_obj.is_game_end = 1;
+ lrc_obj.lost_side_color = color;
+ }
+ else
+ {
+ /* KING is NOT under attack (check) but can not move: Game is a draw */
+ lrc_obj.is_game_end = 1;
+ lrc_obj.lost_side_color = 2;
+ }
+ /* break out of the loop */
+ break;
+ }
+ }
+ i = cu_NextPos(i);
+ } while( i != 0 );
+ }
+}
+
+/* let the computer do a move */
+void chess_ComputerMove(uint8_t depth)
+{
+ stack_Init(depth);
+
+ //stack_GetCurrElement()->current_color = lrc_obj.ply_count;
+ //stack_GetCurrElement()->current_color &= 1;
+
+ cu_ReduceHistoryByFullMove();
+ ce_LoopPieces();
+
+ chess_ManualMove(stack_GetCurrElement()->best_from_pos, stack_GetCurrElement()->best_to_pos);
+}
+
+
+/*==============================================================*/
+/* unix code */
+/*==============================================================*/
+
+#ifdef UNIX_MAIN
+
+#else
+
+/*==============================================================*/
+/* display menu */
+/*==============================================================*/
+
+extern const uint8_t chess_pieces_body_bm[] CHESS_PROGMEM; // forward decl
+extern const uint8_t chess_black_pieces_bm[] CHESS_PROGMEM; // forward decl
+
+// uint8_t chess_key_code = 0; // obsolete, u8g2 does proper debouncing
+uint8_t chess_key_cmd = 0;
+#define CHESS_STATE_MENU 0
+#define CHESS_STATE_SELECT_START 1
+#define CHESS_STATE_SELECT_PIECE 2
+#define CHESS_STATE_SELECT_TARGET_POS 3
+#define CHESS_STATE_THINKING 4
+#define CHESS_STATE_GAME_END 5
+uint8_t chess_state = CHESS_STATE_MENU;
+uint8_t chess_source_pos = 255;
+uint8_t chess_target_pos = 255;
+
+#define MNU_FONT u8g2_font_5x8_tr
+#define MNU_ENTRY_HEIGHT 9
+
+const char *mnu_title = "Little Rook Chess";
+const char *mnu_list[] = { "New Game (White)", "New Game (Black)", "Undo Move", "Return" };
+uint8_t mnu_pos = 0;
+uint8_t mnu_max = 4;
+
+void mnu_DrawHome(uint8_t is_highlight)
+{
+ uint8_t x = lrc_u8g->width - 35;
+ uint8_t y = (lrc_u8g->height-1);
+ uint8_t t;
+
+ u8g2_SetFont(lrc_u8g, u8g2_font_5x7_tr);
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ if ( chess_state == CHESS_STATE_THINKING )
+ u8g2_DrawBitmap(lrc_u8g, x, y-8, 1, 8, chess_black_pieces_bm+24);
+ else
+ {
+ t = u8g2_DrawStrP(lrc_u8g, x, y -1, CHESS_PSTR("Options"));
+
+ if ( is_highlight )
+ u8g2_DrawFrame(lrc_u8g, x-1, y - MNU_ENTRY_HEIGHT +1, t, MNU_ENTRY_HEIGHT);
+ }
+}
+
+void mnu_DrawEntry(uint8_t y, const char *str, uint8_t is_clr_background, uint8_t is_highlight)
+{
+ uint8_t t, x;
+ u8g2_SetFont(lrc_u8g, MNU_FONT);
+ t = u8g2_GetStrWidth(lrc_u8g, str);
+ x = u8g2_GetDisplayWidth(lrc_u8g);
+ x -= t;
+ x >>= 1;
+
+ if ( is_clr_background )
+ {
+ u8g2_SetDefaultBackgroundColor(lrc_u8g);
+ u8g2_DrawBox(lrc_u8g, x-3, (lrc_u8g->height-1) - (y+MNU_ENTRY_HEIGHT-1+2), t+5, MNU_ENTRY_HEIGHT+4);
+ }
+
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ u8g2_DrawStr(lrc_u8g, x, (lrc_u8g->height-1) - y, str);
+
+ if ( is_highlight )
+ {
+ u8g2_DrawFrame(lrc_u8g, 0, (lrc_u8g->height-1) - y -MNU_ENTRY_HEIGHT +1, u8g2_GetDisplayWidth(lrc_u8g), MNU_ENTRY_HEIGHT);
+ }
+}
+
+void mnu_Draw(void)
+{
+ uint8_t i;
+ uint8_t t,y;
+ /* calculate hight of the complete menu */
+ y = mnu_max;
+ y++; /* consider also some space for the title */
+ y++; /* consider also some space for the title */
+ y *= MNU_ENTRY_HEIGHT;
+
+ /* calculate how much space will be left */
+ t = u8g2_GetDisplayHeight(lrc_u8g);
+ t -= y;
+
+ /* topmost pos start half of that empty space from the top */
+ t >>= 1;
+ y = u8g2_GetDisplayHeight(lrc_u8g);
+ y -= t;
+
+ y -= MNU_ENTRY_HEIGHT;
+ mnu_DrawEntry(y, mnu_title, 0, 0);
+
+ y -= MNU_ENTRY_HEIGHT;
+
+
+ u8g2_DrawBitmap(lrc_u8g, 0, 1, 1, 8, chess_black_pieces_bm+24);
+ u8g2_DrawBitmap(lrc_u8g, 128-8, 1, 1, 8, chess_black_pieces_bm+24);
+
+
+ for( i = 0; i < mnu_max; i++ )
+ {
+ y -= MNU_ENTRY_HEIGHT;
+ mnu_DrawEntry(y, mnu_list[i], 0, i == mnu_pos);
+ }
+}
+
+void mnu_Step(uint8_t key_cmd)
+{
+ if ( key_cmd == CHESS_KEY_NEXT )
+ {
+ if ( mnu_pos+1 < mnu_max )
+ mnu_pos++;
+ }
+ else if ( key_cmd == CHESS_KEY_PREV )
+ {
+ if ( mnu_pos > 0 )
+ mnu_pos--;
+ }
+}
+
+
+
+
+
+
+
+const uint8_t chess_pieces_body_bm[] CHESS_PROGMEM =
+{
+ /* PAWN */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, */
+ /* KNIGHT */ 0x00, 0x00, 0x1c, 0x2c, 0x04, 0x04, 0x0e, 0x00,
+ /* BISHOP */ 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0x08, 0x00, 0x00, /* 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x08, 0x00, 0x00, */
+ /* ROOK */ 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0x1c, 0x00,
+ /* QUEEN */ 0x00, 0x00, 0x14, 0x1c, 0x08, 0x1c, 0x08, 0x00,
+ /* KING */ 0x00, 0x00, 0x00, 0x08, 0x3e, 0x1c, 0x08, 0x00,
+};
+
+#ifdef NOT_REQUIRED
+/* white pieces are constructed by painting black pieces and cutting out the white area */
+const uint8_t chess_white_pieces_bm[] CHESS_PROGMEM =
+{
+ /* PAWN */ 0x00, 0x00, 0x0c, 0x12, 0x12, 0x0c, 0x1e, 0x00,
+ /* KNIGHT */ 0x00, 0x1c, 0x22, 0x52, 0x6a, 0x0a, 0x11, 0x1f,
+ /* BISHOP */ 0x00, 0x08, 0x14, 0x22, 0x22, 0x14, 0x08, 0x7f,
+ /* ROOK */ 0x00, 0x55, 0x7f, 0x22, 0x22, 0x22, 0x22, 0x7f,
+ /* QUEEN */ 0x00, 0x55, 0x2a, 0x22, 0x14, 0x22, 0x14, 0x7f,
+ /* KING */ 0x08, 0x1c, 0x49, 0x77, 0x41, 0x22, 0x14, 0x7f,
+};
+#endif
+
+const uint8_t chess_black_pieces_bm[] CHESS_PROGMEM =
+{
+ /* PAWN */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x3c, 0x00, /* 0x00, 0x00, 0x0c, 0x1e, 0x1e, 0x0c, 0x1e, 0x00, */
+ /* KNIGHT */ 0x00, 0x1c, 0x3e, 0x7e, 0x6e, 0x0e, 0x1f, 0x1f,
+ /* BISHOP */ 0x00, 0x1c, 0x2e, 0x3e, 0x3e, 0x1c, 0x08, 0x7f, /*0x00, 0x08, 0x1c, 0x3e, 0x3e, 0x1c, 0x08, 0x7f,*/
+ /* ROOK */ 0x00, 0x55, 0x7f, 0x3e, 0x3e, 0x3e, 0x3e, 0x7f,
+ /* QUEEN */ 0x00, 0x55, 0x3e, 0x3e, 0x1c, 0x3e, 0x1c, 0x7f,
+ /* KING -*/ 0x08, 0x1c, 0x49, 0x7f, 0x7f, 0x3e, 0x1c, 0x7f,
+};
+
+
+#if defined(DOGXL160_HW_GR)
+#define BOXSIZE 13
+#define BOXOFFSET 3
+#else
+#define BOXSIZE 8
+#define BOXOFFSET 1
+#endif
+
+u8g2_uint_t chess_low_edge;
+uint8_t chess_boxsize = 8;
+uint8_t chess_boxoffset = 1;
+
+
+void chess_DrawFrame(uint8_t pos, uint8_t is_bold)
+{
+ u8g2_uint_t x0, y0;
+
+ x0 = pos;
+ x0 &= 15;
+ if ( lrc_obj.orientation != COLOR_WHITE )
+ x0 ^= 7;
+
+ y0 = pos;
+ y0>>= 4;
+ if ( lrc_obj.orientation != COLOR_WHITE )
+ y0 ^= 7;
+
+ x0 *= chess_boxsize;
+ y0 *= chess_boxsize;
+
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ u8g2_DrawFrame(lrc_u8g, x0, chess_low_edge - y0 - chess_boxsize+1, chess_boxsize, chess_boxsize);
+
+
+ if ( is_bold )
+ {
+ x0--;
+ y0++;
+
+ u8g2_DrawFrame(lrc_u8g, x0, chess_low_edge - y0 - chess_boxsize +1, chess_boxsize+2, chess_boxsize+2);
+ }
+}
+
+
+void chess_DrawBoard(void)
+{
+ uint8_t i, j, cp;
+ const uint8_t *ptr; /* pointer into CHESS_PROGMEM */
+
+ {
+ uint8_t x_offset = 1;
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ for( i = 0; i < 8*8; i+=8 )
+ {
+ for( j = 0; j < 8*8; j+=8 )
+ {
+ if ( ((i^j) & 8) == 0 )
+ {
+ if ( lrc_obj.orientation == COLOR_WHITE )
+ {
+ cp = lrc_obj.board[i+j/8];
+ }
+ else
+ {
+ cp = lrc_obj.board[(7-i/8)*8+7-j/8];
+ }
+ if ( cp_GetPiece(cp) == PIECE_NONE )
+ {
+ u8g2_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-0);
+ u8g2_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-2);
+ u8g2_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-4);
+ u8g2_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-6);
+ u8g2_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-0);
+ u8g2_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-6);
+ u8g2_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-0);
+ u8g2_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-6);
+ u8g2_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-0);
+ u8g2_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-2);
+ u8g2_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-4);
+ u8g2_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-6);
+ }
+ }
+ }
+ }
+ }
+
+ for ( i = 0; i < 8; i++ )
+ {
+ for ( j = 0; j < 8; j++ )
+ {
+ /* get piece from global board */
+ if ( lrc_obj.orientation == COLOR_WHITE )
+ {
+ cp = lrc_obj.board[i*8+j];
+ }
+ else
+ {
+ cp = lrc_obj.board[(7-i)*8+7-j];
+ }
+ if ( cp_GetPiece(cp) != PIECE_NONE )
+ {
+ ptr = chess_black_pieces_bm;
+ ptr += (cp_GetPiece(cp)-1)*8;
+
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ u8g2_DrawBitmap(lrc_u8g, j*chess_boxsize+chess_boxoffset-1, chess_low_edge - (i*chess_boxsize+chess_boxsize-chess_boxoffset), 1, 8, ptr);
+
+ if ( cp_GetColor(cp) == lrc_obj.strike_out_color )
+ {
+ ptr = chess_pieces_body_bm;
+ ptr += (cp_GetPiece(cp)-1)*8;
+ u8g2_SetDefaultBackgroundColor(lrc_u8g);
+ u8g2_DrawBitmap(lrc_u8g, j*chess_boxsize+chess_boxoffset-1, chess_low_edge - (i*chess_boxsize+chess_boxsize-chess_boxoffset), 1, 8, ptr);
+ }
+ }
+ }
+ }
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+
+ if ( (chess_source_pos & 0x88) == 0 )
+ {
+ chess_DrawFrame(chess_source_pos, 1);
+ }
+
+ if ( (chess_target_pos & 0x88) == 0 )
+ {
+ chess_DrawFrame(chess_target_pos, 0);
+ }
+
+}
+
+
+void chess_Thinking(void)
+{
+}
+
+void chess_Init(u8g2_t *u8g, uint8_t body_color)
+{
+ lrc_u8g = u8g;
+
+ chess_low_edge = u8g2_GetDisplayHeight(lrc_u8g);
+ chess_low_edge--;
+ u8g2_SetBitmapMode(u8g, 1); // restore previous behaviour
+
+ {
+
+ chess_boxsize = 8;
+ chess_boxoffset = 1;
+ }
+
+
+
+ lrc_obj.strike_out_color = body_color;
+ chess_SetupBoard();
+}
+
+
+
+void chess_Draw(void)
+{
+ if ( chess_state == CHESS_STATE_MENU )
+ {
+ if ( lrc_obj.ply_count == 0)
+ mnu_max = 2;
+ else
+ mnu_max = 4;
+ mnu_Draw();
+ }
+ else
+ {
+ chess_DrawBoard();
+
+ {
+ uint8_t i;
+ uint8_t entries = lrc_obj.chm_pos;
+ if ( entries > 4 )
+ entries = 4;
+
+ u8g2_SetFont(lrc_u8g, u8g2_font_5x7_tr);
+ u8g2_SetDefaultForegroundColor(lrc_u8g);
+ for( i = 0; i < entries; i++ )
+ {
+
+ u8g2_DrawStr(lrc_u8g, u8g2_GetDisplayWidth(lrc_u8g)-35, 8*(i+1), cu_GetHalfMoveStr(lrc_obj.chm_pos-entries+i));
+
+ }
+
+ }
+
+ if ( chess_state == CHESS_STATE_SELECT_PIECE )
+ mnu_DrawHome(chess_source_pos == 255);
+ else if ( chess_state == CHESS_STATE_SELECT_TARGET_POS )
+ mnu_DrawHome(chess_target_pos == 255);
+ else
+ mnu_DrawHome(0);
+
+ if ( chess_state == CHESS_STATE_GAME_END )
+ {
+ switch( lrc_obj.lost_side_color )
+ {
+ case COLOR_WHITE:
+ mnu_DrawEntry(u8g2_GetDisplayHeight(lrc_u8g) / 2-2, "Black wins", 1, 1);
+ break;
+ case COLOR_BLACK:
+ mnu_DrawEntry(u8g2_GetDisplayHeight(lrc_u8g) / 2-2, "White wins", 1, 1);
+ break;
+ default:
+ mnu_DrawEntry(u8g2_GetDisplayHeight(lrc_u8g) / 2-2, "Stalemate", 1, 1);
+ break;
+ }
+ }
+ }
+}
+
+
+void chess_Step(uint8_t keycode)
+{
+ chess_key_cmd = keycode;
+
+ /*
+ if ( keycode == CHESS_KEY_NONE )
+ {
+ chess_key_cmd = chess_key_code;
+ chess_key_code = CHESS_KEY_NONE;
+ }
+ else
+ {
+ chess_key_cmd = CHESS_KEY_NONE;
+ chess_key_code = keycode;
+ }
+ */
+ //chess_ComputerMove(2);
+ switch(chess_state)
+ {
+ case CHESS_STATE_MENU:
+ mnu_Step(chess_key_cmd);
+ if ( chess_key_cmd == CHESS_KEY_SELECT )
+ {
+ if ( mnu_pos == 0 )
+ {
+ chess_SetupBoard();
+ lrc_obj.orientation = 0;
+ chess_state = CHESS_STATE_SELECT_START;
+ }
+ else if ( mnu_pos == 1 )
+ {
+ chess_SetupBoard();
+ lrc_obj.orientation = 1;
+ chess_state = CHESS_STATE_THINKING;
+ }
+ else if ( mnu_pos == 2 )
+ {
+ if ( lrc_obj.ply_count >= 2 )
+ {
+ cu_UndoHalfMove();
+ cu_UndoHalfMove();
+ lrc_obj.ply_count-=2;
+ if ( lrc_obj.ply_count == 0 )
+ mnu_pos = 0;
+ }
+ chess_state = CHESS_STATE_SELECT_START;
+ }
+ else if ( mnu_pos == 3 )
+ {
+ chess_state = CHESS_STATE_SELECT_START;
+ }
+ }
+ break;
+ case CHESS_STATE_SELECT_START:
+ chess_ClearMarks();
+ chess_MarkMovable();
+ chess_source_pos = chess_GetNextMarked(255, 0);
+ chess_target_pos = ILLEGAL_POSITION;
+ chess_state = CHESS_STATE_SELECT_PIECE;
+ break;
+
+ case CHESS_STATE_SELECT_PIECE:
+ if ( chess_key_cmd == CHESS_KEY_NEXT )
+ {
+ chess_source_pos = chess_GetNextMarked(chess_source_pos, lrc_obj.orientation);
+ }
+ else if ( chess_key_cmd == CHESS_KEY_PREV )
+ {
+ chess_source_pos = chess_GetNextMarked(chess_source_pos, 1-lrc_obj.orientation );
+ }
+ else if ( chess_key_cmd == CHESS_KEY_SELECT )
+ {
+ if ( chess_source_pos == 255 )
+ {
+ chess_state = CHESS_STATE_MENU;
+ }
+ else
+ {
+ chess_ClearMarks();
+ chess_MarkTargetMoves(chess_source_pos);
+ chess_target_pos = chess_GetNextMarked(255, 0);
+ chess_state = CHESS_STATE_SELECT_TARGET_POS;
+ }
+ }
+ break;
+ case CHESS_STATE_SELECT_TARGET_POS:
+ if ( chess_key_cmd == CHESS_KEY_NEXT )
+ {
+ chess_target_pos = chess_GetNextMarked(chess_target_pos, lrc_obj.orientation);
+ if ( chess_target_pos == 255 )
+ chess_target_pos = chess_GetNextMarked(chess_target_pos, lrc_obj.orientation);
+ }
+ else if ( chess_key_cmd == CHESS_KEY_PREV )
+ {
+ chess_target_pos = chess_GetNextMarked(chess_target_pos, 1-lrc_obj.orientation);
+ if ( chess_target_pos == 255 )
+ chess_target_pos = chess_GetNextMarked(chess_target_pos, 1-lrc_obj.orientation);
+ }
+ else if ( chess_key_cmd == CHESS_KEY_BACK )
+ {
+ chess_ClearMarks();
+ chess_MarkMovable();
+ chess_target_pos = ILLEGAL_POSITION;
+ chess_state = CHESS_STATE_SELECT_PIECE;
+ }
+ else if ( chess_key_cmd == CHESS_KEY_SELECT )
+ {
+ chess_ManualMove(chess_source_pos, chess_target_pos);
+ if ( lrc_obj.is_game_end != 0 )
+ chess_state = CHESS_STATE_GAME_END;
+ else
+ chess_state = CHESS_STATE_THINKING;
+ /* clear marks as some kind of feedback to the user... it simply looks better */
+ chess_source_pos = ILLEGAL_POSITION;
+ chess_target_pos = ILLEGAL_POSITION;
+ chess_ClearMarks();
+ }
+ break;
+ case CHESS_STATE_THINKING:
+ chess_ComputerMove(2);
+ if ( lrc_obj.is_game_end != 0 )
+ chess_state = CHESS_STATE_GAME_END;
+ else
+ chess_state = CHESS_STATE_SELECT_START;
+ //chess_state = CHESS_STATE_THINKING
+ break;
+ case CHESS_STATE_GAME_END:
+ if ( chess_key_cmd != CHESS_KEY_NONE )
+ {
+ chess_state = CHESS_STATE_MENU;
+ chess_SetupBoard();
+ }
+ break;
+ }
+
+}
+
+#endif /* UNIX_MAIN */
+
+void loop(void) {
+ static uint8_t keycode = 0;
+
+ u8g2.firstPage();
+ do {
+ chess_Draw();
+ if ( keycode == 0 )
+ keycode = u8g2.getMenuEvent();
+ } while ( u8g2.nextPage() );
+
+ if ( keycode == 0 )
+ keycode = u8g2.getMenuEvent();
+
+ if ( keycode == U8X8_MSG_GPIO_MENU_DOWN )
+ keycode = CHESS_KEY_NEXT;
+ if ( keycode == U8X8_MSG_GPIO_MENU_UP )
+ keycode = CHESS_KEY_PREV;
+ //if ( keycode == U8X8_MSG_GPIO_MENU_HOME )
+ // keycode = CHESS_KEY_SELECT;
+
+ chess_Step(keycode);
+ keycode = 0;
+ delay(1);
+}
+
diff --git a/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/SpaceTrash/SpaceTrash.ino b/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/SpaceTrash/SpaceTrash.ino
new file mode 100644
index 0000000..621c70b
--- /dev/null
+++ b/.pio/libdeps/esp32-s3-n16r8/U8g2/examples/games/SpaceTrash/SpaceTrash.ino
@@ -0,0 +1,1857 @@
+/*
+
+ SpaceTrash.ino
+
+ Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+ Copyright (c) 2016, olikraus@gmail.com
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list
+ of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <Arduino.h>
+#include <U8g2lib.h>
+
+#ifdef U8X8_HAVE_HW_SPI
+#include <SPI.h>
+#endif
+#ifdef U8X8_HAVE_HW_I2C
+#include <Wire.h>
+#endif
+
+// Please UNCOMMENT one of the contructor lines below
+// U8g2 Contructor List (Picture Loop Page Buffer)
+// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
+// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected
+//U8G2_NULL u8g2(U8G2_R0); // null device, a 8x8 pixel display which does nothing
+//U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6); // Arduboy (Production, Kickstarter Edition)
+//U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_3W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_3W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1306_128X64_ALT0_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
+//U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display
+//U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE); // ESP32 Thing, pure SW emulated I2C
+//U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17); // ESP32 Thing, HW I2C with pin remapping
+//U8G2_SSD1306_128X64_NONAME_1_6800 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8);
+//U8G2_SSD1306_128X64_NONAME_1_8080 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8);
+//U8G2_SSD1306_128X64_VCOMH0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but maximizes setContrast() range
+//U8G2_SSD1306_128X64_ALT0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
+//U8G2_SSD1306_102X64_EA_OLEDS102_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
+//U8G2_SSD1312_128X64_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1312_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ 8);
+//U8G2_SSD1312_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
+//U8G2_SSD1312_120X28_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1312_120X28_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ 8);
+//U8G2_SSD1312_120X28_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
+//U8G2_SH1106_128X64_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SH1106_128X64_VCOMH0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but maximizes setContrast() range
+//U8G2_SH1106_128X64_WINSTAR_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but uses updated SH1106 init sequence
+//U8G2_SH1106_128X32_VISIONOX_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SH1106_128X32_VISIONOX_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1106_72X40_WISE_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1107_64X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1107_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1107_128X128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
+//U8G2_SH1107_128X80_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
+//U8G2_SH1107_PIMORONI_128X128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
+//U8G2_SH1107_SEEED_128X128_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SH1107_SEEED_128X128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SH1107_SEEED_96X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1107_HJR_OEL1M0201_96X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1107_TK078F288_80X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1108_128X160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_CH1120_128X160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1108_160X160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SH1122_256X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SH1122_256X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1306_128X32_UNIVISION_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 21, /* data=*/ 20, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather M0 Basic Proto + FeatherWing OLED
+//U8G2_SSD1306_128X32_UNIVISION_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather ESP8266/32u4 Boards + FeatherWing OLED
+//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
+//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA); // pin remapping with ESP8266 HW I2C
+//U8G2_SSD1306_128X32_WINSTAR_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA); // pin remapping with ESP8266 HW I2C
+//U8G2_SSD1306_64X48_ER_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // EastRising 0.66" OLED breakout board, Uno: A4=SDA, A5=SCL, 5V powered
+//U8G2_SSD1306_48X64_WINSTAR_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1306_64X32_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1306_64X32_1F_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1306_96X16_ER_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // EastRising 0.69" OLED
+//U8G2_SSD1306_72X40_ER_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // EastRising 0.42" OLED
+//U8G2_SSD1306_96X40_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1306_96X39_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1322_240X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1322_TOPWIN_240X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1322_NHD_256X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1322_NHD_256X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1322_ZJY_256X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1322_ZJY_256X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1362_256X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1362_256X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1362_206X36_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1362_206X36_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1363_256X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1363_256X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
+//U8G2_SSD1322_NHD_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1322_NHD_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1325_NHD_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1325_NHD_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD0323_OS128064_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD0323_OS128064_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1326_ER_256X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // experimental driver for ER-OLED018-1
+//U8G2_SSD1327_SEEED_96X96_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // Seeedstudio Grove OLED 96x96
+//U8G2_SSD1327_SEEED_96X96_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Seeedstudio Grove OLED 96x96
+//U8G2_SSD1327_EA_W128128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_EA_W128128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_EA_W128128_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 5, /* data=*/ 4, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_SSD1327_EA_W128128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); /* Uno: A4=SDA, A5=SCL, add "u8g2.setBusClock(400000);" into setup() for speedup if possible */
+//U8G2_SSD1327_MIDAS_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_MIDAS_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_MIDAS_128X128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); /* Uno: A4=SDA, A5=SCL, add "u8g2.setBusClock(400000);" into setup() for speedup if possible */
+//U8G2_SSD1327_ZJY_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_ZJY_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_ZJY_128X128_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); /* Uno: A4=SDA, A5=SCL, add "u8g2.setBusClock(400000);" into setup() for speedup if possible */
+//U8G2_SSD1327_WS_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_WS_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_VISIONOX_128X96_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1327_VISIONOX_128X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1329_128X96_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1329_128X96_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1329_96X96_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1329_96X96_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1329_96X96_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ A4, /* dc=*/ A2, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather 32u4 Basic Proto
+//U8G2_SSD1305_128X32_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X32_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X32_ADAFRUIT_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X32_ADAFRUIT_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X64_ADAFRUIT_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X64_ADAFRUIT_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X64_RAYSTAR_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1305_128X64_RAYSTAR_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X64_NONAME0_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X64_NONAME0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X128_NONAME0_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X128_NONAME0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X64_NONAME2_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1309_128X64_NONAME2_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1316_128X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1316_128X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1316_96X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1316_96X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1317_96X96_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // not tested, not confirmed
+//U8G2_SSD1317_96X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // not tested, not confirmed
+//U8G2_SSD1318_128X96_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1318_128X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_160X132_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_160X132_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_160X80_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_160X80_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_128X72_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1320_128X72_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_LD7032_60X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 9, /* dc=*/ 10, /* reset=*/ 8); // SW SPI Nano Board
+//U8G2_LD7032_60X32_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* reset=*/ U8X8_PIN_NONE); // NOT TESTED!
+//U8G2_LD7032_60X32_ALT_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 9, /* dc=*/ 10, /* reset=*/ 8); // SW SPI Nano Board
+//U8G2_LD7032_60X32_ALT_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* reset=*/ U8X8_PIN_NONE); // NOT TESTED!
+//U8G2_LD7032_128X36_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 9, /* dc=*/ 10, /* reset=*/ 8); // SW SPI Nano Board
+//U8G2_LD7032_128X36_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* reset=*/ U8X8_PIN_NONE); // NOT TESTED!
+//U8G2_UC1701_EA_DOGS102_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1701_EA_DOGS102_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_PCD8544_84X48_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Nokia 5110 Display
+//U8G2_PCD8544_84X48_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Nokia 5110 Display
+//U8G2_PCF8812_96X65_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Could be also PCF8814
+//U8G2_PCF8812_96X65_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Could be also PCF8814
+//U8G2_PCF8812_101X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Could be also PCF8814
+//U8G2_PCF8812_101X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Could be also PCF8814
+//U8G2_HX1230_96X68_1_3W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8);
+//U8G2_HX1230_96X68_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_KS0108_128X64_1 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*dc=*/ 17, /*cs0=*/ 14, /*cs1=*/ 15, /*cs2=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE); // Set R/W to low!
+//U8G2_KS0108_ERM19264_1 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*dc=*/ 17, /*cs0=*/ 14, /*cs1=*/ 15, /*cs2=*/ 16, /* reset=*/ U8X8_PIN_NONE); // Set R/W to low!
+//U8G2_HD44102_100X64_1 u8g2(U8G2_R0, 4, 5, 6, 7, 8, 9, 10, 11, /*enable=*/ 2, /*dc=*/ 3, /*cs0=*/ A0, /*cs1=*/ A1, /*cs2=*/ A2, /* reset=*/ U8X8_PIN_NONE); // Set R/W to low!
+//U8G2_T7932_150X32_1 u8g2(U8G2_R0, 4, 5, 6, 7, 8, 9, 10, 11, /*enable=*/ 2, /*dc=*/ 3, /*cs0=*/ A0, /*cs1=*/ A1, /*cs2=*/ A2, /* reset=*/ U8X8_PIN_NONE); // Set R/W to low!
+//U8G2_ST7920_256X32_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_256X32_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_192X32_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_192X32_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_128X32_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_128X32_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_144X32_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_144X32_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_160X32_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_160X32_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_128X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18 /* A4 */, /*cs=*/ U8X8_PIN_NONE, /*dc/rs=*/ 17 /* A3 */, /*reset=*/ 15 /* A1 */); // Remember to set R/W to 0
+//U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* CS=*/ 10, /* reset=*/ 8);
+//U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, /* clock=*/ 14, /* data=*/ 13, /* CS=*/ 15, /* reset=*/ 16); // Feather HUZZAH ESP8266, E=clock=14, RW=data=13, RS=CS
+//U8G2_ST7920_128X64_1_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
+//U8G2_ST7920_128X64_1_HW_SPI u8g2(U8G2_R0, /* CS=*/ 15, /* reset=*/ 16); // Feather HUZZAH ESP8266, E=clock=14, RW=data=13, RS=CS
+//U8G2_ST7528_ERC16064_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7528_ERC16064_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7539_192X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7539_192X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_EA_DOGM128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_EA_DOGM128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_64128N_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_64128N_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_EA_DOGM132_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE); // DOGM132 Shield
+//U8G2_ST7565_EA_DOGM132_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE); // DOGM132 Shield
+//U8G2_ST7565_ZOLEN_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_ZOLEN_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_LM6059_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Adafruit ST7565 GLCD
+//U8G2_ST7565_LM6059_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Adafruit ST7565 GLCD
+//U8G2_ST7565_KS0713_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // KS0713 controller
+//U8G2_ST7565_KS0713_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // KS0713 controller
+//U8G2_ST7565_LX12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_LX12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_ERC12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_ERC12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_ERC12864_ALT_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // contrast improved version for ERC12864
+//U8G2_ST7565_ERC12864_ALT_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // contrast improved version for ERC12864
+//U8G2_ST7565_NHD_C12832_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_NHD_C12832_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_NHD_C12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_NHD_C12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_JLX12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7565_JLX12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_PI_132X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8); // Pax Instruments Shield, LCD_BL=6
+//U8G2_ST7567_PI_132X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8); // Pax Instruments Shield, LCD_BL=6
+//U8G2_ST7567_JLX12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_JLX12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_122X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_122X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_OS12864_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_OS12864_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_ENH_DG128064_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_ENH_DG128064_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_ENH_DG128064I_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_ENH_DG128064I_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_64X32_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7567_HEM6432_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_ST7567_ERC13232_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_ERC13232_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_96X65_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7567_96X65_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_128X96_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_128X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_G12896_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7571_G12896_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7302_122X250_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7305_122X250_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7305_200X200_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7305_168X384_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7305_300X400_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7586S_JLX384160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno: Enable U8g2 16 bit mode for this display
+//U8G2_ST7586S_ERC240160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7586S_YMC240160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7586S_JLX320160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno: Enable U8g2 16 bit mode for this display
+//U8G2_ST75160_JM16096_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75160_JM16096_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75161_JLX160160_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75161_JLX160160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX172104_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX172104_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX19296_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX19296_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX16080_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX16080_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX256128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_WO256X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_WO256X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 9, /* data=*/ 8, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5); // MKR Zero, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5); // MKR Zero, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160M_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160M_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160_ALT_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX256160_ALT_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75256_JLX240160_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX240160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST75256_JLX25664_1_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8); // Due, 2nd I2C, enable U8g2 16 bit mode for this display
+//U8G2_ST75320_JLX320240_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_ST75320_JLX320240_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Uno, Enable U8g2 16 bit mode for this display
+//U8G2_NT7534_TG12864R_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_NT7534_TG12864R_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_ST7588_JLX12864_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ 5);
+//U8G2_ST7588_JLX12864_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ 5);
+//U8G2_IST3020_ERC19264_1_6800 u8g2(U8G2_R0, 44, 43, 42, 41, 40, 39, 38, 37, /*enable=*/ 28, /*cs=*/ 32, /*dc=*/ 30, /*reset=*/ 31); // Connect WR pin with GND
+//U8G2_IST3020_ERC19264_1_8080 u8g2(U8G2_R0, 44, 43, 42, 41, 40, 39, 38, 37, /*enable=*/ 29, /*cs=*/ 32, /*dc=*/ 30, /*reset=*/ 31); // Connect RD pin with 3.3V
+//U8G2_IST3020_ERC19264_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_IST3088_320X240_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_IST3088_320X240_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_IST7920_128X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Round display
+//U8G2_IST7920_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Round display
+//U8G2_LC7981_160X80_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
+//U8G2_LC7981_160X160_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
+//U8G2_LC7981_240X128_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
+//U8G2_LC7981_240X64_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
+//U8G2_LC7981_128X128_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
+//U8G2_SED1520_122X32_1 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*dc=*/ A0, /*e1=*/ A3, /*e2=*/ A2, /* reset=*/ A4); // Set R/W to low!
+//U8G2_T6963_240X128_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_T6963_256X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_T6963_160X80_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_T6963_128X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_T6963_128X64_ALT_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_T6963_128X160_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
+//U8G2_SED1330_240X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0
+//U8G2_SED1330_240X128_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0
+//U8G2_SED1330_240X128_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // A0 is dc pin, /WR = RW = GND, enable is /RD = E
+//U8G2_SED1330_256X128_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0, enable U8g2 16Bit Mode
+//U8G2_SED1330_256X128_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // A0 is dc pin, /WR = RW = GND, enable is /RD = E, enable U8g2 16Bit Mode
+//U8G2_SED1330_320X200_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0, enable U8g2 16Bit Mode
+//U8G2_SED1330_320X200_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // A0 is dc pin, /WR = RW = GND, enable is /RD = E, enable U8g2 16Bit Mode
+//U8G2_RA8835_NHD_240X128_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0
+//U8G2_RA8835_NHD_240X128_1_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // A0 is dc pin, /WR = RW = GND, enable is /RD = E
+//U8G2_UC1601_128X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1601_128X32_1_3W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8);
+//U8G2_UC1601_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1604_JLX19264_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1604_JLX19264_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1609_SLG19264_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1609_SLG19264_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1608_ERC24064_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // SW SPI, Due ERC24064-1 Test Setup
+//U8G2_UC1608_DEM240064_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // SW SPI, Due ERC24064-1 Test Setup
+//U8G2_UC1608_ERC240120_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1608_240X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // SW SPI, Due ERC24064-1 Test Setup
+//U8G2_UC1610_EA_DOGXL160_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_UC1610_EA_DOGXL160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE);
+//U8G2_UC1611_EA_DOGM240_1_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8); // Due, 2nd I2C, DOGM240 Test Board
+//U8G2_UC1611_EA_DOGM240_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // SW SPI, Due DOGXL240 Test Board
+//U8G2_UC1611_EA_DOGXL240_1_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8); // Due, 2nd I2C, DOGXL240 Test Board
+//U8G2_UC1611_EA_DOGXL240_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // SW SPI, Due DOGXL240 Test Board
+//U8G2_UC1611_EW50850_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 3, /*dc=*/ 16, /*reset=*/ 17); // 240x160, Connect RD/WR1 pin with 3.3V, CS is aktive high
+//U8G2_UC1611_CG160160_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 3, /*dc=*/ 16, /*reset=*/ 17); // Connect WR1 and CD1 pin with 3.3V, connect CS0 with cs, WR0 with enable, CD with dc
+//U8G2_UC1611_IDS4073_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8g2 16Bit Mode
+//U8G2_UC1611_IDS4073_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8g2 16Bit Mode
+//U8G2_UC1617_JLX128128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1617_JLX128128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_128X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 3, /*dc=*/ 16, /*reset=*/ 17); // UC1628 pin names: enable: /WR, dc: CD
+//U8G2_UC1628_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_256X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_256X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_256X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1628_256X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1638_192X96_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1638_192X96_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1638_192X96_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* reset=*/ 8); // u8g2 test board: I2C clock/data is same as SPI, I2C default address is 0x78
+//U8G2_UC1638_240X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1638_240X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1638_240X128_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* reset=*/ 8); // u8g2 test board: I2C clock/data is same as SPI, I2C default address is 0x78
+//U8G2_UC1698_160X160_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_UC1698_160X160_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_SSD1606_172X72_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // eInk/ePaper Display
+//U8G2_SSD1607_200X200_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // eInk/ePaper Display, original LUT from embedded artists
+//U8G2_SSD1607_GD_200X200_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Good Display
+//U8G2_SSD1607_WS_200X200_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Waveshare
+//U8G2_IL3820_296X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // WaveShare 2.9 inch eInk/ePaper Display, enable 16 bit mode for this display!
+//U8G2_IL3820_V2_296X128_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // ePaper Display, lesser flickering and faster speed, enable 16 bit mode for this display!
+//U8G2_LS013B7DH03_128X128_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display
+//U8G2_LS027B7DH01_400X240_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display, SPI Mode 2
+//U8G2_LS027B7DH01_M0_400X240_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display, SPI Mode 0
+//U8G2_LS013B7DH05_144X168_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display
+//U8G2_ST7511_AVD_320X240_1_8080 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable/WR=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); // Enable U8g2 16Bit Mode and connect RD pin with 3.3V/5V
+//U8G2_ST7511_640X320_1_8080 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable/WR=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); // Enable U8g2 16Bit Mode and connect RD pin with 3.3V/5V
+//U8G2_S1D15300_LM6023_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15300_LM6023_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15300_100X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15300_100X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15300_100X32I_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15300_100X32I_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15721_240X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_S1D15721_240X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_GU800_128X64_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_GU800_128X64_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_GU800_160X16_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_GU800_160X16_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
+//U8G2_GP1294AI_256X48_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/10, /* dc=*/U8X8_PIN_NONE, /* reset=*/8);
+
+
+
+
+// End of constructor list
+
+
+
+/* button setup for Arduboy Production */
+uint8_t pin_up = A0;
+uint8_t pin_down = A3;
+uint8_t pin_fire = 7;
+
+
+
+
+#define ST_FP 4
+
+/* object types */
+struct _st_ot_struct
+{
+ /*
+ missle and hit:
+ bit 0: player missle and trash
+ bit 1: trash, which might hit the player
+ */
+
+ uint8_t missle_mask; /* this object is a missle: it might destroy something if the target is_hit_fn says so */
+ uint8_t hit_mask; /* if missle_mask & hit_mask is != 0 then the object can be destroyed */
+ uint8_t points;
+ uint8_t draw_fn;
+ uint8_t move_fn;
+ /* ST_MOVE_FN_NONE, ST_MOVE_FN_X_SLOW */
+ uint8_t destroy_fn; /* object can be destroyed by a missle (e.g. a missle from the space ship) */
+ /* ST_DESTROY_FN_NONE, ST_DESTROY_FN_SPLIT */
+ uint8_t is_hit_fn; /* is hit procedure */
+ /* ST_IS_HIT_FN_NONE, ST_IS_HIT_BBOX */
+ uint8_t fire_fn;
+ /* ST_FIRE_FN_NONE, ST_FIRE_FN_X_LEFT */
+
+};
+typedef struct _st_ot_struct st_ot;
+
+/*
+ objects, which are visible at the play area
+*/
+struct _st_obj_struct
+{
+ uint8_t ot; /* object type: zero means, object is not used */
+ int8_t tmp; /* generic value, used by ST_MOVE_IMPLODE */
+ /* absolute position */
+ /* LCD pixel position is x>>ST_FP and y>>ST_FP */
+ int16_t x, y;
+ int8_t x0,y0,x1,y1; /* object outline in pixel, reference point is at 0,0 */
+};
+typedef struct _st_obj_struct st_obj;
+
+#define ST_DRAW_NONE 0
+#define ST_DRAW_BBOX 1
+#define ST_DRAW_TRASH1 2
+#define ST_DRAW_PLAYER1 3
+#define ST_DRAW_TRASH2 4
+#define ST_DRAW_PLAYER2 5
+#define ST_DRAW_PLAYER3 6
+#define ST_DRAW_GADGET 7
+#define ST_DRAW_BACKSLASH 8
+#define ST_DRAW_SLASH 9
+#define ST_DRAW_BIG_TRASH 10
+
+#define ST_MOVE_NONE 0
+#define ST_MOVE_X_SLOW 1
+#define ST_MOVE_PX_NORMAL 2
+#define ST_MOVE_PX_FAST 3
+#define ST_MOVE_PLAYER 4
+#define ST_MOVE_PY 5
+#define ST_MOVE_NY 6
+#define ST_MOVE_IMPLODE 7
+#define ST_MOVE_X_FAST 8
+#define ST_MOVE_WALL 9
+#define ST_MOVE_NXPY 10
+#define ST_MOVE_NXNY 11
+
+#define ST_IS_HIT_NONE 0
+#define ST_IS_HIT_BBOX 1
+#define ST_IS_HIT_WALL 2
+
+#define ST_DESTROY_NONE 0
+#define ST_DESTROY_DISAPPEAR 1
+#define ST_DESTROY_TO_DUST 2
+#define ST_DESTROY_GADGET 3
+#define ST_DESTROY_PLAYER 4
+#define ST_DESTROY_PLAYER_GADGETS 5
+#define ST_DESTROY_BIG_TRASH 6
+
+#define ST_FIRE_NONE 0
+#define ST_FIRE_PLAYER1 1
+#define ST_FIRE_PLAYER2 2
+#define ST_FIRE_PLAYER3 3
+
+#define ST_OT_WALL_SOLID 1
+#define ST_OT_BIG_TRASH 2
+#define ST_OT_MISSLE 3
+#define ST_OT_TRASH1 4
+#define ST_OT_PLAYER 5
+#define ST_OT_DUST_PY 6
+#define ST_OT_DUST_NY 7
+#define ST_OT_TRASH_IMPLODE 8
+#define ST_OT_TRASH2 9
+#define ST_OT_PLAYER2 10
+#define ST_OT_PLAYER3 11
+#define ST_OT_GADGET 12
+#define ST_OT_GADGET_IMPLODE 13
+#define ST_OT_DUST_NXPY 14
+#define ST_OT_DUST_NXNY 15
+
+
+/*================================================================*/
+/* graphics object */
+/*================================================================*/
+
+u8g2_t *st_u8g2;
+
+u8g2_uint_t u8g_height_minus_one;
+
+
+#define ST_AREA_HEIGHT (st_u8g2->height - 8)
+#define ST_AREA_WIDTH (st_u8g2->width)
+
+
+/*================================================================*/
+/* object types */
+/*================================================================*/
+
+
+const st_ot st_object_types[] U8X8_PROGMEM =
+{
+ /* 0: empty object type */
+ { 0, 0, 0, ST_DRAW_NONE, ST_MOVE_NONE, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* 1: wall, player will be destroyed */
+ { 2, 1, 30, ST_DRAW_BBOX, ST_MOVE_WALL, ST_DESTROY_DISAPPEAR, ST_IS_HIT_WALL, ST_FIRE_NONE },
+ /* ST_OT_BIG_TRASH (2) */
+ { 2, 1, 0, ST_DRAW_BIG_TRASH, ST_MOVE_X_SLOW, ST_DESTROY_BIG_TRASH, ST_IS_HIT_BBOX, ST_FIRE_NONE },
+ /* 3: simple space ship (player) missle */
+ { 1, 0, 0, ST_DRAW_BBOX, ST_MOVE_PX_FAST, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_TRASH1 (4): trash */
+ { 2, 1, 0, ST_DRAW_TRASH1, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE },
+ /* ST_OT_PLAYER (5): player space ship */
+ { 0, 2, 0, ST_DRAW_PLAYER1, ST_MOVE_PLAYER, ST_DESTROY_PLAYER, ST_IS_HIT_BBOX, ST_FIRE_PLAYER1 },
+ /* ST_OT_DUST_PY (6): Last part of trash */
+ { 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_PY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_DUST_NY (7): Last part of trash */
+ { 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_NY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_TRASH_IMPLODE (8): trash was hit */
+ { 0, 0, 5, ST_DRAW_TRASH1, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_TRASH2 (9): trash */
+ { 2, 1, 0, ST_DRAW_TRASH2, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE },
+ /* ST_OT_PLAYER2 (10): player space ship+1x enhancement */
+ { 0, 2, 0, ST_DRAW_PLAYER2, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER2 },
+ /* ST_OT_PLAYER3 (11): player space ship+2x enhancement */
+ { 0, 2, 0, ST_DRAW_PLAYER3, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER3 },
+ /* ST_OT_GADGET (12): adds enhancements */
+ { 0, 1, 0, ST_DRAW_GADGET, ST_MOVE_X_FAST, ST_DESTROY_GADGET, ST_IS_HIT_BBOX, ST_FIRE_NONE },
+ /* ST_OT_GADGET_IMPLODE (13) */
+ { 0, 0, 20, ST_DRAW_GADGET, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_DUST_NXPY (14): Last part of trash */
+ { 0, 0, 0, ST_DRAW_BACKSLASH, ST_MOVE_NXPY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+ /* ST_OT_DUST_NXNY (15): Last part of trash */
+ { 0, 0, 0, ST_DRAW_SLASH, ST_MOVE_NXNY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
+
+};
+
+/*================================================================*/
+/* list of all objects on the screen */
+/*================================================================*/
+
+/* use AVR RAMEND constant to derive the number of allowed objects */
+
+#if RAMEND < 0x300
+#define ST_OBJ_CNT 25
+#else
+//#define ST_OBJ_CNT 45
+#define ST_OBJ_CNT 60
+#endif
+
+st_obj st_objects[ST_OBJ_CNT];
+
+/*================================================================*/
+/* about players space ship*/
+/*================================================================*/
+
+/* player position */
+uint8_t st_player_pos;
+
+/* points */
+#define ST_POINTS_PER_LEVEL 25
+uint16_t st_player_points;
+uint16_t st_player_points_delayed;
+uint16_t st_highscore = 0;
+
+/*================================================================*/
+/* overall game state */
+/*================================================================*/
+
+#define ST_STATE_PREPARE 0
+#define ST_STATE_IPREPARE 1
+#define ST_STATE_GAME 2
+#define ST_STATE_END 3
+#define ST_STATE_IEND 4
+
+uint8_t st_state = ST_STATE_PREPARE;
+
+/*================================================================*/
+/* game difficulty */
+/*================================================================*/
+uint8_t st_difficulty = 1;
+#define ST_DIFF_VIS_LEN 30
+#define ST_DIFF_FP 5
+uint16_t st_to_diff_cnt = 0;
+
+/*================================================================*/
+/* bitmaps */
+/*================================================================*/
+
+const uint8_t st_bitmap_player1[] =
+{
+ /* 01100000 */ 0x060,
+ /* 11111000 */ 0x0f8,
+ /* 01111110 */ 0x07e,
+ /* 11111000 */ 0x0f8,
+ /* 01100000 */ 0x060
+};
+
+const uint8_t st_bitmap_player2[] =
+{
+ /* 01100000 */ 0x060,
+ /* 01111100 */ 0x078,
+ /* 01100000 */ 0x060,
+ /* 11100000 */ 0x0e0,
+ /* 11111000 */ 0x0f8,
+ /* 01111110 */ 0x07e,
+ /* 11111000 */ 0x0f8,
+ /* 01100000 */ 0x060
+};
+
+const uint8_t st_bitmap_player3[] =
+{
+ /* 01100000 */ 0x060,
+ /* 01111100 */ 0x078,
+ /* 01100000 */ 0x060,
+ /* 11100000 */ 0x0e0,
+ /* 11111000 */ 0x0f8,
+ /* 01111110 */ 0x07e,
+ /* 11111000 */ 0x0f8,
+ /* 11100000 */ 0x0e0,
+ /* 01100000 */ 0x060,
+ /* 01111100 */ 0x078,
+ /* 01100000 */ 0x060
+ };
+
+const uint8_t st_bitmap_trash_5x5_1[] =
+{
+ /* 01110000 */ 0x070,
+ /* 11110000 */ 0x0f0,
+ /* 11111000 */ 0x0f8,
+ /* 01111000 */ 0x078,
+ /* 00110000 */ 0x030,
+};
+
+const uint8_t st_bitmap_trash_5x5_2[] =
+{
+ /* 00110000 */ 0x030,
+ /* 11111000 */ 0x0f8,
+ /* 11111000 */ 0x0f8,
+ /* 11110000 */ 0x0f0,
+ /* 01110000 */ 0x070,
+};
+
+const uint8_t st_bitmap_trash_7x7[] =
+{
+ /* 00111000 */ 0x038,
+ /* 01111100 */ 0x07c,
+ /* 11111100 */ 0x0fc,
+ /* 11111110 */ 0x0fe,
+ /* 11111110 */ 0x0fe,
+ /* 01111110 */ 0x07e,
+ /* 01111000 */ 0x078,
+};
+
+const uint8_t st_bitmap_gadget[] =
+{
+ /* 01110000 */ 0x070,
+ /* 11011000 */ 0x0d8,
+ /* 10001000 */ 0x088,
+ /* 11011000 */ 0x0d8,
+ /* 01110000 */ 0x070,
+};
+
+/*================================================================*/
+/* forward definitions */
+/*================================================================*/
+uint8_t st_rnd(void) U8X8_NOINLINE;
+static st_obj *st_GetObj(uint8_t objnr) U8X8_NOINLINE;
+uint8_t st_GetMissleMask(uint8_t objnr);
+uint8_t st_GetHitMask(uint8_t objnr);
+int8_t st_FindObj(uint8_t ot) U8X8_NOINLINE;
+void st_ClrObjs(void) U8X8_NOINLINE;
+int8_t st_NewObj(void) U8X8_NOINLINE;
+uint8_t st_CntObj(uint8_t ot);
+uint8_t st_CalcXY(st_obj *o) U8X8_NOINLINE;
+void st_SetXY(st_obj *o, uint8_t x, uint8_t y) U8X8_NOINLINE;
+
+void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire) U8X8_NOINLINE;
+
+void st_InitTrash(uint8_t x, uint8_t y, int8_t dir);
+void st_NewGadget(uint8_t x, uint8_t y);
+void st_NewPlayerMissle(uint8_t x, uint8_t y) ;
+void st_NewTrashDust(uint8_t x, uint8_t y, int ot);
+void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot);
+void st_SetupPlayer(uint8_t objnr, uint8_t ot);
+
+
+/*================================================================*/
+/* utility functions */
+/*================================================================*/
+
+char st_itoa_buf[12];
+char *st_itoa(unsigned long v)
+{
+ volatile unsigned char i = 11;
+ st_itoa_buf[11] = '\0';
+ while( i > 0)
+ {
+ i--;
+ st_itoa_buf[i] = (v % 10)+'0';
+ v /= 10;
+ if ( v == 0 )
+ break;
+ }
+ return st_itoa_buf+i;
+}
+
+
+uint8_t st_rnd(void)
+{
+ return rand();
+}
+
+/*
+ for the specified index number, return the object
+*/
+static st_obj *st_GetObj(uint8_t objnr)
+{
+ return st_objects+objnr;
+}
+
+
+/*
+ check, if this is a missle-like object (that is, can this object destroy something else)
+*/
+uint8_t st_GetMissleMask(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ return u8x8_pgm_read(&(st_object_types[o->ot].missle_mask));
+}
+
+/*
+ check, if this is a missle-like object (that is, can this object destroy something else)
+*/
+uint8_t st_GetHitMask(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ return u8x8_pgm_read(&(st_object_types[o->ot].hit_mask));
+}
+
+/*
+ search an empty object
+*/
+int8_t st_FindObj(uint8_t ot)
+{
+ int8_t i;
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ if ( st_objects[i].ot == ot )
+ return i;
+ }
+ return -1;
+}
+
+/*
+ delete all objects
+*/
+
+void st_ClrObjs(void)
+{
+ int8_t i;
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ st_objects[i].ot = 0;
+}
+
+/*
+ search an empty object
+*/
+int8_t st_NewObj(void)
+{
+ int8_t i;
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ if ( st_objects[i].ot == 0 )
+ return i;
+ }
+ return -1;
+}
+
+/*
+ count number of objectes of the provided type
+ st_CntObj(0) will return the number of empty objects, that means if
+ st_CntObj(0) > 0 then st_NewObj() will return a valid index
+*/
+uint8_t st_CntObj(uint8_t ot)
+{
+ uint8_t i;
+ uint8_t cnt = 0;
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ if ( st_objects[i].ot == ot )
+ cnt++;
+ }
+ return cnt;
+}
+
+/*
+ calculate the pixel coordinates of the reference point of an object
+ return rhe x value
+*/
+uint8_t st_px_x, st_px_y; /* pixel within area */
+uint8_t st_CalcXY(st_obj *o)
+{
+ //st_obj *o = st_GetObj(objnr);
+ st_px_y = o->y>>ST_FP;
+ st_px_x = o->x>>ST_FP;
+ return st_px_x;
+}
+
+void st_SetXY(st_obj *o, uint8_t x, uint8_t y)
+{
+ o->x = ((int16_t)x) << ST_FP;
+ o->y = ((int16_t)y) << ST_FP;
+}
+
+/*
+ calculate the object bounding box and place it into some global variables
+*/
+int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1;
+
+void st_CalcBBOX(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+
+ st_bbox_x0 = (uint16_t)(o->x>>ST_FP);
+ st_bbox_x1 = st_bbox_x0;
+ st_bbox_x0 += o->x0;
+ st_bbox_x1 += o->x1;
+
+ st_bbox_y0 = (uint16_t)(o->y>>ST_FP);
+ st_bbox_y1 = st_bbox_y0;
+ st_bbox_y0 += o->y0;
+ st_bbox_y1 += o->y1;
+}
+
+/*
+ clip bbox with the view window. requires a call to st_CalcBBOX
+ return 0, if the bbox is totally outside the window
+*/
+uint8_t st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1;
+uint8_t st_ClipBBOX(void)
+{
+ if ( st_bbox_x0 >= ST_AREA_WIDTH )
+ return 0;
+ if ( st_bbox_x0 >= 0 )
+ st_cbbox_x0 = (uint16_t)st_bbox_x0;
+ else
+ st_cbbox_x0 = 0;
+
+ if ( st_bbox_x1 < 0 )
+ return 0;
+ if ( st_bbox_x1 < ST_AREA_WIDTH )
+ st_cbbox_x1 = (uint16_t)st_bbox_x1;
+ else
+ st_cbbox_x1 = ST_AREA_WIDTH-1;
+
+ if ( st_bbox_y0 >= ST_AREA_HEIGHT )
+ return 0;
+ if ( st_bbox_y0 >= 0 )
+ st_cbbox_y0 = (uint16_t)st_bbox_y0;
+ else
+ st_cbbox_y0 = 0;
+
+ if ( st_bbox_y1 < 0 )
+ return 0;
+ if ( st_bbox_y1 < ST_AREA_HEIGHT )
+ st_cbbox_y1 = (uint16_t)st_bbox_y1;
+ else
+ st_cbbox_y1 = ST_AREA_HEIGHT-1;
+
+ return 1;
+}
+
+
+/*================================================================*/
+/* universal member functions */
+/*================================================================*/
+
+
+uint8_t st_IsOut(uint8_t objnr)
+{
+ st_CalcBBOX(objnr);
+ if ( st_bbox_x0 >= ST_AREA_WIDTH )
+ return 1;
+ if ( st_bbox_x1 < 0 )
+ return 1;
+ if ( st_bbox_y0 >= ST_AREA_HEIGHT )
+ return 1;
+ if ( st_bbox_y1 < 0 )
+ return 1;
+ return 0;
+}
+
+void st_Disappear(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ st_player_points += u8x8_pgm_read(&(st_object_types[o->ot].points));
+ o->ot = 0;
+}
+
+/*================================================================*/
+/* type dependent member functions */
+/*================================================================*/
+
+void st_Move(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ switch(u8x8_pgm_read(&(st_object_types[o->ot].move_fn)))
+ {
+ case ST_MOVE_NONE:
+ break;
+ case ST_MOVE_X_SLOW:
+ o->x -= (1<<ST_FP)/8;
+ o->x -= st_difficulty;
+ o->y += (int16_t)o->tmp;
+ if ( o->y >= ((ST_AREA_HEIGHT-1) << ST_FP) || o->y <= 0 )
+ o->tmp = - o->tmp;
+ break;
+ case ST_MOVE_X_FAST:
+ o->x -= (1<<ST_FP)/2;
+ o->y += (int16_t)o->tmp;
+ if ( o->y >= ((ST_AREA_HEIGHT-1) << ST_FP) || o->y <= 0 )
+ o->tmp = - o->tmp;
+ break;
+ case ST_MOVE_PX_NORMAL:
+ o->x += (1<<ST_FP)/4;
+ break;
+ case ST_MOVE_PX_FAST:
+ o->x += (1<<ST_FP);
+ break;
+ case ST_MOVE_PLAYER:
+ o->y = st_player_pos<<ST_FP;
+ break;
+ case ST_MOVE_PY:
+ o->y += 3*ST_FP;
+ break;
+ case ST_MOVE_NY:
+ o->y -= 3*ST_FP;
+ break;
+ case ST_MOVE_NXPY:
+ o->y += 3*ST_FP;
+ o->x -= 3*ST_FP;
+ break;
+ case ST_MOVE_NXNY:
+ o->y -= 3*ST_FP;
+ o->x -= 3*ST_FP;
+ break;
+ case ST_MOVE_IMPLODE:
+ o->tmp++;
+ if ( (o->tmp & 0x03) == 0 )
+ {
+ if ( o->x0 != o->x1 )
+ o->x0++;
+ else
+ st_Disappear(objnr);
+ }
+ break;
+ case ST_MOVE_WALL:
+ o->x -= 1;
+ o->x -= (st_difficulty>>1);
+ break;
+ }
+}
+
+void st_DrawBBOX(uint8_t objnr)
+{
+ uint8_t y0, y1;
+ /*st_obj *o = st_GetObj(objnr);*/
+ st_CalcBBOX(objnr);
+ if ( st_ClipBBOX() == 0 )
+ return;
+ /* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */
+
+
+ // w = st_cbbox_x1-st_cbbox_x0;
+ // w++;
+ // h = st_cbbox_y1-st_cbbox_y0;
+ // h++;
+
+
+ //dog_SetVLine(st_cbbox_x0, st_cbbox_y0, st_cbbox_y1);
+ //dog_SetVLine(st_cbbox_x1, st_cbbox_y0, st_cbbox_y1);
+ //dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y0);
+ //dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y1);
+
+ u8g2_SetDrawColor(st_u8g2, 1);
+ y0 = u8g_height_minus_one - st_cbbox_y0;
+ y1 = u8g_height_minus_one - st_cbbox_y1;
+
+ u8g2_DrawFrame(st_u8g2, st_cbbox_x0, y1, st_cbbox_x1-st_cbbox_x0+1, y0-y1+1);
+
+ //dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1);
+
+ /*
+ if ( o->ot == ST_OT_PLAYER )
+ {
+ dog_DrawStr(0, 26, font_4x6, st_itoa(st_cbbox_y0));
+ dog_DrawStr(10, 26, font_4x6, st_itoa(st_cbbox_y1));
+ }
+ */
+}
+
+#ifdef FN_IS_NOT_IN_USE
+void st_DrawFilledBox(uint8_t objnr)
+{
+ st_CalcBBOX(objnr);
+ if ( st_ClipBBOX() == 0 )
+ return;
+ /* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */
+ dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1);
+}
+#endif
+
+void st_DrawBitmap(uint8_t objnr, const uint8_t * bm, uint8_t w, uint8_t h)
+{
+ /* st_obj *o = st_GetObj(objnr); */
+ st_CalcBBOX(objnr);
+ /* result is here: int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1 */
+ //dog_SetBitmapP(st_bbox_x0,st_bbox_y1,bm,w,h);
+
+ u8g2_DrawBitmap(st_u8g2, st_bbox_x0, u8g_height_minus_one - st_bbox_y1, (w+7)/8, h, bm);
+
+ }
+
+void st_DrawObj(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ switch(u8x8_pgm_read(&(st_object_types[o->ot].draw_fn)))
+ {
+ case ST_DRAW_NONE:
+ break;
+ case ST_DRAW_BBOX:
+ st_DrawBBOX(objnr);
+ break;
+ case ST_DRAW_TRASH1:
+ st_DrawBitmap(objnr, st_bitmap_trash_5x5_1,o->x1-o->x0+1, 5);
+ break;
+ case ST_DRAW_TRASH2:
+ st_DrawBitmap(objnr, st_bitmap_trash_5x5_2,o->x1-o->x0+1, 5);
+ break;
+ case ST_DRAW_BIG_TRASH:
+ st_DrawBitmap(objnr, st_bitmap_trash_7x7,o->x1-o->x0+1, 7);
+ break;
+ case ST_DRAW_PLAYER1:
+ st_DrawBitmap(objnr, st_bitmap_player1,7,5);
+ break;
+ case ST_DRAW_PLAYER2:
+ st_DrawBitmap(objnr, st_bitmap_player2,7,8);
+ break;
+ case ST_DRAW_PLAYER3:
+ st_DrawBitmap(objnr, st_bitmap_player3,7,11);
+ break;
+ case ST_DRAW_GADGET:
+ /* could use this proc, but... */
+ /* st_DrawBitmap(objnr, st_bitmap_gadget,o->x1-o->x0+1, 5); */
+ /* ... this one looks also funny. */
+ st_DrawBitmap(objnr, st_bitmap_gadget,5,5);
+ break;
+ case ST_DRAW_BACKSLASH:
+ {
+ uint8_t x;
+ uint8_t y;
+ x = st_CalcXY(o);
+ y = st_px_y;
+
+
+ // dog_SetPixel(x,y);
+ // x++; y--;
+ // dog_SetPixel(x,y);
+ // x++; y--;
+ // dog_SetPixel(x,y);
+
+ u8g2_SetDrawColor(st_u8g2, 1);
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ x++; y--;
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ x++; y--;
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ }
+ break;
+ case ST_DRAW_SLASH:
+ {
+ uint8_t x;
+ uint8_t y;
+ x = st_CalcXY(o);
+ y = st_px_y;
+
+ // dog_SetPixel(x,y);
+ // x++; y++;
+ // dog_SetPixel(x,y);
+ // x++; y++;
+ // dog_SetPixel(x,y);
+
+ u8g2_SetDrawColor(st_u8g2, 1);
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ x++; y++;
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ x++; y++;
+ u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
+ }
+ break;
+ }
+}
+
+uint8_t st_IsHitBBOX(uint8_t objnr, uint8_t x, uint8_t y)
+{
+ st_CalcBBOX(objnr);
+ if ( st_ClipBBOX() == 0 )
+ return 0; /* obj is outside (not visible) */
+ if ( x < st_cbbox_x0 )
+ return 0;
+ if ( x > st_cbbox_x1 )
+ return 0;
+ if ( y < st_cbbox_y0 )
+ return 0;
+ if ( y > st_cbbox_y1 )
+ return 0;
+ return 1;
+}
+
+void st_Destroy(uint8_t objnr)
+{
+ int8_t nr;
+ st_obj *o = st_GetObj(objnr);
+ switch(u8x8_pgm_read(&(st_object_types[o->ot].destroy_fn)))
+ {
+ case ST_DESTROY_NONE: /* only usefull for missels or walls which stay alife */
+ break;
+ case ST_DESTROY_DISAPPEAR: /* this should be the default operation */
+ st_Disappear(objnr);
+ break;
+ case ST_DESTROY_GADGET:
+ nr = st_FindObj(ST_OT_PLAYER2);
+ if ( nr >= 0 )
+ st_SetupPlayer(nr, ST_OT_PLAYER3);
+ else
+ {
+ nr = st_FindObj(ST_OT_PLAYER);
+ if ( nr >= 0 )
+ st_SetupPlayer(nr, ST_OT_PLAYER2);
+ }
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
+ o->ot = ST_OT_GADGET_IMPLODE;
+ o->tmp = 0;
+ break;
+ case ST_DESTROY_TO_DUST:
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
+ o->ot = ST_OT_TRASH_IMPLODE;
+ o->tmp = 0;
+ break;
+ case ST_DESTROY_BIG_TRASH:
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
+ st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
+ st_InitTrash((o->x>>ST_FP)-1, (o->y>>ST_FP)+3, 2+(st_rnd()&3));
+ st_InitTrash((o->x>>ST_FP)-2, (o->y>>ST_FP)-3, -2-(st_rnd()&3));
+ st_Disappear(objnr);
+ break;
+ case ST_DESTROY_PLAYER:
+ st_Disappear(objnr);
+ st_state = ST_STATE_END;
+ o->tmp = 0;
+ break;
+ case ST_DESTROY_PLAYER_GADGETS:
+ /* o->ot = ST_OT_PLAYER; */
+ st_SetupPlayer(objnr, ST_OT_PLAYER);
+ break;
+ }
+}
+
+/*
+ check if the target (objnr) has been hit.
+ st_IsHit() must also destroy the target.
+ return value:
+ 0: do not destroy the missle
+ 1: destroy the missle
+*/
+uint8_t st_IsHit(uint8_t objnr, uint8_t x, uint8_t y, uint8_t missle_mask)
+{
+ uint8_t hit_mask = st_GetHitMask(objnr);
+ st_obj *o;
+
+ if ( (hit_mask & missle_mask) == 0 )
+ return 0;
+
+ o = st_GetObj(objnr);
+
+ switch(u8x8_pgm_read(&(st_object_types[o->ot].is_hit_fn)))
+ {
+ case ST_IS_HIT_NONE:
+ break;
+ case ST_IS_HIT_BBOX:
+ if ( st_IsHitBBOX(objnr, x, y) != 0 )
+ {
+ st_Destroy(objnr);
+ return 1;
+ }
+ break;
+ case ST_IS_HIT_WALL:
+ if ( st_IsHitBBOX(objnr, x, y) != 0 )
+ {
+ o->x0++;
+ if ( o->x0 < o->x1 )
+ {
+ st_NewTrashDust(x, y, ST_OT_DUST_NXPY);
+ st_NewTrashDust(x, y, ST_OT_DUST_NXNY);
+ }
+ else
+ {
+ st_Destroy(objnr);
+ st_NewTrashDust(x, y, ST_OT_DUST_NXPY);
+ st_NewTrashDust(x, y, ST_OT_DUST_NXNY);
+ st_NewTrashDust(x, y, ST_OT_DUST_NY);
+ st_NewTrashDust(x, y, ST_OT_DUST_PY);
+ }
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+
+/* update all fire counters */
+uint8_t st_fire_player = 0;
+uint8_t st_fire_period = 51;
+uint8_t st_manual_fire_delay = 20;
+uint8_t st_is_fire_last_value = 0;
+
+/*
+ is_auto_fire == 1
+ is_fire will be ignored, autofire enabled
+ is_auto_fire == 0
+ a transition from 1 to 0 on the is_fire variable will issue a missle
+*/
+void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire)
+{
+ if ( is_auto_fire != 0 )
+ {
+ st_fire_player++;
+ if ( st_fire_player >= st_fire_period )
+ st_fire_player = 0;
+ }
+ else
+ {
+ if ( st_fire_player < st_manual_fire_delay )
+ {
+ st_fire_player++;
+ }
+ else
+ {
+ if ( st_is_fire_last_value == 0 )
+ if ( is_fire != 0 )
+ st_fire_player = 0;
+ }
+ st_is_fire_last_value = is_fire;
+ }
+}
+
+void st_Fire(uint8_t objnr)
+{
+ st_obj *o = st_GetObj(objnr);
+ uint8_t x;
+ uint8_t y;
+
+ switch(u8x8_pgm_read(&(st_object_types[o->ot].fire_fn)))
+ {
+ case ST_FIRE_NONE:
+ break;
+ case ST_FIRE_PLAYER1:
+ if ( st_fire_player == 0 )
+ {
+ /* create missle at st_px_x and st_px_y */
+ x = st_CalcXY(o);
+ y = st_px_y;
+ st_NewPlayerMissle(x , y );
+ }
+ break;
+ case ST_FIRE_PLAYER2:
+ if ( st_fire_player == 0 )
+ {
+ /* create missle at st_px_x and st_px_y */
+ x = st_CalcXY(o);
+ y = st_px_y;
+ st_NewPlayerMissle(x , y );
+ st_NewPlayerMissle(x , y+4 );
+ }
+ break;
+ case ST_FIRE_PLAYER3:
+ if ( st_fire_player == 0 )
+ {
+ /* create missle at st_px_x and st_px_y */
+ x = st_CalcXY(o);
+ y = st_px_y;
+ st_NewPlayerMissle(x , y );
+ st_NewPlayerMissle(x , y+4 );
+ st_NewPlayerMissle(x , y-4 );
+ }
+ break;
+ }
+}
+
+/*================================================================*/
+/* object init functions */
+/*================================================================*/
+
+/*
+ x,y are pixel coordinats within the play arey
+*/
+void st_NewGadget(uint8_t x, uint8_t y)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ st_SetXY(o, x, y);
+ o->ot = ST_OT_GADGET;
+ o->tmp = 8;
+ //o->x = (x)<<ST_FP;
+ //o->y = (y)<<ST_FP;
+ o->x0 = -3;
+ o->x1 = 1;
+ o->y0 = -2;
+ o->y1 = 2;
+}
+
+/*
+ x,y are pixel coordinats within the play arey
+ dir: direction
+ 0: random
+ != 0 --> assigned
+*/
+void st_InitTrash(uint8_t x, uint8_t y, int8_t dir)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ if ( (st_rnd() & 1) == 0 )
+ o->ot = ST_OT_TRASH1;
+ else
+ o->ot = ST_OT_TRASH2;
+ if ( dir == 0 )
+ {
+ o->tmp = 0;
+ if ( st_rnd() & 1 )
+ {
+ if ( st_rnd() & 1 )
+ o->tmp++;
+ else
+ o->tmp--;
+ }
+ }
+ else
+ {
+ o->tmp = dir;
+ }
+ st_SetXY(o, x, y);
+ //o->x = (x)<<ST_FP;
+ //o->y = (y)<<ST_FP;
+ o->x0 = -3;
+ o->x1 = 1;
+ o->y0 = -2;
+ o->y1 = 2;
+ if ( st_difficulty >= 5 )
+ {
+ if ( (st_rnd() & 3) == 0 )
+ {
+ o->ot = ST_OT_BIG_TRASH;
+ o->y0--;
+ o->y1++;
+ o->x0--;
+ o->x1++;
+ }
+ }
+}
+
+/*
+ x,y are pixel coordinats within the play arey
+*/
+void st_NewTrashDust(uint8_t x, uint8_t y, int ot)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ o->ot = ot;
+ st_SetXY(o, x, y);
+ //o->x = (x)<<ST_FP;
+ //o->y = (y)<<ST_FP;
+ o->x0 = 0;
+ o->x1 = 0;
+ o->y0 = -2;
+ o->y1 = 2;
+}
+
+void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot)
+{
+ st_NewTrashDust(x>>ST_FP, y>>ST_FP, ot);
+}
+
+
+void st_NewWall(void)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ int8_t h;
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ o->ot = ST_OT_WALL_SOLID;
+ h = st_rnd();
+ h &= 63;
+ h = (int8_t)(((int16_t)h*(int16_t)(ST_AREA_HEIGHT/4))>>6);
+ h += ST_AREA_HEIGHT/6;
+
+ o->x0 = 0;
+ o->x1 = 5;
+ o->x = (ST_AREA_WIDTH-1)<<ST_FP;
+
+ if ( (st_rnd() & 1) == 0 )
+ {
+ o->y = (ST_AREA_HEIGHT-1)<<ST_FP;
+
+ o->y0 = -h;
+ o->y1 = 0;
+ }
+ else
+ {
+ o->y = (0)<<ST_FP;
+ o->y0 = 0;
+ o->y1 = h;
+ }
+}
+
+void st_NewPlayerMissle(uint8_t x, uint8_t y)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ o->ot = ST_OT_MISSLE;
+ st_SetXY(o, x, y);
+ //o->x = x<<ST_FP;
+ //o->y = y<<ST_FP;
+ o->x0 = -4;
+ o->x1 = 1;
+ o->y0 = 0;
+ o->y1 = 0;
+}
+
+void st_SetupPlayer(uint8_t objnr, uint8_t ot)
+{
+ st_obj *o = st_GetObj(objnr);
+ switch(ot)
+ {
+ case ST_OT_PLAYER:
+ o->ot = ot;
+ o->y0 = -2;
+ o->y1 = 2;
+ break;
+ case ST_OT_PLAYER2:
+ o->ot = ot;
+ o->y0 = -2;
+ o->y1 = 5;
+ break;
+ case ST_OT_PLAYER3:
+ o->ot = ot;
+ o->y0 = -5;
+ o->y1 = 5;
+ break;
+ }
+}
+
+void st_NewPlayer(void)
+{
+ st_obj *o;
+ int8_t objnr = st_NewObj();
+ if ( objnr < 0 )
+ return;
+ o = st_GetObj(objnr);
+ o->x = 6<<ST_FP;
+ o->y = (ST_AREA_HEIGHT/2)<<ST_FP;
+ o->x0 = -6;
+ o->x1 = 0;
+ st_SetupPlayer(objnr, ST_OT_PLAYER);
+}
+
+/*================================================================*/
+/* trash creation */
+/*================================================================*/
+
+void st_InitDeltaWall(void)
+{
+ uint8_t i;
+ uint8_t cnt = 0;
+ uint8_t max_x = 0;
+ uint8_t max_l;
+
+ uint8_t min_dist_for_new = 40;
+ uint8_t my_difficulty = st_difficulty;
+
+ if ( st_difficulty >= 2 )
+ {
+
+ max_l = ST_AREA_WIDTH;
+ max_l -= min_dist_for_new;
+
+ if ( my_difficulty > 30 )
+ my_difficulty = 30;
+ min_dist_for_new -= my_difficulty;
+
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ if ( st_objects[i].ot == ST_OT_WALL_SOLID )
+ {
+ cnt++;
+ if ( max_x < (st_objects[i].x>>ST_FP) )
+ max_x = (st_objects[i].x>>ST_FP);
+ }
+ }
+ /* if ( cnt < upper_trash_limit ) */
+ if ( max_x < max_l )
+ {
+ st_NewWall();
+ }
+ }
+}
+
+
+void st_InitDeltaTrash(void)
+{
+ uint8_t i;
+ uint8_t cnt = 0;
+ uint8_t max_x = 0;
+ uint8_t max_l;
+
+ uint8_t upper_trash_limit = ST_OBJ_CNT-7;
+ uint8_t min_dist_for_new = 20;
+ uint8_t my_difficulty = st_difficulty;
+
+ if ( my_difficulty > 14 )
+ my_difficulty = 14;
+ min_dist_for_new -= my_difficulty;
+
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ if ( st_objects[i].ot == ST_OT_TRASH1 || st_objects[i].ot == ST_OT_TRASH2 || st_objects[i].ot == ST_OT_GADGET || st_objects[i].ot == ST_OT_BIG_TRASH )
+ {
+ cnt++;
+ if ( max_x < (st_objects[i].x>>ST_FP) )
+ max_x = (st_objects[i].x>>ST_FP);
+ }
+ }
+
+ max_l = ST_AREA_WIDTH;
+ max_l -= min_dist_for_new;
+
+ if ( cnt < upper_trash_limit )
+ if ( max_x < max_l )
+ {
+ if ( (st_difficulty >= 3) && ((st_rnd() & 7) == 0) )
+ st_NewGadget(ST_AREA_WIDTH-1, rand() & (ST_AREA_HEIGHT-1));
+ else
+ st_InitTrash(ST_AREA_WIDTH-1, rand() & (ST_AREA_HEIGHT-1),0 );
+ }
+}
+
+void st_InitDelta(void)
+{
+ st_InitDeltaTrash();
+ st_InitDeltaWall();
+ /*
+
+ uint8_t cnt;
+ cnt = st_CntObj(2);
+ if ( cnt == 0 )
+ st_InitBrick1();
+ */
+}
+
+/*================================================================*/
+/* API: game draw procedure */
+/*================================================================*/
+
+void st_DrawInGame(uint8_t fps)
+{
+ uint8_t i;
+ /* draw all objects */
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ st_DrawObj(i);
+
+ //dog_ClrBox(0, ST_AREA_HEIGHT, st_u8g2->width-1, ST_AREA_HEIGHT+3);
+
+ u8g2_SetDrawColor(st_u8g2, 0);
+ u8g2_DrawBox(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT-3, st_u8g2->width, 4);
+
+ u8g2_SetDrawColor(st_u8g2, 1);
+ u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT+1, ST_AREA_WIDTH);
+ u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one, ST_AREA_WIDTH);
+ u8g2_SetFont(st_u8g2, u8g_font_4x6r);
+ u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_difficulty));
+ u8g2_DrawHLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT-3, (st_to_diff_cnt>>ST_DIFF_FP)+1);
+ u8g2_DrawVLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT-4, 3);
+ u8g2_DrawVLine(st_u8g2, 10+ST_DIFF_VIS_LEN, u8g_height_minus_one - ST_AREA_HEIGHT-4, 3);
+
+
+ /* player points */
+ u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_player_points_delayed));
+
+
+ /* FPS output */
+ if ( fps > 0 )
+ {
+ //i = dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4, ST_AREA_HEIGHT, font_4x6, "FPS:");
+ i = u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2-7*4, u8g_height_minus_one - ST_AREA_HEIGHT, "FPS:");
+
+ //dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4+i, ST_AREA_HEIGHT, font_4x6, st_itoa(fps));
+ u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH-5*4-2-7*4+i, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(fps));
+ }
+ /*dog_DrawStr(60+i, ST_AREA_HEIGHT, font_4x6, st_itoa(st_CntObj(0)));*/
+}
+
+void st_Draw(uint8_t fps)
+{
+ switch(st_state)
+ {
+ case ST_STATE_PREPARE:
+ case ST_STATE_IPREPARE:
+ //dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "SpaceTrash");
+ u8g2_SetFont(st_u8g2, u8g_font_4x6r);
+ u8g2_SetDrawColor(st_u8g2, 1);
+ //dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("SpaceTrash"));
+ u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height-6)/2, "SpaceTrash");
+ //dog_SetHLine(st_u8g2->width-st_to_diff_cnt-10, st_u8g2->width-st_to_diff_cnt, (st_u8g2->height-6)/2-1);
+ u8g2_DrawHLine(st_u8g2, st_u8g2->width-st_to_diff_cnt-10, u8g_height_minus_one - (st_u8g2->height-6)/2+1, 11);
+ break;
+ case ST_STATE_GAME:
+ st_DrawInGame(fps);
+ break;
+ case ST_STATE_END:
+ case ST_STATE_IEND:
+ u8g2_SetFont(st_u8g2, u8g_font_4x6r);
+ u8g2_SetDrawColor(st_u8g2, 1);
+ //dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "Game Over");
+ //dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("Game Over"));
+ u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height-6)/2, "Game Over");
+ //dog_DrawStr(50, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_player_points));
+ u8g2_DrawStr(st_u8g2, 50, u8g_height_minus_one - (st_u8g2->height-6)/2, st_itoa(st_player_points));
+ //dog_DrawStr(75, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_highscore));
+ u8g2_DrawStr(st_u8g2, 75, u8g_height_minus_one - (st_u8g2->height-6)/2, st_itoa(st_highscore));
+ //dog_SetHLine(st_to_diff_cnt, st_to_diff_cnt+10, (st_u8g2->height-6)/2-1);
+ u8g2_DrawHLine(st_u8g2, st_to_diff_cnt, u8g_height_minus_one - (st_u8g2->height-6)/2+1, 11);
+ break;
+ }
+}
+
+void st_SetupInGame(void)
+{
+ st_player_points = 0;
+ st_player_points_delayed = 0;
+ st_difficulty = 1;
+ st_to_diff_cnt = 0;
+ st_ClrObjs();
+ st_NewPlayer();
+ /* st_InitBrick1(); */
+}
+
+
+/*================================================================*/
+/* API: game setup */
+/*================================================================*/
+
+void st_Setup(u8g2_t *u8g)
+{
+ st_u8g2 = u8g;
+ u8g2_SetBitmapMode(u8g, 1);
+ u8g_height_minus_one = u8g->height;
+ u8g_height_minus_one--;
+}
+
+/*================================================================*/
+/* API: game step execution */
+/*================================================================*/
+
+/*
+ player_pos: 0..255
+*/
+void st_StepInGame(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire)
+{
+ uint8_t i, j;
+ uint8_t missle_mask;
+
+ /* rescale player pos */
+ //st_player_pos = ((uint16_t)player_pos * (uint16_t)ST_AREA_HEIGHT)/256;
+ if ( player_pos < 64 )
+ st_player_pos = 0;
+ else if ( player_pos >= 192 )
+ st_player_pos = ST_AREA_HEIGHT-2-1;
+ else
+ st_player_pos = ((uint16_t)((player_pos-64)) * (uint16_t)(ST_AREA_HEIGHT-2))/128;
+ st_player_pos+=1;
+ /* move all objects */
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ st_Move(i);
+
+ /* check for objects which left the play area */
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ if ( st_objects[i].ot != 0 )
+ if ( st_IsOut(i) != 0 )
+ st_Disappear(i);
+
+ /* missle and destruction handling */
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ {
+ missle_mask = st_GetMissleMask(i);
+ if ( missle_mask != 0 ) /* should we apply missle handling? */
+ if ( st_CalcXY(st_objects+i) != 0 ) /* yes: calculate pixel reference point (st_px_x, st_px_y) */
+ for( j = 0; j < ST_OBJ_CNT; j++ ) /* has any other object been hit? */
+ if ( i != j ) /* except missle itself... */
+ if ( st_IsHit(j, st_px_x, st_px_y, missle_mask) != 0 ) /* let the member function decide */
+ { /* let the member function destroy the object if required */
+ st_Destroy(i);
+ }
+ }
+
+ /* handle fire counter */
+ st_FireStep(is_auto_fire, is_fire);
+
+ /* fire */
+ for( i = 0; i < ST_OBJ_CNT; i++ )
+ st_Fire(i);
+
+ /* create new objects */
+ st_InitDelta();
+
+ /* increase difficulty */
+
+ st_to_diff_cnt++;
+ if ( st_to_diff_cnt == (ST_DIFF_VIS_LEN<<ST_DIFF_FP) )
+ {
+ st_to_diff_cnt = 0;
+ st_difficulty++;
+ st_player_points += ST_POINTS_PER_LEVEL;
+ }
+
+ /* update visible player points */
+ if ( st_player_points_delayed < st_player_points )
+ st_player_points_delayed++;
+}
+
+void st_Step(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire)
+{
+ switch(st_state)
+ {
+ case ST_STATE_PREPARE:
+ st_to_diff_cnt = st_u8g2->width-10; /* reuse st_to_diff_cnt */
+ st_state = ST_STATE_IPREPARE;
+ break;
+ case ST_STATE_IPREPARE:
+ st_to_diff_cnt--;
+ if ( st_to_diff_cnt == 0 )
+ {
+ st_state = ST_STATE_GAME;
+ st_SetupInGame();
+ }
+ break;
+ case ST_STATE_GAME:
+ st_StepInGame(player_pos, is_auto_fire, is_fire);
+ break;
+ case ST_STATE_END:
+ st_to_diff_cnt = st_u8g2->width-10; /* reuse st_to_diff_cnt */
+ if ( st_highscore < st_player_points)
+ st_highscore = st_player_points;
+ st_state = ST_STATE_IEND;
+ break;
+ case ST_STATE_IEND:
+ st_to_diff_cnt--;
+ if ( st_to_diff_cnt == 0 )
+ st_state = ST_STATE_PREPARE;
+ break;
+ }
+}
+
+
+
+void setup(void) {
+ u8g2.begin();
+}
+
+uint8_t a;
+uint8_t b;
+uint8_t y = 128;
+
+void loop(void) {
+
+ u8g2.setFont(u8g2_font_6x10_tr);
+ u8g2.setFontDirection(0);
+ u8g2.setFontRefHeightAll();
+
+ st_Setup(u8g2.getU8g2());
+ for(;;)
+ {
+ st_Step(y, /* is_auto_fire */ 0, /* is_fire */ digitalRead(pin_fire));
+ u8g2.firstPage();
+ do
+ {
+ st_Draw(0);
+ } while( u8g2.nextPage() );
+
+ if ( digitalRead(pin_down) ) {
+ y++;
+ }
+
+ if ( digitalRead(pin_up) ) {
+ y--;
+ }
+ }
+}
+
+