Herramientas de usuario

¡Esta es una revisión vieja del documento!


<file c microchess.c> * Kim-1 MicroChess © 1976-2005 Peter Jennings, www.benlo.com 6502 emulation © 2005 Bill Forster Runs an emulation of the Kim-1 Microchess on any standard C platform * All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * Part 1 * —— * Create virtual 6502 platform using standard C facilities. * Goal is to run Microchess on any platform supporting C. * * Part 1 added July 2005 by Bill Forster (www.triplehappy.com) Standard library include files #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <setjmp.h> #include <math.h> Use <setjmp.h> macros and functions to emulate the “jump to reset stack pointer then restart program” behaviour used by microchess jmp_buf jmp_chess; #define EXIT -1 #define RESTART -2 void RESTART_CHESS( void ) start CHESS program with reset stack { longjmp( jmp_chess, RESTART ); } void EXIT_TO_SYSTEM( void ) return to operating system { longjmp( jmp_chess, EXIT ); } 6502 emulation memory typedef unsigned char byte; byte zeropage[256]; byte stack[256]; byte stack_cy[256]; byte stack_v[256]; 6502 emulation registers byte reg_a, reg_f, reg_x, reg_y, reg_s, reg_cy, reg_v, temp_cy; unsigned int temp1, temp2; Debug stuff #if 0 #define DBG , register_dump() #else #define DBG #endif void register_dump( void ) { printf( “A=%02x X=%02x Y=%02x S=%02x F=%02X CY=%d V=%d\n”, reg_a, reg_x, reg_y, reg_s, reg_f, reg_cy, reg_v ); } 6502 emulation macros - register moves #define T(src,dst) reg_f = (dst) = (src) DBG #define A reg_a #define S reg_s #define X reg_x #define Y reg_y #define TYA T(Y,A) #define TXS T(X,S) #define TAX T(A,X) #define TAY T(A,Y) #define TSX T(S,X) #define TXA T(X,A) 6502 emulation macros - branches #define BEQ(label) if( reg_f == 0 ) goto label #define BNE(label) if( reg_f != 0 ) goto label #define BPL(label) if( ! (reg_f&0x80) ) goto label #define BMI(label) if( reg_f & 0x80 ) goto label #define BCC(label) if( !reg_cy ) goto label #define BCS(label) if( reg_cy ) goto label #define BVC(label) if( !reg_v ) goto label #define BVS(label) if( reg_v ) goto label #define BRA(label) /*extra*/ goto label 6502 emulation macros - call/return from functions #define JSR(func) func() #define RTS return 6502 emulation macros - jump to functions, note that in assembly language jumping to a function is a more efficient way of calling the function then returning, so we emulate that in the high level language by (actually) calling then returning. There is no JEQ 6502 opcode, but it's useful to us so we have made it up! (like BRA, SEV) #define JMP(func) if( 1 ) { func(); return; } \ else else eats ';' #define JEQ(func) /*extra*/ if( reg_f == 0 ) { func(); return; } \ else else eats ';' 6502 emulation macros - load registers Addressing conventions; default addressing mode is zero page, else indicate with suffix; i = immediate x = indexed, zero page f = indexed, not zero page (f for “far”) #define ZP(addr8) (zeropage[ (byte) (addr8) ]) #define ZPX(addr8,idx) (zeropage[ (byte) 1) ]) #define LDAi(dat8) reg_f = reg_a = dat8 DBG #define LDAx(addr8,idx) reg_f = reg_a = ZPX(addr8,idx) DBG #define LDAf(addr16,idx) reg_f = reg_a = (addr16)[idx] DBG #define LDA(addr8) reg_f = reg_a = ZP(addr8) DBG #define LDXi(dat8) reg_f = reg_x = dat8 DBG #define LDX(addr8) reg_f = reg_x = ZP(addr8) DBG #define LDYi(dat8) reg_f = reg_y = dat8 DBG #define LDY(addr8) reg_f = reg_y = ZP(addr8) DBG #define LDYx(addr8,idx) reg_f = reg_y = ZPX(addr8,idx) DBG 6502 emulation macros - store registers #define STA(addr8) ZP(addr8) = reg_a DBG #define STAx(addr8,idx) ZPX(addr8,idx) = reg_a DBG #define STX(addr8) ZP(addr8) = reg_x DBG #define STY(addr8) ZP(addr8) = reg_y DBG #define STYx(addr8,idx) ZPX(addr8,idx) = reg_y DBG 6502 emulation macros - set/clear flags #define CLD luckily CPU's BCD flag is cleared then never set #define CLC reg_cy = 0 DBG #define SEC reg_cy = 1 DBG #define CLV reg_v = 0 DBG #define SEV /*extra*/ reg_v = 1 /*avoid problematic V emulation*/ DBG 6502 emulation macros - accumulator logical operations #define ANDi(dat8) reg_f = (reg_a &= dat8) DBG #define ORA(addr8) reg_f = (reg_a |= ZP(addr8)) DBG 6502 emulation macros - shifts and rotates #define ASL(addr8) reg_cy = (ZP(addr8)&0x80) ? 1 : 0, \ ZP(addr8) = ZP(addr8)«1, \ reg_f = ZP(addr8) DBG #define ROL(addr8) temp_cy = (ZP(addr8)&0x80) ? 1 : 0, \ ZP(addr8) = ZP(addr8)«1, \ ZP(addr8) |= reg_cy, \ reg_cy = temp_cy, \ reg_f = ZP(addr8) DBG #define LSR reg_cy = reg_a & 0x01, \ reg_a = reg_a»1, \ reg_a &= 0x7f, \ reg_f = reg_a DBG 6502 emulation macros - push and pull #define PHA stack[reg_s–] = reg_a DBG #define PLA reg_a = stack[++reg_s] DBG #define PHY stack[reg_s–] = reg_y DBG #define PLY reg_y = stack[++reg_s] DBG #define PHP stack [reg_s] = reg_f, \ stack_cy[reg_s] = reg_cy, \ stack_v [reg_s] = reg_v, \ reg_s– DBG #define PLP reg_s++, \ reg_f = stack [reg_s], \ reg_cy = stack_cy[reg_s], \ reg_v = stack_v [reg_s] DBG 6502 emulation macros - compare #define cmp(reg,dat) reg_f = 2), \ reg_cy = 3)

1)
addr8)+(idx
2)
reg) - (dat
3)
reg) >= (dat) ? 1 : 0) DBG #define CMPi(dat8) cmp( reg_a, dat8 ) #define CMP(addr8) cmp( reg_a, ZP(addr8) ) #define CMPx(addr8,idx) cmp( reg_a, ZPX(addr8,idx) ) #define CMPf(addr16,idx) cmp( reg_a, (addr16)[idx] ) #define CPXi(dat8) cmp( reg_x, dat8 ) #define CPXf(addr16,idx) cmp( reg_x, (addr16)[idx] ) #define CPYi(dat8) cmp( reg_y, dat8 ) 6502 emulation macros - increment,decrement #define DEX reg_f = –reg_x DBG #define DEY reg_f = –reg_y DBG #define DEC(addr8) reg_f = –ZP(addr8) DBG #define INX reg_f = ++reg_x DBG #define INY reg_f = ++reg_y DBG #define INC(addr8) reg_f = ++ZP(addr8) DBG #define INCx(addr8,idx) reg_f = ++ZPX(addr8,idx) DBG 6502 emulation macros - add #define adc(dat) temp1 = reg_a, \
                          temp2 = (dat),                   \
                          temp1 += (temp2+(reg_cy?1:0)),   \
                          reg_f = reg_a = (byte)temp1,     \
                          reg_cy = ((temp1&0xff00)?1:0)         DBG
