1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392 |
- /*
- chessengine.c
-
- "Little Rook Chess" (lrc)
- Port to u8g library
- chess for embedded 8-Bit controllers
- Copyright (c) 2012, 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.
- Note:
- UNIX_MAIN --> unix console executable
- 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
- */
- #include "u8g.h"
- //#ifndef __unix__
- //#else
- //#include <assert.h>
- //#define U8G_NOINLINE
- //#endif
- /*
- 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 */
- /*==============================================================*/
- u8g_t *lrc_u8g;
- lrc_t lrc_obj;
- /*==============================================================*/
- /* 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) U8G_NOINLINE;
- void stack_Pop(void) U8G_NOINLINE;
- void stack_InitCurrElement(void) U8G_NOINLINE;
- void stack_Init(uint8_t max) U8G_NOINLINE;
- void stack_SetMove(eval_t val, uint8_t to_pos) U8G_NOINLINE;
- uint8_t cu_NextPos(uint8_t pos) U8G_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) U8G_NOINLINE;
- void cp_SetOnBoard(uint8_t pos, uint8_t cp) U8G_NOINLINE;
- void cu_ClearBoard(void) U8G_NOINLINE;
- void chess_SetupBoard(void) U8G_NOINLINE;
- eval_t ce_Eval(void);
- void cu_ClearMoveHistory(void) U8G_NOINLINE;
- void cu_ReduceHistoryByFullMove(void) U8G_NOINLINE;
- void cu_UndoHalfMove(void) U8G_NOINLINE;
- chm_p cu_PushHalfMove(void) U8G_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 */
- stack_element_p 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) U8G_NOINLINE;
- static void cu_add_pos(char *s, uint8_t pos)
- {
- *s = pos;
- *s >>= 4;
- *s += 'a';
- s++;
- *s = pos;
- *s &= 15;
- *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[] PROGMEM = { 1, 16, -16, -1, 0 };
- static const uint8_t ce_dir_offset_bishop[] PROGMEM = { 15, 17, -17, -15, 0 };
- static const uint8_t ce_dir_offset_queen[] PROGMEM = { 1, 16, -16, -1, 15, 17, -17, -15, 0 };
- static const uint8_t ce_dir_offset_knight[] PROGMEM = {14, -14, 18, -18, 31, -31, 33, -33, 0};
- void ce_LoopDirsSingleMultiStep(const uint8_t *d, uint8_t is_multi_step)
- {
- uint8_t loop_pos;
-
- /* with all directions */
- for(;;)
- {
- if ( u8g_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 += u8g_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) U8G_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 ( u8g_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 += u8g_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
- #include <stdio.h>
- #include <string.h>
- char *piece_str[] = {
- /* 0x00 */
- " ",
- "wP",
- "wN",
- "wB",
-
- /* 0x04 */
- "wR",
- "wQ",
- "wK",
- "w?",
- /* 0x08 */
- "w?",
- "w?",
- "w?",
- "w?",
-
- /* 0x0c */
- "w?",
- "w?",
- "w?",
- "w?",
- /* 0x10 */
- "b ",
- "bP",
- "bN",
- "bB",
- "bR",
- "bQ",
- "bK",
- "b?",
- "b?",
- "b?",
- "b?",
- "b?",
- "b?",
- "b?",
- "b?",
- "b?"
- };
- void chess_Thinking(void)
- {
- uint8_t i;
- uint8_t cp = cp_GetPiece(stack_GetCurrElement()->current_cp);
-
- printf("Thinking: ", piece_str[cp], stack_GetCurrElement()->current_pos);
-
- for( i = 0; i <= lrc_obj.curr_depth; i++ )
- printf("%s ", piece_str[(lrc_obj.stack_memory+i)->current_cp]);
-
- printf(" \r");
- }
- void board_Show(void)
- {
- uint8_t i, j, cp;
- char buf[10];
- for ( i = 0; i < 8; i++ )
- {
- printf("%1d ", 7-i);
- for ( j = 0; j < 8; j++ )
- {
- /* get piece from global board */
- cp = lrc_obj.board[(7-i)*8+j];
- strcpy(buf, piece_str[cp&COLOR_PIECE_MASK]);
-
- if ( (cp & CP_MARK_MASK) != 0 )
- {
- buf[0] = '#';
- }
-
- /* mask out any bits except color and piece index */
- cp &= COLOR_PIECE_MASK;
- printf("%s %02x ", buf, cp);
-
- }
- printf("\n");
- }
- }
- int main(void)
- {
- uint8_t depth = 3;
- chess_SetupBoard();
- board_Show();
- puts("");
-
-
- /*
- chess_ClearMarks();
- chess_MarkMovable(COLOR_WHITE);
- board_Show();
- */
-
- chess_ManualMove(0x006, 0x066);
-
- printf("lrc_obj.is_game_end: %d\n" , lrc_obj.is_game_end);
- printf("lrc_obj.lost_side_color: %d\n" , lrc_obj.lost_side_color);
- chess_ComputerMove(2);
- printf("lrc_obj.is_game_end: %d\n" , lrc_obj.is_game_end);
- printf("lrc_obj.lost_side_color: %d\n" , lrc_obj.lost_side_color);
-
- board_Show();
- }
- #else
- /*==============================================================*/
- /* display menu */
- /*==============================================================*/
- //#define MNU_FONT font_5x7
- #define MNU_FONT u8g_font_5x8r
- //#define MNU_FONT font_6x9
- #define MNU_ENTRY_HEIGHT 9
- char *mnu_title = "Little Rook Chess";
- 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;
-
- u8g_SetFont(lrc_u8g, u8g_font_5x7r);
- u8g_SetDefaultForegroundColor(lrc_u8g);
- t = u8g_DrawStrP(lrc_u8g, x, y -1, U8G_PSTR("Options"));
-
- if ( is_highlight )
- u8g_DrawFrame(lrc_u8g, x-1, y - MNU_ENTRY_HEIGHT +1, t, MNU_ENTRY_HEIGHT);
- }
- void mnu_DrawEntry(uint8_t y, char *str, uint8_t is_clr_background, uint8_t is_highlight)
- {
- uint8_t t, x;
- u8g_SetFont(lrc_u8g, MNU_FONT);
- t = u8g_GetStrWidth(lrc_u8g, str);
- x = u8g_GetWidth(lrc_u8g);
- x -= t;
- x >>= 1;
-
- if ( is_clr_background )
- {
- u8g_SetDefaultBackgroundColor(lrc_u8g);
- u8g_DrawBox(lrc_u8g, x-3, (lrc_u8g->height-1) - (y+MNU_ENTRY_HEIGHT-1+2), t+5, MNU_ENTRY_HEIGHT+4);
- }
-
- u8g_SetDefaultForegroundColor(lrc_u8g);
- u8g_DrawStr(lrc_u8g, x, (lrc_u8g->height-1) - y, str);
-
- if ( is_highlight )
- {
- u8g_DrawFrame(lrc_u8g, x-1, (lrc_u8g->height-1) - y -MNU_ENTRY_HEIGHT +1, t, 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 = u8g_GetHeight(lrc_u8g);
- t -= y;
-
- /* topmost pos start half of that empty space from the top */
- t >>= 1;
- y = u8g_GetHeight(lrc_u8g);
- y -= t;
-
- y -= MNU_ENTRY_HEIGHT;
- mnu_DrawEntry(y, mnu_title, 0, 0);
-
- y -= MNU_ENTRY_HEIGHT;
-
-
- 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--;
- }
- }
- uint8_t chess_key_code = 0;
- 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;
- const uint8_t chess_pieces_body_bm[] 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[] 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[] 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
- u8g_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)
- {
- u8g_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;
-
- u8g_SetDefaultForegroundColor(lrc_u8g);
- u8g_DrawFrame(lrc_u8g, x0, chess_low_edge - y0 - chess_boxsize+1, chess_boxsize, chess_boxsize);
-
-
- if ( is_bold )
- {
- x0--;
- y0++;
-
- u8g_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 PROGMEM */
-
- if ( U8G_MODE_GET_BITS_PER_PIXEL(u8g_GetMode(lrc_u8g)) > 1 )
- {
- for( i = 0; i < 8; i++ )
- for( j = 0; j < 8; j++ )
- {
- uint8_t x,y;
- x = i;
- x*=chess_boxsize;
- y = j;
- y*=chess_boxsize;
- if ( ((i^j) & 1) == 0 )
- u8g_SetDefaultMidColor(lrc_u8g);
- else
- u8g_SetDefaultBackgroundColor(lrc_u8g);
- u8g_DrawBox(lrc_u8g, x,chess_low_edge-y-chess_boxsize+1,chess_boxsize,chess_boxsize);
- }
- //u8g_SetDefaultForegroundColor(lrc_u8g);
- }
- else
- {
- uint8_t x_offset = 1;
- u8g_SetDefaultForegroundColor(lrc_u8g);
- for( i = 0; i < 8*8; i+=8 )
- {
- for( j = 0; j < 8*8; j+=8 )
- {
- if ( ((i^j) & 8) == 0 )
- {
- u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-0);
- u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-2);
- u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-4);
- u8g_DrawPixel(lrc_u8g, j+0+x_offset, chess_low_edge - i-6);
- u8g_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-0);
- u8g_DrawPixel(lrc_u8g, j+2+x_offset, chess_low_edge - i-6);
- u8g_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-0);
- u8g_DrawPixel(lrc_u8g, j+4+x_offset, chess_low_edge - i-6);
- u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-0);
- u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-2);
- u8g_DrawPixel(lrc_u8g, j+6+x_offset, chess_low_edge - i-4);
- u8g_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;
- u8g_SetDefaultForegroundColor(lrc_u8g);
- u8g_DrawBitmapP(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;
- u8g_SetDefaultBackgroundColor(lrc_u8g);
- u8g_DrawBitmapP(lrc_u8g, j*chess_boxsize+chess_boxoffset-1, chess_low_edge - (i*chess_boxsize+chess_boxsize-chess_boxoffset), 1, 8, ptr);
- }
- }
- }
- }
-
- 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(u8g_t *u8g, uint8_t body_color)
- {
- lrc_u8g = u8g;
- chess_low_edge = u8g_GetHeight(lrc_u8g);
- chess_low_edge--;
-
- if ( U8G_MODE_GET_BITS_PER_PIXEL(u8g_GetMode(lrc_u8g)) == 1 )
- {
-
- chess_boxsize = 8;
- chess_boxoffset = 1;
- }
- else
- {
- /*
- if ( u8g_GetHeight(lrc_u8g) >= 12*8 )
- {
- chess_boxsize = 12;
- chess_boxoffset = 3;
- }
- else */ if ( u8g_GetHeight(lrc_u8g) >= 11*8 )
- {
- chess_boxsize = 10;
- chess_boxoffset = 2;
- }
- else
- {
- chess_boxsize = 8;
- chess_boxoffset = 1;
- }
-
- if ( u8g_GetHeight(lrc_u8g) > 64 )
- chess_low_edge -= (u8g_GetHeight(lrc_u8g)-chess_boxsize*8) / 2;
-
- }
-
- 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;
-
- u8g_SetFont(lrc_u8g, u8g_font_5x7);
- u8g_SetDefaultForegroundColor(lrc_u8g);
- for( i = 0; i < entries; i++ )
- {
-
- #if defined(DOGXL160_HW_GR) || defined(DOGXL160_HW_BW)
- dog_DrawStr(u8g_GetWidth(lrc_u8g)-35, u8g_GetHeight(lrc_u8g)-8*(i+1), font_5x7, cu_GetHalfMoveStr(lrc_obj.chm_pos-entries+i));
- #else
- u8g_DrawStr(lrc_u8g, u8g_GetWidth(lrc_u8g)-35, 8*(i+1), cu_GetHalfMoveStr(lrc_obj.chm_pos-entries+i));
- #endif
- }
-
- }
-
- 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(u8g_GetHeight(lrc_u8g) / 2-2, "Black wins", 1, 1);
- break;
- case COLOR_BLACK:
- mnu_DrawEntry(u8g_GetHeight(lrc_u8g) / 2-2, "White wins", 1, 1);
- break;
- default:
- mnu_DrawEntry(u8g_GetHeight(lrc_u8g) / 2-2, "Stalemate", 1, 1);
- break;
- }
- }
- }
- }
- void chess_Step(uint8_t 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, 0);
- }
- else if ( chess_key_cmd == CHESS_KEY_PREV )
- {
- chess_source_pos = chess_GetNextMarked(chess_source_pos, 1);
- }
- 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, 0);
- }
- else if ( chess_key_cmd == CHESS_KEY_PREV )
- {
- chess_target_pos = chess_GetNextMarked(chess_target_pos, 1);
- }
- 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;
- break;
- case CHESS_STATE_GAME_END:
- if ( chess_key_cmd != CHESS_KEY_NONE )
- {
- chess_state = CHESS_STATE_MENU;
- chess_SetupBoard();
- }
- break;
- }
-
- }
- #endif
|