X3FYJUNL5ORLRC7TW3C5OMNZOX4JEWL73RXOQZLRKLAUBVNARIMAC
CWEVCXXC3D5NLLIFIYEWTXHPLX4EU5XH3YUUTMV7GYBLSQXT5VPQC
RNEXG5IFDKMHSUR6RMNTI3Y32ORLVMZ6UJYKHLV2XBMT2QONBTVQC
A46B5KNQFPTZEIL2JZKD2CQELGU3COE6FGTV2ABS5U7DVTVDGEBQC
FOORIA7SEZCLKDBNMV6KEDTQOJJVAH57BQFBRSQMET6FERJPHCVQC
GLTWBA5NKQIHAL23SWKCFOZQH62W6B3LX4RC5GFQUEQUIYN4OKSAC
WSRRWTTVBE2K6NKPS54CXMY3QYK5YTDRGEH3YJ53VQ2XW5UM5O2QC
THYIOCFC72V4ZMTLMGRGRIBARXT2LPSQCL2XNOIBI22QRVYUMIYQC
TB4YBE4CMWCLSKJ43QF6IU5HVYUUO33BLXVG7XDRLJS3IFIBQLYAC
NYVHTMLLUMBKBQSWO6SQDQ5KFACQLNCBRDDM5BH3OU6WWT54KC2AC
LWF4H4TMNZYUKTCVDALXQLBE3U5AXQJ3LLNUJJ7YGTLG6T2O33JAC
WZNDXPQM23LLYDZ3ZCTB4GOVRJLL7PMSEPSYBVFX6AOTJOZ5YYZQC
6S6HHKOXBQ5ARL7S7PKMPDIAH3VTPOAPWWSMGY37RP2R2U662FBAC
2CU67A3QXXPH722WBAL74O6P2N2RRXFBQVPT3A5QAXTUCQ3UUU5AC
DKK2G2S3X7KFEJBHGLUEVTBBW6UBR36XR7ZBUWG5GO6JYXWGJOOAC
const std = @import("std");
const Str = []const u8;
const SIZE = @import("Board.zig").SIZE;
const BitMove = @import("Board.zig").BitMove;
const GameState = @import("Board.zig").GameState;
const MoveList = @import("Board.zig").MoveList;
const search = @import("search.zig");
pub fn parseGo(gs: *GameState, in: Str) !Str {
if (std.mem.containsAtLeast(u8, in, 1, "depth")) {
// go depth <some val>
const depth = try std.fmt.parseUnsigned(u4, in[9..], 10);
return search.bestMove(gs, depth);
}
// TODO: different time controls...
return search.bestMove(gs, 6);
}
pub fn parsePosition(gs: *GameState, in: Str) !void {
var words = std.mem.tokenize(u8, in, " ");
if (words.next()) |position| {
if (position[0] != 'p') {
return error.InvalidPosition;
}
} else return error.InvalidPosition;
if (words.next()) |start| {
switch (start[0]) {
's' => {
// startpos
try gs.parseFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
},
'f' => {
// fen
const end = std.mem.indexOf(u8, in, "moves");
if (end) |e| {
try gs.parseFEN(in[13 .. e - 1]);
for ([_]u3{ 0, 1, 2, 3, 4, 5 }) |_| {
_ = words.next();
}
} else {
try gs.parseFEN(in[13..]);
return;
}
},
else => return error.InvalidPosition,
}
} else return error.InvalidPosition;
if (words.next()) |moves| {
if (moves[0] != 'm') return error.InvalidPosition;
while (words.next()) |move| {
const m = try parseMove(gs.*, move);
_ = gs.makeMove(m, .all);
}
}
}
fn parseMove(gs: GameState, in: Str) !BitMove {
var move: BitMove = .{ .source = undefined, .target = undefined, .piece = undefined };
move.source = @intToEnum(Square, (in[0] - 'a' + (8 - (in[1] - '0')) * SIZE));
move.target = @intToEnum(Square, (in[2] - 'a' + (8 - (in[3] - '0')) * SIZE));
var ml = try MoveList.init(0);
try gs.generateMoves(&ml);
for (ml.slice()) |ml_move| {
if (move.source == ml_move.source and move.target == ml_move.target) {
move = ml_move;
// if there is a promotion, check if it is the right one
if (move.prom != .none) {
switch (move.prom) {
.N => if (in[4] != 'N') continue,
.n => if (in[4] != 'n') continue,
.B => if (in[4] != 'B') continue,
.b => if (in[4] != 'b') continue,
.R => if (in[4] != 'R') continue,
.r => if (in[4] != 'r') continue,
.Q => if (in[4] != 'Q') continue,
.q => if (in[4] != 'q') continue,
else => unreachable,
}
}
return move;
}
}
return error.IllegalMove;
}
const Square = @import("Board.zig").Square;
const Chess = @import("Chess.zig");
test "UCI - parseMove" {
var gs = try GameState.init("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8");
{
// gs.show();
const got = try parseMove(gs, "d7c8B");
try std.testing.expectEqual(Square.d7, got.source);
try std.testing.expectEqual(Square.c8, got.target);
try std.testing.expectEqual(Chess.PE.B, got.prom);
try std.testing.expectEqual(true, got.capture);
try std.testing.expectEqual(Chess.PE.P, got.piece);
// _ = gs.makeMove(got, .all);
// gs.show();
}
{
// gs.show();
const got = parseMove(gs, "d7d8");
try std.testing.expectError(error.IllegalMove, got);
}
}
test "UCI - parsePosition" {
var gs = try GameState.init(null);
{
try parsePosition(&gs, "position startpos");
// gs.show();
}
{
try parsePosition(&gs, "position startpos moves e2e4 e7e5");
// gs.show();
}
{
try parsePosition(&gs, "position fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -");
// gs.show();
}
{
try parsePosition(&gs, "position fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1 moves g2g4 c7c5");
// gs.show();
}
}
}
pub fn parseGo(self: *@This(), in: Str) !Str {
if (std.mem.containsAtLeast(u8, in, 1, "depth")) {
// go depth <some val>
const depth = try std.fmt.parseUnsigned(u4, in[9..], 10);
return self.searchPosition(depth);
}
// TODO: different time controls...
return self.searchPosition(6);
pub fn parsePosition(self: *@This(), in: Str) !void {
var words = std.mem.tokenize(u8, in, " ");
if (words.next()) |position| {
if (position[0] != 'p') {
return error.InvalidPosition;
}
} else return error.InvalidPosition;
if (words.next()) |start| {
switch (start[0]) {
's' => {
// startpos
try self.parseFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
},
'f' => {
// fen
const end = std.mem.indexOf(u8, in, "moves");
if (end) |e| {
try self.parseFEN(in[13 .. e - 1]);
for ([_]u3{ 0, 1, 2, 3, 4, 5 }) |_| {
_ = words.next();
}
} else {
try self.parseFEN(in[13..]);
return;
}
},
else => return error.InvalidPosition,
}
} else return error.InvalidPosition;
if (words.next()) |moves| {
if (moves[0] != 'm') return error.InvalidPosition;
while (words.next()) |move| {
const m = try self.parseMove(move);
_ = self.makeMove(m, .all);
}
}
}
fn parseMove(self: @This(), in: Str) !BitMove {
var move: BitMove = .{ .source = undefined, .target = undefined, .piece = undefined };
move.source = @intToEnum(Square, (in[0] - 'a' + (8 - (in[1] - '0')) * SIZE));
move.target = @intToEnum(Square, (in[2] - 'a' + (8 - (in[3] - '0')) * SIZE));
var ml = try MoveList.init(0);
try self.generateMoves(&ml);
for (ml.slice()) |ml_move| {
if (move.source == ml_move.source and move.target == ml_move.target) {
move = ml_move;
// if there is a promotion, check if it is the right one
if (move.prom != .none) {
switch (move.prom) {
.N => if (in[4] != 'N') continue,
.n => if (in[4] != 'n') continue,
.B => if (in[4] != 'B') continue,
.b => if (in[4] != 'b') continue,
.R => if (in[4] != 'R') continue,
.r => if (in[4] != 'r') continue,
.Q => if (in[4] != 'Q') continue,
.q => if (in[4] != 'q') continue,
else => unreachable,
}
}
return move;
}
}
return error.IllegalMove;
}
fn parseFEN(self: *@This(), in: []const u8) !void {
pub fn parseFEN(self: *@This(), in: []const u8) !void {
}
fn sideAttacks(self: *const @This(), color: Chess.Colors) BoardType {
var ret: BoardType = 0;
for (std.enums.values(Square)) |square| {
if (isSquareAttacked(self, @enumToInt(square), color)) {
ret |= @as(BoardType, 1) << @enumToInt(square);
}
}
return ret;
var bb = BitBoard{};
const got = game.sideAttacks(.white);
bb = @bitCast(BitBoard, got);
var got: BoardType = 0;
for (std.enums.values(Square)) |square| {
if (game.isSquareAttacked(@enumToInt(square), .white)) {
got |= @as(BoardType, 1) << @enumToInt(square);
}
}
}
test "UCI - parseMove" {
var gs = try GameState.init("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8");
{
// gs.show();
const got = try gs.parseMove("d7c8B");
try std.testing.expectEqual(Square.d7, got.source);
try std.testing.expectEqual(Square.c8, got.target);
try std.testing.expectEqual(Chess.PE.B, got.prom);
try std.testing.expectEqual(true, got.capture);
try std.testing.expectEqual(Chess.PE.P, got.piece);
// _ = gs.makeMove(got, .all);
// gs.show();
}
{
// gs.show();
const got = gs.parseMove("d7d8");
try std.testing.expectError(error.IllegalMove, got);
}
test "UCI - parsePosition" {
var gs = try GameState.init(null);
{
try gs.parsePosition("position startpos");
// gs.show();
}
{
try gs.parsePosition("position startpos moves e2e4 e7e5");
// gs.show();
}
{
try gs.parsePosition("position fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -");
// gs.show();
}
{
try gs.parsePosition("position fen 8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1 moves g2g4 c7c5");
// gs.show();
}
}