#define ADCi(dat8) adc( dat8 ) #define ADC(addr8) adc( ZP(addr8) ) #define ADCx(addr8,idx) adc( ZPX(addr8,idx) ) #define ADCf(addr16,idx) adc( (addr16)[idx] ) 6502 emulation macros - subtract (note that both as an input and an output cy flag has opposite sense to that used for adc(), seems unintuitive to me) #define sbc(dat) temp1 = reg_a, \ temp2 = (dat), \ temp1 -= (temp2+(reg_cy?0:1)), \ reg_f = reg_a = (byte)temp1, \ reg_cy = ((temp1&0xff00)?0:1) DBG #define SBC(addr8) sbc( ZP(addr8) ) #define SBCx(addr8,idx) sbc( ZPX(addr8,idx) ) Test some of the trickier opcodes (hook this up as needed) void test_function( void ) { byte hi, lo; LDAi (0x33); 0x4444 - 0x3333 = 0x1111
              STA     (0);
              STA     (1);
              LDAi    (0x44);
              SEC;
              SBC     (0);
              lo      = reg_a;
              LDAi    (0x44);
              SBC     (1);
              hi      = reg_a;
              LDAi    (0x44);     // 0x3333 - 0x4444 = 0xeeef
              STA     (0);
              STA     (1);
              LDAi    (0x33);
              SEC;
              SBC     (0);
              lo      = reg_a;
              LDAi    (0x33);
              SBC     (1);
              hi      = reg_a;
              LDAi    (0x33);     // 0x3333 + 0x4444 = 0x7777
              STA     (0);
              STA     (1);
              LDAi    (0x44);
              CLC;
              ADC     (0);
              lo      = reg_a;
              LDAi    (0x44);
              ADC     (1);
              hi      = reg_a;
} * * Part 2 * —— * Original microchess program by Peter Jennings, www.benlo.com * In this form, 6502 assembly language has been minimally transformed * to run with the virtual 6502 in C facilities created in part 1. * (New comments by Bill Forster are identified with text (WRF)) page zero variables const byte BOARD = 0x50; const byte BK = 0x60; const byte PIECE = 0xB0; const byte SQUARE = 0xB1; const byte SP2 = 0xB2; const byte SP1 = 0xB3; const byte INCHEK = 0xB4; const byte STATE = 0xB5; const byte MOVEN = 0xB6; const byte REV = 0xB7; const byte OMOVE = 0xDC; const byte WCAP0 = 0xDD; const byte COUNT = 0xDE; const byte BCAP2 = 0xDE; const byte WCAP2 = 0xDF; const byte BCAP1 = 0xE0; const byte WCAP1 = 0xE1; const byte BCAP0 = 0xE2; const byte MOB = 0xE3; const byte MAXC = 0xE4; const byte CC = 0xE5; const byte PCAP = 0xE6; const byte BMOB = 0xE3; const byte BMAXC = 0xE4; const byte BMCC = 0xE5; was BCC (TASS doesn't like it as a label) const byte BMAXP = 0xE6; const byte XMAXC = 0xE8; const byte WMOB = 0xEB; const byte WMAXC = 0xEC; const byte WCC = 0xED; const byte WMAXP = 0xEE; const byte PMOB = 0xEF; const byte PMAXC = 0xF0; const byte PCC = 0xF1; const byte PCP = 0xF2; const byte OLDKY = 0xF3; const byte BESTP = 0xFB; const byte BESTV = 0xFA; const byte BESTM = 0xF9; const byte DIS1 = 0xFB; const byte DIS2 = 0xFA; const byte DIS3 = 0xF9; const byte temp = 0xFC; (WRF) For C version, data definitions precede code references to data byte SETW[] = { 0x03, 0x04, 0x00, 0x07, 0x02, 0x05, 0x01, 0x06,
                      0x10, 0x17, 0x11, 0x16, 0x12, 0x15, 0x14, 0x13,
                      0x73, 0x74, 0x70, 0x77, 0x72, 0x75, 0x71, 0x76,
                      0x60, 0x67, 0x61, 0x66, 0x62, 0x65, 0x64, 0x63
              };
byte MOVEX[] = { 0x00, 0xF0, 0xFF, 0x01, 0x10, 0x11, 0x0F, 0xEF, 0xF1,
                      0xDF, 0xE1, 0xEE, 0xF2, 0x12, 0x0E, 0x1F, 0x21
              };
byte POINTS[] = { 0x0B, 0x0A, 0x06, 0x06, 0x04, 0x04, 0x04, 0x04,
                      0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
              };
byte OPNING[] = { 0x99, 0x25, 0x0B, 0x25, 0x01, 0x00, 0x33, 0x25,
                      0x07, 0x36, 0x34, 0x0D, 0x34, 0x34, 0x0E, 0x52,
                      0x25, 0x0D, 0x45, 0x35, 0x04, 0x55, 0x22, 0x06,
                      0x43, 0x33, 0x0F, 0xCC
              };
