130
|
1 //
|
|
2 // Notes:
|
|
3 // ply = half move (ie black or white's half of the move)
|
|
4
|
127
|
5 import std.stdio;
|
129
|
6 import std.ascii;
|
127
|
7 import std.traits;
|
128
|
8 import std.range;
|
|
9
|
130
|
10 enum Side {
|
128
|
11 White, Black
|
|
12 }
|
|
13
|
130
|
14 enum Name {
|
127
|
15 King, Queen, Rook, Bishop, Knight, Pawn
|
|
16 }
|
|
17
|
130
|
18 struct Piece {
|
|
19 Side side;
|
|
20 Name name;
|
129
|
21 }
|
|
22
|
130
|
23 string toString(Piece piece) {
|
129
|
24 return
|
127
|
25 [
|
|
26 [ "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" ],
|
|
27 [ "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F" ]
|
129
|
28 ]
|
130
|
29 [piece.side][piece.name];
|
127
|
30 }
|
|
31
|
130
|
32 //
|
|
33 //
|
|
34 //
|
127
|
35
|
|
36 enum File {
|
|
37 _A, _B, _C, _D, _E, _F, _G, _H
|
|
38 }
|
|
39
|
128
|
40 char toChar(File f) {
|
129
|
41 return "abcdefgh"[f];
|
128
|
42 }
|
|
43
|
127
|
44 enum Rank {
|
|
45 _1, _2, _3, _4, _5, _6, _7, _8
|
|
46 }
|
|
47
|
128
|
48 char toChar(Rank r) {
|
129
|
49 return "12345678"[r];
|
128
|
50 }
|
|
51
|
|
52 struct Coord {
|
|
53 File file;
|
|
54 Rank rank;
|
|
55 }
|
|
56
|
130
|
57 string toString(in Coord coord) {
|
|
58 return toChar(coord.file) ~ "+" ~ toChar(coord.rank);
|
128
|
59 }
|
|
60
|
130
|
61 //
|
|
62 //
|
|
63 //
|
|
64
|
127
|
65 struct Board {
|
130
|
66 struct Square {
|
|
67 this(in Side side, in Name name) {
|
|
68 occupied = true;
|
|
69 piece = Piece(side, name);
|
|
70 }
|
|
71
|
|
72 bool occupied = false;
|
|
73 Piece piece; // valid if occupied
|
|
74 }
|
|
75
|
|
76 this(in Square[8][8] squares_) {
|
|
77 squares = squares_;
|
128
|
78 }
|
|
79
|
|
80 Square square(Coord coord) const {
|
|
81 return squares[coord.file][coord.rank];
|
127
|
82 }
|
|
83
|
|
84 private:
|
130
|
85 Square * at(Coord coord) {
|
128
|
86 return &squares[coord.file][coord.rank];
|
|
87 }
|
|
88
|
130
|
89 void add(Piece piece, Coord coord) {
|
|
90 auto square = at(coord);
|
|
91 if (square.occupied) {
|
|
92 // error
|
|
93 }
|
|
94 else {
|
|
95 square.occupied = true;
|
|
96 square.piece = piece;
|
|
97 }
|
|
98 }
|
|
99
|
|
100 void remove(Coord coord) {
|
|
101 auto square = at(coord);
|
|
102 if (square.occupied) {
|
|
103 square.occupied = false;
|
|
104 }
|
|
105 else {
|
|
106 // error
|
|
107 }
|
|
108 }
|
|
109
|
|
110 void move(Coord source, Coord dest) {
|
|
111 auto source_sq = at(source);
|
|
112 auto dest_sq = at(dest);
|
|
113
|
|
114 if (source_sq.occupied && !dest_sq.occupied) {
|
|
115 source_sq.occupied = false;
|
|
116 dest_sq.occupied = true;
|
|
117 dest_sq.piece = source_sq.piece;
|
|
118 }
|
|
119 else {
|
|
120 // error
|
|
121 }
|
|
122 }
|
|
123
|
|
124 Square[8][8] squares =
|
|
125 [
|
|
126 [ Square(Side.White, Name.Rook), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook) ],
|
|
127 [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
|
|
128 [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
|
|
129 [ Square(Side.White, Name.Queen), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Queen) ],
|
|
130 [ Square(Side.White, Name.King), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.King) ],
|
|
131 [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
|
|
132 [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
|
|
133 [ Square(Side.White, Name.Rook), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook) ]
|
|
134 ];
|
|
135 }
|
|
136
|
|
137 void dump(in Board board) {
|
|
138 bool light_square = true;
|
|
139
|
|
140 foreach_reverse(r; EnumMembers!Rank) {
|
|
141 write(toChar(r));
|
|
142 foreach(f; EnumMembers!File) {
|
|
143
|
|
144 if (light_square) {
|
|
145 write("\033[47m");
|
|
146 }
|
|
147 else {
|
|
148 write("\033[40m");
|
|
149 }
|
|
150
|
|
151 Board.Square square = board.square(Coord(f, r));
|
|
152 if (square.occupied) {
|
|
153 write(toString(square.piece));
|
|
154 }
|
|
155 else {
|
|
156 write(" ");
|
|
157 }
|
|
158
|
|
159 light_square = !light_square;
|
|
160 }
|
|
161 writeln("\033[0m");
|
|
162
|
|
163 light_square = !light_square;
|
|
164 }
|
|
165
|
|
166 write(" ");
|
|
167 foreach(f; EnumMembers!File) {
|
|
168 writef("%s", toChar(f));
|
|
169 }
|
|
170 writeln("");
|
|
171 }
|
|
172
|
|
173 //
|
|
174 //
|
|
175 //
|
|
176
|
|
177 enum KingState {
|
|
178 Safe,
|
|
179 Check,
|
|
180 CheckMate
|
|
181 }
|
|
182
|
|
183 class Game {
|
|
184 struct SideState {
|
|
185 KingState kingState;
|
|
186 bool kingMoved;
|
|
187 bool queenRookMoved;
|
|
188 bool kingRookMoved;
|
|
189 }
|
|
190
|
|
191 struct Ply {
|
|
192 this(Coord source_, Coord dest_) {
|
|
193 source = source_;
|
|
194 dest = dest_;
|
|
195 }
|
|
196
|
|
197 Coord source;
|
|
198 Coord dest;
|
|
199 }
|
|
200
|
|
201 @property Board board() { return _board; }
|
|
202
|
|
203 struct Flags {
|
|
204 bool check;
|
|
205 bool mate;
|
|
206 }
|
|
207
|
|
208 // Default initial pieces, white to play
|
|
209 this () {
|
|
210 }
|
|
211
|
|
212 this (Board board, Flags whiteFlags, Flags blackFlags, Side nextPly) {
|
|
213 _board = board;
|
|
214 _nextPly = nextPly;
|
|
215 }
|
|
216
|
|
217 enum Acceptance {
|
|
218 Normal,
|
|
219 Check,
|
|
220 Mate,
|
|
221 Illegal
|
|
222 }
|
|
223
|
|
224 Acceptance apply(in Ply ply) {
|
|
225 /+
|
129
|
226 auto sq1 = square(update.source);
|
|
227 auto sq2 = square(update.dest);
|
128
|
228
|
129
|
229 if (sq1.piece == Piece.Pawn && update.dest.file != update.source.file) {
|
128
|
230 // en-passant
|
|
231 }
|
129
|
232 else if (sq1.piece == Piece.King && update.dest.file - update.source.file > 1) {
|
128
|
233 // castle
|
|
234 }
|
130
|
235 +/
|
128
|
236
|
130
|
237 return Acceptance.Normal;
|
129
|
238 }
|
|
239
|
|
240 private {
|
130
|
241 struct PieceState {
|
|
242 bool uncaptured;
|
|
243 Coord coord; // valid if uncaptured
|
|
244 }
|
129
|
245
|
130
|
246 Board _board;
|
|
247 Side _nextPly;
|
|
248 SideState _whiteSideState;
|
|
249 PieceState[8] _whitePieceState;
|
|
250 SideState _blackSideState;
|
|
251 PieceState[8] _blackPieceState;
|
129
|
252 }
|
|
253 }
|
|
254
|
127
|
255 void main(string[] args) {
|
|
256 Board board;
|
128
|
257 dump(board);
|
129
|
258
|
130
|
259 /+
|
129
|
260 Game game;
|
130
|
261 +/
|
127
|
262 }
|