I have a nice skeleton started.
Code: Select all
// Rommie.cpp
// A Chess Engine
// By Michael Sherwin
#include <bit>
#include "Defines.cpp"
#include "Variables.cpp"
#include "Move.cpp"
#include "GenMoves.cpp"
#include "Search.cpp"
#include "GetCommand.cpp"
#include "Initialize.cpp"
#include "Main.cpp"
Code: Select all
// Defines.cpp
typedef char s08;
typedef unsigned char u08;
typedef int s32;
typedef unsigned long long u64;
enum { EXIT, GETCMD, ROMMIE, MOVE };
enum { BLACK, WHITE };
enum {
EMPTY,
WP2, WP3, WP4, WP5, WP6, WP7, WN, WB, WRC, WR, WQ, WKC, WK, WCS, WCL,
BP7, BP6, BP5, BP4, BP3, BP2, BN, BB, BRC, BR, BQ, BKC, BK, BCS, BCL
};
enum {
A1, B1, C1, D1, E1, F1, G1, H1,
A2, B2, C2, D2, E2, F2, G2, H2,
A3, B3, C3, D3, E3, F3, G3, H3,
A4, B4, C4, D4, E4, F4, G4, H4,
A5, B5, C5, D5, E5, F5, G5, H5,
A6, B6, C6, D6, E6, F6, G6, H6,
A7, B7, C7, D7, E7, F7, G7, H7,
A8, B8, C8, D8, E8, F8, G8, H8
};
enum { FILE1, FILE2, FILE3, FILE4, FILE5, FILE6, FILE7, FILE8 };
enum { RANK1, RANK2, RANK3, RANK4, RANK5, RANK6, RANK7, RANK8 };
struct Rays {
u64 rayNW;
u64 rayNN;
u64 rayNE;
u64 rayEE;
u64 raySE;
u64 raySS;
u64 raySW;
u64 rayWW;
u64 rwsNW;
u64 rwsNN;
u64 rwsNE;
u64 rwsEE;
u64 rwsSE;
u64 rwsSS;
u64 rwsSW;
u64 rwsWW;
};
struct sMove {
u08 fs;
u08 ts;
u08 ft;
u08 tt;
s32 sc;
};
union uMove {
sMove s;
u64 m;
};
struct Thread {
u64 pieceSquareBits[2];
s32 board[64];
s32 stm;
s32 ply;
};
#define pieceSquareBits t->pieceSquareBits
#define board t->board
#define stm t->stm
#define ply t->ply
Code: Select all
// Variables.cpp
s32 mode;
Rays ray[65];
u64 bob[64];
u64 rob[64];
u64 qob[64];
Thread* thread[32];
Thread* t;
Code: Select all
// Main.cpp
s32 main() {
Initialize();
while (mode != EXIT) {
if (mode == GETCMD) GetCommand();
if (mode == ROMMIE) RLSearch(t);
if (mode == MOVE) GameMove();
}
return 0;
}
Code: Select all
// Initialize.cpp
void NewGame() {
}
void Initialize() {
int sq, ts, file, rank, c, maxThreads;
mode = GETCMD;
maxThreads = 32;
Thread* Rommie = new Thread[maxThreads];
for (c = 0; c < maxThreads; c++) {
thread[c] = Rommie + c;
}
t = thread[0];
ray[64].rayNW = 0;
ray[64].rayNN = 0;
ray[64].rayNE = 0;
ray[64].rayEE = 0;
ray[64].raySE = 0;
ray[64].raySS = 0;
ray[64].raySW = 0;
ray[64].rayWW = 0;
for (sq = A1; sq <= H8; sq++) {
file = sq & 7;
rank = sq >> 3;
bob[sq] = 0;
rob[sq] = 0;
qob[sq] = 0;
// Northwest
ray[sq].rayNW = 0;
for (c = 1, ts = sq + 7; file - c >= FILE1 && rank + c <= RANK8; c++, ts += 7) ray[sq].rayNW |= 1ull << ts;
ray[sq].rwsNW |= ray[sq].rayNW & 0x8000000000000001;
bob[sq] |= ray[sq].rayNW;
// Northeast
ray[sq].rayNE = 0;
for (c = 1, ts = sq + 9; file + c <= FILE8 && rank + c <= RANK8; c++, ts += 9) ray[sq].rayNE |= 1ull << ts;
ray[sq].rwsNE |= ray[sq].rayNE & 0x8000000000000001;
bob[sq] |= ray[sq].rayNE;
// Southeast
ray[sq].raySE = 0;
for (c = 1, ts = sq - 7; file + c <= FILE8 && rank - c >= RANK1; c++, ts -= 7) ray[sq].raySE |= 1ull << ts;
ray[sq].rwsSE |= ray[sq].raySE & 0x8000000000000001;
bob[sq] |= ray[sq].raySE;
// Southwest
ray[sq].raySW = 0;
for (c = 1, ts = sq - 9; file - c >= FILE1 && rank - c >= RANK1; c++, ts -= 9) ray[sq].raySW |= 1ull << ts;
ray[sq].rwsSW |= ray[sq].raySW & 0x8000000000000001;
bob[sq] |= ray[sq].raySW;
// North
ray[sq].rayNN = 0;
for (c = 1, ts = sq + 8; rank + c <= RANK8; c++, ts += 8) ray[sq].rayNN |= 1ull << ts;
ray[sq].rwsNN |= ray[sq].rayNN & 0x8000000000000001;
rob[sq] |= ray[sq].rayNN;
// East
ray[sq].rayEE = 0;
for (c = 1, ts = sq + 1; file + c <= FILE8; c++, ts += 1) ray[sq].rayEE |= 1ull << ts;
ray[sq].rwsEE |= ray[sq].rayEE & 0x8000000000000001;
rob[sq] |= ray[sq].rayEE;
// South
ray[sq].raySS = 0;
for (c = 1, ts = sq - 8; rank - c >= RANK1; c++, ts -= 8) ray[sq].raySS |= 1ull << ts;
ray[sq].rwsSS |= ray[sq].raySS & 0x8000000000000001;
rob[sq] |= ray[sq].raySS;
// West
ray[sq].rayWW = 0;
for (c = 1, ts = sq - 1; file - c >= FILE1; c++, ts -= 1) ray[sq].rayWW |= 1ull << ts;
ray[sq].rwsWW |= ray[sq].rayWW & 0x8000000000000001;
rob[sq] |= ray[sq].rayWW;
qob[sq] = bob[sq] | rob[sq];
}
}
Code: Select all
// Search.cpp
void RootSearch(Thread* t, s32 depth) {
}
void IterativeDeepeningSearch(Thread* t) {
s32 depth;
for (depth = 1; ; depth++) {
RootSearch(t, depth);
}
}
// reinforcement learning in real time
void RLSearch(Thread* t) {
// RL code
IterativeDeepeningSearch(t);
}
The code so far is just to support writing the GenMoves function. I haven't got very far yet but it will come together in the next few days. Speed is of course is the goal. Like in RomiChess only the bitboards will be generated as they are very efficient for finding moves for staged move generation and removing the corresponding bit when a move is found. It is also efficient for determining legality instead of calling Incheck() all the time. On newer CPUs there is plenty of instruction cache so having more code than say on a 80386 is no problem. Some of the case statements can be combined like I used to do but that type of code is not pretty code in my opinion. The pawns by Rank are all different pseudo types, to save time, as it is known for each pseudo type what to do. The rook and king also have a pseudo types depending if castling is still possible or not. Once castling moves are found and stored MakeMove and TakeBack have the pseudo types WCS, WCL, BCS, BCL to speed up that processing. And when castling is not possible then no more clock cycles will be wasted. By itself it makes little difference but everything adds up.
Code: Select all
// GenMoves.cpp
s32 GenMoves(Thread* t) {
u64 fromSquares, bb, notMe, occ, captures;
u08 fs;
s32 ft;
notMe = pieceSquareBits[1 - stm];
fromSquares = pieceSquareBits[stm];
occ = fromSquares | notMe;
do {
fs = std::countr_zero(fromSquares);
fromSquares ^= 1ull << fs;
ft = board[fs];
switch (ft) {
case EMPTY:
// can't get here
break;
case WP2:
break;
case WP3:
break;
case WP4:
break;
case WP5:
break;
case WP6:
break;
case WP7:
break;
case WN:
break;
case WB:
break;
case WRC:
case WR:
break;
case WQ:
occ |= 0x8000000000000001;
bb = ray[std::countr_zero(ray[fs].rwsNW & occ)].rayNW
| ray[std::countr_zero(ray[fs].rwsNN & occ)].rayNN
| ray[std::countr_zero(ray[fs].rwsNE & occ)].rayNE
| ray[std::countr_zero(ray[fs].rwsEE & occ)].rayEE
| ray[63 - std::countl_zero(ray[fs].rwsSE & occ)].raySE
| ray[63 - std::countl_zero(ray[fs].rwsSS & occ)].raySS
| ray[63 - std::countl_zero(ray[fs].rwsSW & occ)].raySW
| ray[63 - std::countl_zero(ray[fs].rwsWW & occ)].rayWW
^ qob[fs]
& notMe;
break;
case WKC:
case WK:
break;
case WCS:
case WCL:
// can't get here
break;
case BP7:
break;
case BP6:
break;
case BP5:
break;
case BP4:
break;
case BP3:
break;
case BP2:
break;
case BN:
break;
case BB:
break;
case BRC:
case BR:
break;
case BQ:
occ |= 0x8000000000000001;
bb = ray[std::countr_zero(ray[fs].rwsNW & occ)].rayNW
| ray[std::countr_zero(ray[fs].rwsNN & occ)].rayNN
| ray[std::countr_zero(ray[fs].rwsNE & occ)].rayNE
| ray[std::countr_zero(ray[fs].rwsEE & occ)].rayEE
| ray[63 - std::countl_zero(ray[fs].rwsSE & occ)].raySE
| ray[63 - std::countl_zero(ray[fs].rwsSS & occ)].raySS
| ray[63 - std::countl_zero(ray[fs].rwsSW & occ)].raySW
| ray[63 - std::countl_zero(ray[fs].rwsWW & occ)].rayWW
^ qob[fs]
& notMe;
break;
case BKC:
case BK:
break;
}
} while (fromSquares);
return true;
}