(WRF) level information: | Level | addr=02F2 | addr=018B | | (level1) | (level2) +————-+———–+————- | SUPER BLITZ | 00 | FF | BLITZ | 00 | FB | NORMAL | 08 | FB static byte level1=8; static byte level2=0xfb; (WRF) Forward declarations void CHESS( void ); void JANUS( void ); void INPUT( void ); void DISP( void ); void GNMZ( void ); void GNMX( void ); void GNM( void ); void RUM( void ); void STRV( void ); void SNGMV( void ); void LINE( void ); void REVERSE( void ); void CMOVE( void ); void RESET( void ); void GENRM( void ); void UMOVE( void ); void MOVE( void ); void CKMATE( void ); void GO( void ); void DISMV( void ); void STRATGY( void ); void POUT( void ); void POUT5(void ); void POUT8(void ); void POUT9( void ); void POUT10( void ); void POUT12( void ); void POUT13( void ); void KIN( void ); void syskin( void ); void syschout( void ); void syshexout( void ); void PrintDig( void ); WRF debug stuff static void show_move_evaluation( int ivalue ); static void show_move_generation( byte src, byte dst ); static int bool_show_move_evaluation; static int bool_show_move_generation; Start here; Was *=$1000 ; load into RAM @ $1000-$15FF int main( int argc, char* argv[] ) {
              LDAi    (0x00);             // REVERSE TOGGLE
              STA     (REV);
           // JSR     (Init_6551);
              if( EXIT != setjmp(jmp_chess) )
                  CHESS();    // after setjmp() and then any
                              //  subsequent RESTART_CHESS()
              return(0);  // after EXIT_TO_SYSTEM()
} void CHESS( void ) { CHESS_BEGIN: CLD; INITIALIZE
              LDXi    (0xFF);             // TWO STACKS
              TXS;
              LDXi    (0xC8);
              STX     (SP2);
ROUTINES TO LIGHT LED DISPLAY AND GET KEY FROM KEYBOARD /*OUT:*/ JSR (POUT); DISPLAY AND
              JSR     (KIN);              // GET INPUT   *** my routine waits for a keypress
CMP (OLDKY); KEY IN ACC * no need to debounce BEQ (OUT); (DEBOUNCE) STA (OLDKY); CMPi (0x43); [C] BNE (NOSET); SET UP LDXi (0x1F); BOARD WHSET: LDAf (SETW,X); FROM STAx (BOARD,X); SETW DEX; BPL (WHSET); LDXi (0x1B); *ADDED STX (OMOVE); INITS TO 0xFF LDAi (0xCC); Display CCC BNE (CLDSP); NOSET: CMPi (0x45); [E] BNE (NOREV); REVERSE JSR (REVERSE); BOARD IS SEC; LDAi (0x01); SBC (REV); STA (REV); TOGGLE REV FLAG LDAi (0xEE); IS BNE (CLDSP); NOREV: CMPi (0x40); [P] BNE (NOGO); PLAY CHESS JSR (GO); CLDSP: STA (DIS1); DISPLAY STA (DIS2); ACROSS STA (DIS3); DISPLAY BNE (CHESS_BEGIN); NOGO: CMPi (0x0D); [Enter] BNE (NOMV); MOVE MAN JSR (MOVE); AS ENTERED JMP (DISP); NOMV: CMPi (0x41); [Q] *Added to allow game exit* BEQ (DONE); quit the game, exit back to system. JMP (INPUT); DONE: JMP (EXIT_TO_SYSTEM); JMP (0xFF00); * MUST set this to YOUR OS starting address } THE ROUTINE JANUS DIRECTS THE ANALYSIS BY DETERMINING WHAT SHOULD OCCUR AFTER EACH MOVE GENERATED BY GNM void JANUS( void ) { LDX (STATE);
              BMI     (NOCOUNT);
THIS ROUTINE COUNTS OCCURRENCES IT DEPENDS UPON STATE TO INDEX THE CORRECT COUNTERS /*COUNTS:*/ LDA (PIECE); BEQ (OVER); IF STATE=8
              CPXi    (0x08);             // DO NOT COUNT
              BNE     (OVER);             // BLK MAX CAP
              CMP     (BMAXP);            // MOVES FOR
              BEQ     (XRT);              // WHITE
OVER: INCx (MOB,X); MOBILITY
              CMPi    (0x01);             //  + QUEEN
              BNE     (NOQ);              // FOR TWO
              INCx    (MOB,X);
NOQ: BVC (NOCAP); LDYi (0x0F); CALCULATE
              LDA     (SQUARE);           // POINTS
ELOOP: CMPx (BK,Y); CAPTURED BEQ (FOUN); BY THIS
              DEY;                        // MOVE
              BPL     (ELOOP);
FOUN: LDAf (POINTS,Y);
              CMPx    (MAXC,X);
              BCC     (LESS);             // SAVE IF
              STYx    (PCAP,X);           // BEST THIS
              STAx    (MAXC,X);           // STATE
LESS: CLC; PHP; ADD TO
              ADCx    (CC,X);             // CAPTURE
              STAx    (CC,X);             // COUNTS
              PLP;
NOCAP: CPXi (0x04); BEQ (ON4); BMI (TREE); (=00 ONLY) XRT: RTS; GENERATE FURTHER MOVES FOR COUNT AND ANALYSIS ON4: LDA (XMAXC); SAVE ACTUAL STA (WCAP0); CAPTURE
              LDAi    (0x00);             // STATE=0
              STA     (STATE);
              JSR     (MOVE);             // GENERATE
              JSR     (REVERSE);          // IMMEDIATE
              JSR     (GNMZ);             // REPLY MOVES
              JSR     (REVERSE);
LDAi (0x08); STATE=8
              STA     (STATE);            // GENERATE
              JSR     (GNM);              // CONTINUATION
              JSR     (UMOVE);            // MOVES
JMP (STRATGY); NOCOUNT: CPXi (0xF9);
              BNE     (TREE);
DETERMINE IF THE KING CAN BE TAKEN, USED BY CHKCHK
              LDA     (BK);               // IS KING
              CMP     (SQUARE);           // IN CHECK?
              BNE     (RETJ);             // SET INCHEK=0
              LDAi    (0x00);             // IF IT IS
              STA     (INCHEK);
RETJ: RTS; IF A PIECE HAS BEEN CAPTURED BY A TRIAL MOVE, GENERATE REPLIES & EVALUATE THE EXCHANGE GAIN/LOSS TREE: BVC (RETJ); NO CAP
              LDYi    (0x07);             // (PIECES)
              LDA     (SQUARE);
LOOPX: CMPx (BK,Y);
              BEQ     (FOUNX);
              DEY;
              BEQ     (RETJ);             // (KING)
              BPL     (LOOPX);            // SAVE
FOUNX: LDAf (POINTS,Y); BEST CAP CMPx (BCAP0,X); AT THIS
              BCC     (NOMAX);            // LEVEL
              STAx    (BCAP0,X);
NOMAX: DEC (STATE);
              LDAf    (&level2,0);        // IF STATE=FB  (WRF, was LDAi (0xFB);)
              CMP     (STATE);            // TIME TO TURN
              BEQ     (UPTREE);           // AROUND
              JSR     (GENRM);            // GENERATE FURTHER
UPTREE: INC (STATE); CAPTURES RTS; } THE PLAYER'S MOVE IS INPUT void INPUT( void ) {
              CMPi    (0x08);             // NOT A LEGAL
              BCS     (ERROR);            // SQUARE #
              JSR     (DISMV);
              JMP     (DISP);             // fall through
ERROR: JMP (RESTART_CHESS); } void DISP( void ) {
              LDXi    (0x1F);
SEARCH: LDAx (BOARD,X);
              CMP     (DIS2);
              BEQ     (HERE);             // DISPLAY
              DEX;                        // PIECE AT
              BPL     (SEARCH);           // FROM
HERE: STX (DIS1); SQUARE STX (PIECE); JMP (RESTART_CHESS); } GENERATE ALL MOVES FOR ONE SIDE, CALL JANUS AFTER EACH ONE FOR NEXT STEP void GNMZ( void ) { LDXi (0x10); CLEAR
              JMP     (GNMX);             // fall through
} void GNMX( void ) {
              LDAi    (0x00);             // COUNTERS
CLEAR: STAx (COUNT,X);
              DEX;
              BPL     (CLEAR);
              JMP     (GNM);              // fall though
} void GNM( void ) {
              LDAi    (0x10);             // SET UP
              STA     (PIECE);            // PIECE
NEWP: DEC (PIECE); NEW PIECE BPL (NEX); ALL DONE?
              RTS;                        //    -YES
NEX: JSR (RESET); READY
              LDY     (PIECE);            // GET PIECE
              LDXi    (0x08);
              STX     (MOVEN);            // COMMON START
              CPYi    (0x08);             // WHAT IS IT?
              BPL     (PAWN);             // PAWN
              CPYi    (0x06);
              BPL     (KNIGHT);           // KNIGHT
              CPYi    (0x04);
              BPL     (BISHOP);           // BISHOP
              CPYi    (0x01);
              BEQ     (QUEEN);            // QUEEN
              BPL     (ROOK);             // ROOK
KING: JSR (SNGMV); MUST BE KING!
              BNE     (KING);             // MOVES
              BEQ     (NEWP);             // 8 TO 1
QUEEN: JSR (LINE);
              BNE     (QUEEN);            // MOVES
              BEQ     (NEWP);             // 8 TO 1
ROOK: LDXi (0x04); STX (MOVEN); MOVES AGNR: JSR (LINE); 4 TO 1 BNE (AGNR); BEQ (NEWP); BISHOP: JSR (LINE);
              LDA     (MOVEN);            // MOVES
              CMPi    (0x04);             // 8 TO 5
              BNE     (BISHOP);
              BEQ     (NEWP);
KNIGHT: LDXi (0x10); STX (MOVEN); MOVES AGNN: JSR (SNGMV); 16 TO 9 LDA (MOVEN); CMPi (0x08); BNE (AGNN); BEQ (NEWP); PAWN: LDXi (0x06);
              STX     (MOVEN);
P1: JSR (CMOVE); RIGHT CAP? BVC (P2); BMI (P2); JSR (JANUS); YES P2: JSR (RESET);
              DEC     (MOVEN);            // LEFT CAP?
              LDA     (MOVEN);
              CMPi    (0x05);
              BEQ     (P1);
P3: JSR (CMOVE); AHEAD BVS (NEWP); ILLEGAL
              BMI     (NEWP);
              JSR     (JANUS);
              LDA     (SQUARE);           // GETS TO
              ANDi    (0xF0);             // 3RD RANK?
              CMPi    (0x20);
              BEQ     (P3);               // DO DOUBLE
              BRA     (NEWP);             // JMP (NEWP);
} CALCULATE SINGLE STEP MOVES FOR K,N void SNGMV( void ) {
              JSR     (CMOVE);            // CALC MOVE
              BMI     (ILL1);             // -IF LEGAL
              JSR     (JANUS);            // -EVALUATE
ILL1: JSR (RESET);
              DEC     (MOVEN);
              RTS;
} CALCULATE ALL MOVES DOWN A STRAIGHT LINE FOR Q,B,R void LINE( void ) { LINE: JSR (CMOVE); CALC MOVE BCC (OVL); NO CHK
              BVC     (LINE);             // NOCAP
OVL: BMI (ILL); RETURN PHP; JSR (JANUS); EVALUATE POSN
              PLP;
              BVC     (LINE);             // NOT A CAP
ILL: JSR (RESET); LINE STOPPED DEC (MOVEN); NEXT DIR
              RTS;
} EXCHANGE SIDES FOR REPLY ANALYSIS void REVERSE( void ) {
              LDXi    (0x0F);
ETC: SEC;
              LDYx    (BK,X);             // SUBTRACT
              LDAi    (0x77);             // POSITION
              SBCx    (BOARD,X);          // FROM 77
              STAx    (BK,X);
              STYx    (BOARD,X);          // AND
              SEC;
              LDAi    (0x77);             // EXCHANGE
              SBCx    (BOARD,X);          // PIECES
              STAx    (BOARD,X);
              DEX;
              BPL     (ETC);
              RTS;
} CMOVE CALCULATES THE TO SQUARE USING SQUARE AND THE MOVE TABLE FLAGS SET AS FOLLOWS: N - ILLEGAL MOVE V - CAPTURE (LEGAL UNLESS IN CH) C - ILLEGAL BECAUSE OF CHECK [MY THANKS TO JIM BUTTERFIELD WHO WROTE THIS MORE EFFICIENT VERSION OF CMOVE] void CMOVE( void ) { byte src; LDA (SQUARE); GET SQUARE
              src     = reg_a;
              LDX     (MOVEN);            // MOVE POINTER
              CLC;
              ADCf    (MOVEX,X);          // MOVE LIST
              STA     (SQUARE);           // NEW POS'N
              ANDi    (0x88);
              BNE     (ILLEGAL);          // OFF BOARD
              LDA     (SQUARE);
              if( bool_show_move_generation )
                  show_move_generation( src, reg_a );
LDXi (0x20); LOOP: DEX; IS TO
              BMI     (NO);               // SQUARE
              CMPx    (BOARD,X);          // OCCUPIED?
              BNE     (LOOP);
CPXi (0x10); BY SELF?
              BMI     (ILLEGAL);
LDAi (0x7F); MUST BE CAP! ADCi (0x01); SET V FLAG SEV; LDAi(0x80); Avoid problematic V emulation
              BVS     (SPX);              // (JMP)
NO: CLV; NO CAPTURE SPX: LDA (STATE); SHOULD WE
              BMI     (RETL);             // DO THE
              CMPf    (&level1,0);        // CHECK CHECK? (WRF: was CMPi (0x08);)
              BPL     (RETL);
CHKCHK REVERSES SIDES AND LOOKS FOR A KING CAPTURE TO INDICATE ILLEGAL MOVE BECAUSE OF CHECK SINCE THIS IS TIME CONSUMING, IT IS NOT ALWAYS DONE /*CHKCHK:*/ PHA; STATE
              PHP;
              LDAi    (0xF9);
              STA     (STATE);            // GENERATE
              STA     (INCHEK);           // ALL REPLY
              JSR     (MOVE);             // MOVES TO
              JSR     (REVERSE);          // SEE IF KING
              JSR     (GNM);              // IS IN
              JSR     (RUM);              // CHECK
              PLP;
              PLA;
              STA     (STATE);
              LDA     (INCHEK);
              BMI     (RETL);             // NO - SAFE
              SEC;                        // YES - IN CHK
              LDAi    (0xFF);
              RTS;
RETL: CLC; LEGAL
              LDAi    (0x00);             // RETURN
              RTS;
ILLEGAL: LDAi (0xFF); CLC; ILLEGAL
              CLV;                        // RETURN
              RTS;
} REPLACE PIECE ON CORRECT SQUARE void RESET( void ) { LDX (PIECE); GET LOGAT
              LDAx    (BOARD,X);          // FOR PIECE
              STA     (SQUARE);           // FROM BOARD
              RTS;
} void GENRM( void ) { JSR (MOVE); MAKE MOVE /*GENR2:*/ JSR (REVERSE); REVERSE BOARD JSR (GNM); GENERATE MOVES
              JMP     (RUM);              // fall through
} void RUM( void ) {
              JSR     (REVERSE);          // REVERSE BACK
              JMP     (UMOVE);            // fall through
} ROUTINE TO UNMAKE A MOVE MADE BY MOVE void UMOVE( void ) {
              TSX;                        // UNMAKE MOVE
              STX     (SP1);
              LDX     (SP2);              // EXCHANGE
              TXS;                        // STACKS
              PLA;                        // MOVEN
              STA     (MOVEN);
              PLA;                        // CAPTURED
              STA     (PIECE);            // PIECE
              TAX;
              PLA;                        // FROM SQUARE
              STAx    (BOARD,X);
              PLA;                        // PIECE
              TAX;
              PLA;                        // TO SOUARE
              STA     (SQUARE);
              STAx    (BOARD,X);
              JMP     (STRV);
} THIS ROUTINE MOVES PIECE TO SQUARE, PARAMETERS ARE SAVED IN A STACK TO UNMAKE THE MOVE LATER void MOVE( void ) { TSX;
              STX     (SP1);              // SWITCH
              LDX     (SP2);              // STACKS
              TXS;
              LDA     (SQUARE);
              PHA;                        // TO SQUARE
              TAY;
              LDXi    (0x1F);
CHECK: CMPx (BOARD,X); CHECK FOR BEQ (TAKE); CAPTURE
              DEX;
              BPL     (CHECK);
TAKE: LDAi (0xCC);
              STAx    (BOARD,X);
              TXA;                        // CAPTURED
              PHA;                        // PIECE
              LDX     (PIECE);
              LDAx    (BOARD,X);
              STYx    (BOARD,X);          // FROM
              PHA;                        // SQUARE
              TXA;
              PHA;                        // PIECE
              LDA     (MOVEN);
              PHA;                        // MOVEN
              JMP     (STRV);             // fall through
} (WRF) Fortunately when we swap stacks we jump here and swap back before returning. So we aren't swapping stacks to do threading (if we were we would need to enhance 6502 stack emulation to incorporate our subroutine mechanism, instead we simply use the native C stack for subroutine return addresses). void STRV( void ) { TSX; STX (SP2); SWITCH
              LDX     (SP1);              // STACKS
              TXS;                        // BACK
              RTS;
} CONTINUATION OF SUB STRATGY -CHECKS FOR CHECK OR CHECKMATE AND ASSIGNS VALUE TO MOVE void CKMATE( void ) { LDX (BMAXC); CAN BLK CAP
              CPXf    (POINTS,0);         // MY KING?
              BNE     (NOCHEK);
              LDAi    (0x00);             // GULP!
              BEQ     (RETV);             // DUMB MOVE!
NOCHEK: LDX (BMOB); IS BLACK
              BNE     (RETV);             // UNABLE TO
              LDX     (WMAXP);            // MOVE AND
              BNE     (RETV);             // KING IN CH?
              LDAi    (0xFF);             // YES! MATE
RETV: LDXi (0x04); RESTORE
              STX     (STATE);            // STATE=4
THE VALUE OF THE MOVE (IN ACCU) IS COMPARED TO THE BEST MOVE AND REPLACES IT IF IT IS BETTER if( bool_show_move_evaluation ) show_move_evaluation( reg_a ); /*PUSH:*/ CMP (BESTV); IS THIS BEST
              BCC     (RETP);             // MOVE SO FAR?
              BEQ     (RETP);
              if( bool_show_move_evaluation )
                  printf( "NEW BEST MOVE\n" );
              STA     (BESTV);            // YES!
              LDA     (PIECE);            // SAVE IT
              STA     (BESTP);
              LDA     (SQUARE);
              STA     (BESTM);            // FLASH DISPLAY
RETP: LDAi ('.'); print … instead of flashing disp JMP (syschout); print . and return } MAIN PROGRAM TO PLAY CHESS PLAY FROM OPENING OR THINK void GO( void ) {
              LDX     (OMOVE);            // OPENING?
              BMI     (NOOPEN);           // -NO   *ADD CHANGE FROM BPL
              LDA     (DIS3);             // -YES WAS
              CMPf    (OPNING,X);         // OPPONENT'S
              BNE     (END);              // MOVE OK?
              DEX;
              LDAf    (OPNING,X);         // GET NEXT
              STA     (DIS1);             // CANNED
              DEX;                        // OPENING MOVE
              LDAf    (OPNING,X);
              STA     (DIS3);             // DISPLAY IT
              DEX;
              STX     (OMOVE);            // MOVE IT
              BNE     (MV2);              // (JMP)
END: LDAi (0xFF); *ADD - STOP CANNED MOVES
              STA     (OMOVE);            // FLAG OPENING
NOOPEN: LDXi (0x0C); FINISHED STX (STATE); STATE=C
              STX     (BESTV);            // CLEAR BESTV
              LDXi    (0x14);             // GENERATE P
              JSR     (GNMX);             // MOVES
LDXi (0x04); STATE=4
              STX     (STATE);            // GENERATE AND
              JSR     (GNMZ);             // TEST AVAILABLE
MOVES
              LDX     (BESTV);            // GET BEST MOVE
              CPXi    (0x0F);             // IF NONE
              BCC     (MATE);             // OH OH!
MV2: LDX (BESTP); MOVE
              LDAx    (BOARD,X);          // THE
              STA     (BESTV);            // BEST
              STX     (PIECE);            // MOVE
              LDA     (BESTM);
              STA     (SQUARE);           // AND DISPLAY
              JSR     (MOVE);             // IT
              JMP     (RESTART_CHESS);
MATE: LDAi (0xFF); RESIGN
              RTS;                        // OR STALEMATE
} SUBROUTINE TO ENTER THE PLAYER'S MOVE void DISMV( void ) {
              LDXi    (0x04);             // ROTATE
DROL: ASL (DIS3); KEY ROL (DIS2); INTO
              DEX;                        // DISPLAY
              BNE     (DROL);             //
              ORA     (DIS3);
              STA     (DIS3);
              STA     (SQUARE);
              RTS;
} THE FOLLOWING SUBROUTINE ASSIGNS A VALUE TO THE MOVE UNDER CONSIDERATION AND RETURNS IT IN THE ACCUMULATOR void STRATGY( void ) {
              CLC;
              LDAi    (0x80);
              ADC     (WMOB);             // PARAMETERS
              ADC     (WMAXC);            // WITH WEIGHT
              ADC     (WCC);              // OF O.25
              ADC     (WCAP1);
              ADC     (WCAP2);
              SEC;
              SBC     (PMAXC);
              SBC     (PCC);
              SBC     (BCAP0);
              SBC     (BCAP1);
              SBC     (BCAP2);
              SBC     (PMOB);
              SBC     (BMOB);
              BCS     (POS);              // UNDERFLOW
              LDAi    (0x00);             // PREVENTION
POS: LSR;
              CLC;                        // **************
              ADCi    (0x40);
              ADC     (WMAXC);            // PARAMETERS
              ADC     (WCC);              // WITH WEIGHT
              SEC;                        // OF 0.5
              SBC     (BMAXC);
              LSR;                        // **************
              CLC;
              ADCi    (0x90);
              ADC     (WCAP0);            // PARAMETERS
              ADC     (WCAP0);            // WITH WEIGHT
              ADC     (WCAP0);            // OF 1.0
              ADC     (WCAP0);
              ADC     (WCAP1);
              SEC;                        // [UNDER OR OVER-
              SBC     (BMAXC);            // FLOW MAY OCCUR
              SBC     (BMAXC);            // FROM THIS
              SBC     (BMCC);             // SECTION]
              SBC     (BMCC);
              SBC     (BCAP1);
              LDX     (SQUARE);           // ***************
              CPXi    (0x33);
              BEQ     (POSN);             // POSITION
              CPXi    (0x34);             // BONUS FOR
              BEQ     (POSN);             // MOVE TO
              CPXi    (0x22);             // CENTRE
              BEQ     (POSN);             // OR
              CPXi    (0x25);             // OUT OF
              BEQ     (POSN);             // BACK RANK
              LDX     (PIECE);
              BEQ     (NOPOSN);
              LDYx    (BOARD,X);
              CPYi    (0x10);
              BPL     (NOPOSN);
POSN: CLC;
              ADCi    (0x02);
NOPOSN: JMP (CKMATE); CONTINUE } * * Part 3 * —— * Text based interface over RS-232 port added later. * * Part 3 added August 2002 by Daryl Richtor —————————————————————– The following routines were added to allow text-based board display over a standard RS-232 port. (WRF) For C version, data definitions precede code references to data char banner[] = “MicroChess © 1976-2005 Peter Jennings, www.benlo.com\r\n”; char cpl[] = “WWWWWWWWWWWWWWWWBBBBBBBBBBBBBBBBWWWWWWWWWWWWWWWW”; char cph[] = “KQRRBBNNPPPPPPPPKQRRBBNNPPPPPPPP”; void POUT( void ) { JSR (POUT9); print CRLF JSR (POUT13); print copyright JSR (POUT10); print column labels LDYi (0x00); init board location JSR (POUT5); print board horz edge POUT1: LDAi ('|'); print vert edge JSR (syschout); PRINT ONE ASCII CHR - SPACE LDXi (0x1F); POUT2: TYA; scan the pieces for a location match CMPx (BOARD,X); match found? BEQ (POUT4); yes, print the piece's color and type DEX; no BPL (POUT2); if not the last piece, try again TYA; empty square ANDi (0x01); odd or even column? STA (temp); save it TYA; is the row odd or even LSR; shift column right 4 spaces LSR; LSR; LSR; ANDi (0x01); strip LSB CLC; ADC (temp); combine row & col to determine square color ANDi (0x01); is board square white or blk? BEQ (POUT25); white, print space LDAi ('#'); black, print # BRA (POUT99); DB 0x2c used to skip over LDA #0x20 POUT25: LDAi (' '); ASCII space POUT99: JSR (syschout); PRINT ONE ASCII CHR - SPACE JSR (syschout); PRINT ONE ASCII CHR - SPACE POUT3: INY; TYA; get row number ANDi (0x08); have we completed the row? BEQ (POUT1); no, do next column LDAi ('|'); yes, put the right edge on JSR (syschout); PRINT ONE ASCII CHR - | JSR (POUT12); print row number JSR (POUT9); print CRLF JSR (POUT5); print bottom edge of board CLC; TYA; ADCi (0x08); point y to beginning of next row TAY; CPYi (0x80); was that the last row? JEQ (POUT8); (BEQ) yes, print the LED values BNE (POUT1); no, do new row POUT4: LDA (REV); print piece's color & type BEQ (POUT41); LDAf (cpl+16,X); BNE (POUT42); POUT41: LDAf (cpl,X); POUT42: JSR (syschout); LDAf (cph,X); JSR (syschout); BNE (POUT3); branch always } void POUT5( void ) { TXA; print “—–…—–<crlf>” PHA; LDXi (0x19); LDAi ('-'); POUT6: JSR (syschout); PRINT ONE ASCII CHR - “-” DEX; BNE (POUT6); PLA; TAX; JSR (POUT9); RTS; } void POUT8( void ) { JSR (POUT10); LDA (0xFB); JSR (syshexout); PRINT 1 BYTE AS 2 HEX CHRS LDAi (0x20); JSR (syschout); PRINT ONE ASCII CHR - SPACE LDA (0xFA); JSR (syshexout); PRINT 1 BYTE AS 2 HEX CHRS LDAi (0x20); JSR (syschout); PRINT ONE ASCII CHR - SPACE LDA (0xF9); JSR (syshexout); PRINT 1 BYTE AS 2 HEX CHRS JMP (POUT9); fall through } void POUT9( void ) { LDAi (0x0D); JSR (syschout); PRINT ONE ASCII CHR - CR LDAi (0x0A); JSR (syschout); PRINT ONE ASCII CHR - LF RTS; } void POUT10( void ) { LDXi (0x00); print the column labels POUT11: LDAi (0x20); 00 01 02 03 … 07 <CRLF> JSR (syschout); TXA; JSR (syshexout); INX; CPXi (0x08); BNE (POUT11); JEQ (POUT9); JMP (POUT12); fall through } void POUT12( void ) { TYA; ANDi (0x70); JSR (syshexout); RTS; } void POUT13( void ) { LDXi (0x00); Print the copyright banner POUT14: LDAf (banner,X); BEQ (POUT15); JSR (syschout); INX; BNE (POUT14); POUT15: RTS; } void KIN( void ) { LDAi ('?'); JSR (syschout); PRINT ONE ASCII CHR - ? JSR (syskin); GET A KEYSTROKE FROM SYSTEM ANDi (0x4F); MASK 0-7, AND ALPHA'S RTS; } 6551 I/O Support Routines /* Init_6551 lda #0x1F 19.2K/8/1 sta ACIActl control reg lda #0x0B N parity/echo off/rx int off/ dtr active low sta ACIAcmd command reg rts done */ (WRF) See enhanced syskin() routine in Part 4 input chr from ACIA1 (waiting) /* syskin lda ACIASta Serial port status and #0x08 is recvr full beq syskin no character to get Lda ACIAdat get chr RTS */ (WRF) See enhanced syschout() routine in Part 4 output to OutPut Port /* syschout PHA save registers ACIA_Out1 lda ACIASta serial port status and #0x10 is tx buffer empty beq ACIA_Out1 no PLA get chr sta ACIAdat put character to Port RTS done */ Print as hex digits void syshexout( void ) { PHA; prints AA hex digits LSR; MOVE UPPER NIBBLE TO LOWER LSR; LSR; LSR; JSR (PrintDig); PLA; JMP (PrintDig); fall through } void PrintDig( void ) { char Hexdigdata[] = “0123456789ABCDEF”; ANDi (0x0F); prints A hex nibble (low 4 bits) PHY; TAY; LDAf (Hexdigdata,Y); PLY; JMP (syschout); } * * Part 4 * —— * Enhance text interface by creating 'smart' syskin(), syschout() * routines. * * Part 4 added July 2005 by Bill Forster (www.triplehappy.com) ** Misc prototypes static char algebraic_file( byte square ); static char algebraic_rank( byte square ); static char octal_file( char file ); static char octal_rank( char rank ); Here are the commands available in the enhanced interface static char help[] = “Los comandos son;\n” “ w ;empezar jugando blancas contra microchess jugando negras\n” “ b ;empezar jugando negras contra microchess jugando blancas\n” “ nnnn ;(eg 6343 = P-K4) mover pieza usando coordenadas numéricas\n” “ anan ;(eg e7e5 = negro P-K4, e2e4 = blanco P-K4) mover con notación \n” “ ; algebráica \n” “ oo ;enroque a rey\n” “ ooo ;enroque a reina\n” “ f ;jugar movimiento\n” “ p ;forzar movimiento a la CPU\n” “ a ;conmutar autojugado (éste inserta comandos \'p\' y \'f\' )\n” “ c ;limpiar tablero\n” “ e ;alternar (invertir) el lado del tablero\n” “ ln ;ajustar nivel, n=1 (flojo), 2 (medio), 3 (fuerte)\n” “ hh ;editor de piezas, ver lugar de la pieza, ej 01, reina de la CPU\n” “ hh=xx ;editor de piezas, colocar pieza, ej 01=64 o 01=e2\n” “ hh= ;editor, borrar pieza, ej 01=, borrar reina de la CPU\n” “ m ;depuración, alterna info sobre generar un movimiento\n” “ v ;depuración, alterna info sobre evaluar un movimiento\n” “ ;Note que la depuración es muy locuaz y lo mejor \n” “ ; es redirigirla a un fichero (esp. generando movimientos)\n” “ q ;salir\n” “?”; Alternatively, allow a primitive interface for DOS/Windows systems that closely simulates the RS-232 interface originally envisaged for part 3 #define PRIMITIVE_INTERFACE normally commented out #ifdef PRIMITIVE_INTERFACE #include <conio.h> these routines emulate dumb terminal in/out #endif Forward declaration of smart in/out alternatives void smart_out( char c ); char smart_in( void ); Character in void syskin( void ) { #ifdef PRIMITIVE_INTERFACE reg_a = (byte)getch(); #else reg_a = (byte)smart_in(); #endif } Character out void syschout( void ) { #ifdef PRIMITIVE_INTERFACE putch( (int)reg_a ); #else smart_out( (char)reg_a ); #endif } Smart character out, supplements enhanced interface of smart_in() static int discard = 1194; Discard until initial CLEAR and EXCHANGE commands are complete The discard mechanism optionally discards characters - this is useful because the smart_in() routine works by converting higher level commands into a a series of primitive commands. The discard mechanism allows us to skip over (discard) the board displays generated for all of the intermediate primitive commands. The values assigned to discard are in each case determined by simple trial and error void smart_out( char c ) { static char first='?'; replace first '?' with message below if( discard ) discard–; else { if( first && c==first ) { printf( “ (escriba ? para ayuda)\n?” ); first = '\0'; } else { if( c != '\r' )printf converts “\n” to “\r\n” so don't need “\r” printf( “%c”, c ); } } } Smart character in, provides a help screen + algebraic notation interface + position editor + diagnostics commands etc. char smart_in( void ) { static char error[] = “Movimiento o comando no válido, escribe ? para ayuda\n?”; static char buf[20] = “ CE”; start with a CLEAR then EXCHANGE command static int offset=1; static int bool_auto=1; char color, file, rank, file2, rank2, ch='\0'; int i, len, bool_okay; byte piece, square; char *s; Get orientation; is human player white or black ? byte bool_white = ZP(REV); Emit buffered commands until '\0' if( offset ) ch = buf[offset++]; Loop until command ready while( ch == '\0' ) { Reset grooming machinery offset = 0; discard = 2; remove initial “\r\n” Reset flag indicating entry of a legal command handled internally (i.e. within this function, without passing characters to underlying microchess implementation) bool_okay = 0; Get edited command line if( NULL == fgets(buf,sizeof(buf)-1,stdin) ) EXIT_TO_SYSTEM(); else { Convert to lower case, zap '\n' for( s=buf; *s; s++ ) { if( isascii(*s) && isupper(*s) ) *s = tolower(*s); else if( *s == '\n' ) *s = '\0'; } Trim string from end s = strchr(buf,'\0') - 1; while( s>=buf && (*s==' '||*s=='\t') ) *s– = '\0'; Trim string from start s = buf; while( *s==' ' || *s=='\t' ) s++; len = strlen(s); for( i=0; i<len+1; i++ ) +1 gets '\0' at end buf[i] = *s++; if no leading space this does nothing, but no harm either Convert an algebraic move eg “e2e4” into an octal microchess move if( len == 4 && 'a'⇐buf[0] && buf[0]⇐'h' && '1'⇐buf[1] && buf[1]⇐'8' && 'a'⇐buf[2] && buf[2]⇐'h' && '1'⇐buf[3] && buf[3]⇐'8' ) { file = octal_file(buf[0]); rank = octal_rank(buf[1]); file2 = octal_file(buf[2]); rank2 = octal_rank(buf[3]); buf[0] = rank; specify move microchess grid style buf[1] = file; buf[2] = rank2; buf[3] = file2; } Is it a microchess octal numeric move eg “6364” ? if( len == 4 && '0'⇐buf[0] && buf[0]⇐'7' && '0'⇐buf[1] && buf[1]⇐'7' && '0'⇐buf[2] && buf[2]⇐'7' && '0'⇐buf[3] && buf[3]⇐'7' ) { offset = 1; emit from here next if( bool_auto ) { buf[4] = '\r'; play move buf[5] = 'p'; get response buf[6] = '\0'; done discard = 2386; skip over intermediate board displays } else { buf[4] = '\0'; done discard = 1790; skip over intermediate board displays } } Is it a level command ? else if( len==2 && (buf[0]=='l' && '1'⇐buf[1] && buf[1]⇐'3' ) ) { bool_okay = 1; switch( buf[1] ) { case '1': level1 = 0; level2 = 0xff; printf( “Level 1, super blitz\n” ); break; (on 6502: 3 seconds per move) case '2': level1 = 0; level2 = 0xfb; printf( “Level 2, blitz\n” ); break; (on 6502: 10 seconds per move) case '3': level1 = 8; level2 = 0xfb; printf( “Level 3, normal\n” ); break; (on 6502: 100 seconds per move) } } Is it a single letter command ? else if( len == 1 ) { switch( buf[0] ) { Send single letter commands to underlying microchess (step 3) interface case 'c': ch = 'C'; break; case 'e': ch = 'E'; break; case 'p': ch = 'P'; discard=0; no initial “\r\n” break; case 'q': ch = 'Q'; break; case 'f': ch = '\r'; break; Toggle various features case 'a': { bool_okay = 1; bool_auto = !bool_auto; printf( “Auto play now %s\n”, bool_auto ? “enabled” : “disabled” ); break; } case 'm': { bool_okay = 1; bool_show_move_generation = !bool_show_move_generation; printf( “Show move generation now %s\n”, bool_show_move_generation ? “enabled” : “disabled” ); break; } case 'v': { bool_okay = 1; bool_show_move_evaluation = !bool_show_move_evaluation; printf( “Show move evaluation now %s\n”, bool_show_move_evaluation ? “enabled” : “disabled” ); break; } Start a white game by emitting “clear” and “reverse” commands. Make sure we set to “black” orientation before clear command else we get a nasty mirror image chess board case 'w': { strcpy( buf, bool_white?“ece”:“ce” ); discard = bool_white?1194:598; offset = 1; emit from here next break; } Start a black game by emitting [“reverse”], “clear”, and “play” commands. Make sure we set to “black” orientation before clear command else we get a nasty mirror image chess board case 'b': { strcpy( buf, bool_white?“ecp”:“cp” ); discard = bool_white?1194:598; offset = 1; emit from here next break; } } } Algebraic castling - emit as two half moves else if( 0==strcmp(buf,“oo”) || 0==strcmp(buf,“ooo”) ) { if( bool_auto ) { if( 0 == strcmp(buf,“oo”) ) strcpy( buf, bool_white ? “7476\r7775\rp” : “7371\r7072\rp” ); else strcpy( buf, bool_white ? “7472\r7073\rp” : “7375\r7774\rp” ); offset = 1; discard = 5422; skip intermediate boards } else { printf( “Castling only available in auto play mode” “ (use \'a\' command)\n” ); bool_okay = 1; } } Piece editor ? else if( len>=2 && '0'⇐buf[0] && buf[0]⇐'1' && isascii(buf[1]) && isxdigit(buf[1]) ) { bool_okay = 0; assume syntax is bad unless proven otherwise if( len == 2 ) bool_okay = 1; view else if( len==3 && buf[2]=='=' ) bool_okay = 1; delete else if( len==5 && buf[2]=='=' && ( '0'⇐buf[3] && buf[3]⇐'7' && '0'⇐buf[4] && buf[4]⇐'7' ) ) { bool_okay = 1; octal edit file = buf[4]; rank = buf[3]; } else if( len==5 && buf[2]=='=' && ( 'a'⇐buf[3] && buf[3]⇐'h' && '1'⇐buf[4] && buf[4]⇐'8' ) ) { bool_okay = 1; algebraic edit file = octal_file(buf[3]); rank = octal_rank(buf[4]); } If piece editor command with correct syntax if( bool_okay ) { First two characters are hex 00-1f indicating one of the 32 pieces piece = buf[1]>='a' ? buf[1]-'a'+10 : buf[1]-'0'; if( buf[0] == '1' ) piece += 16; square = ZP(BOARD+piece); square our piece is occupying If edit place our piece on specified square, after making sure no other piece is on that square if( len == 5 ) edit ? { square = (rank-'0')*16 + (file-'0'); for( i=0; i<32; i++ ) { if( ZP(BOARD+i) == square ) delete other piece? ZP(BOARD+i)= 0xcc; microchess convention } ZP(BOARD+piece) = square; } If delete assign special illegal square value to piece else if( len == 3 ) ZP(BOARD+piece) = 0xcc; microchess convention Report on the color and type of piece … if( piece < 16 ) color = bool_white?'B':'W'; else color = bool_white?'W':'B'; printf( “Piece %c%c is %s %c%c ”, buf[0], buf[1], (piece&0x0f) < 2 ? “the” : “a”, color, “KQRRBBNNPPPPPPPP”[piece&0x0f] ); … and the square it (now) occupies if( square & 0x88 ) printf( “and is not on the board\n” ); else { printf( “%son square %02x”, len==3?“previously ”:“”, square ); printf( “ (algebraic %c%c)”, algebraic_file(square), algebraic_rank(square) ); if( len == 3 ) printf( “ now deleted” ); printf(“\n”); } POUT(); } } Emit the first of a buffered series of commands ? if( offset ) ch = buf[0]; If still no command available, illegal or unknown command if( ch == '\0' ) { if( len==0 || bool_okay ) if bool_okay internal command printf( “?” ); else if( buf[0] == '?' ) printf( help ); else printf( error ); } } } return( ch ); } Show internally generated move void show_move_generation( byte src, byte dst ) { static byte lookup[64] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 }; static char spaces[]= “ ”; int i, indent; char ch; byte square, piece; Indent according to state printf( “\n” ); if( ZP(STATE) >= 0xf5 ) indent = (ZP(STATE)-0xf5)*4; else indent = ZP(STATE); printf( strchr(spaces,'\0') - indent ); Print two characters for each square for( i=0; i<64; i++ ) { square = lookup[i]; ch = ' '; empty by default for( piece=0; piece<32; piece++ ) unless we find a piece { if( ZP(BOARD+piece) == square ) { ch = “KQRRBBNNPPPPPPPPkqrrbbnnpppppppp”[piece]; break; } } printf( “%c”, ch ); if( square == src ) printf( “*” ); highlight src square like this else if( square == dst ) printf( “@” ); highlight dst square like this else printf( “ ” ); normally no hightlight Next row if( (i&7) == 7 ) { printf( “\n” ); printf( strchr(spaces,'\0') - indent ); } } Also show the most important debug variable information printf( “state=%02x ”, ZP(STATE) ); } Show numeric move evaluation static void show_move_evaluation( int ivalue ) { Compare ivalue calculated by microchess with independently calculated float value, then float value scaled into same range as ivalue double value; int svalue; Counters byte wcap0 = ZP(WCAP0); byte wcap1 = ZP(WCAP1); byte wmaxc = ZP(WMAXC); byte wcc = ZP(WCC ); byte wmob = ZP(WMOB ); byte wcap2 = ZP(WCAP2); byte bmaxc = ZP(BMAXC); byte bcc = ZP(BMCC ); byte bcap1 = ZP(BCAP1); byte pmaxc = ZP(PMAXC); byte pcc = ZP(PCC ); byte pmob = ZP(PMOB ); byte bcap0 = ZP(BCAP0); byte bcap2 = ZP(BCAP2); byte bmob = ZP(BMOB ); Show move printf( “\nEvaluating move %c-%c%c\n”, “KQRRBBNNpppppppp”[ZP(PIECE)&0x0f], algebraic_file(ZP(SQUARE)), algebraic_rank(ZP(SQUARE)) ); Calculate weighted sum value = 4.00 * (wcap0) + 1.25 * (wcap1) + 0.75 * (wmaxc + wcc) + 0.25 * (wmob + wcap2) - 2.50 * (bmaxc) - 2.00 * (bcc) - 1.25 * (bcap1) - 0.25 * (pmaxc + pcc + pmob + bcap0 + bcap2 + bmob); printf( “(+4) WCAP0=%u\n”, wcap0 ); printf( “(+1.25) WCAP1=%u\n”, wcap1 ); printf( “(+0.75) WMAXC=%u WCC=%u\n”, wmaxc, wcc ); printf( “(+0.25) WMOB =%u WCAP2=%u\n”, wmob, wcap2 ); printf( “(-2.50) BMAXC=%u\n”, bmaxc ); printf( “(-2.00) BCC =%u\n”, bcc ); printf( “(-1.25) BCAP1=%u\n”, bcap1 ); printf( “(-0.25) PMAXC=%u PCC=%u PMOB=%u BCAP0=%u BCAP2=%u BMOB=%u\n”, pmaxc, pcc, pmob, bcap0, bcap2, bmob ); printf( “Weighted sum = %f\n”, value ); Calculate scaled weighted sum, corresponds to single byte value used internally by microchess svalue = (int)floor(208.0 + value); 208 = 0x90+0x40 from STRATGY(); printf( “Scaled weighted sum = %d\n”, svalue ); Comment on correspondence (or otherwise) of two values printf( “Move value = %d” , ivalue ); if( ivalue == 0 ) printf( “ (minimum, I'm in check?)\n”, ivalue ); else if( ivalue == 255 ) printf( “ (maximum, I'm delivering mate?)\n”, ivalue ); else if( ivalue == svalue ) printf( “ (=scaled weighted sum)\n” ); else if( ivalue == svalue+2 ) printf( “ (=scaled weighted sum plus 2 bonus points)\n” ); else printf( “ (unexpected value, suspect overflow or underflow)\n” ); printf( “best so far = %u\n”, ZP(BESTV) ); } Get algebraic file 'a'-'h' from octal square static char algebraic_file( byte square ) { char file = square & 0x0f; byte bool_white = ZP(REV); if( bool_white ) file = 'a' + file; eg 0→'a', 7→'h' else if( black ) file = 'a' + (7-file); eg 7→'a', 0→'h' return( file ); } Get algebraic rank '1'-'8' from octal square static char algebraic_rank( byte square ) { char rank = (square»4) & 0x0f; byte bool_white = ZP(REV); if( bool_white ) rank = '1' + (7-rank); eg 7→'1', 0→'8' else if( black ) rank = '1' + rank; eg 0→'1', 7→'8' return( rank ); } Get microchess file '0'-'7' from algebraic file 'a'-'h' static char octal_file( char file ) { byte bool_white = ZP(REV); if( bool_white ) file = '0' + (file-'a'); eg 'a'→'0', 'h'→'7' else if( black ) file = '7' - (file-'a'); eg 'a'→'7', 'h'→'0' return( file ); } Get microchess rank '0'-'7' from algebraic rank '1'-'8' static char octal_rank( char rank ) { byte bool_white = ZP(REV); if( bool_white ) rank = '7' - (rank-'1'); eg '1'→'7', '8'→'0' else if( black ) rank = '0' + (rank-'1'); eg '1'→'0', '8'→'7' return( rank ); } </code>

Última modificación:

Este sitio web utiliza cookies para guardar datos esenciales de su actividad, como su autenticación. Al entrar acepta el uso de cookies.

Más información