8 Commits

12 changed files with 94 additions and 90 deletions

View File

@@ -19,7 +19,7 @@ ifeq ($(CC),cc)
CC = gcc
endif
ifeq ($(BUILD),)
BUILD = release
BUILD = perf
endif
BEAR := bear
@@ -49,7 +49,7 @@ OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
TSTSRC := $(wildcard $(TSTDIR)/*.c)
LIB := br_$(shell uname -m) # library name
LIBS := $(strip -l$(LIB) -lreadline -lncurses -ltinfo)
LIBS := $(strip -l$(LIB))
DEP_FN := $(SRC_FN)
DEP := $(addprefix $(DEPDIR)/,$(DEP_FN:.c=.d))
@@ -92,7 +92,7 @@ CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR) -DVERSION=\"$(VERSION)\"
ifeq ($(BUILD),release)
CPPFLAGS += -DNDEBUG # assert (unused)
else ifeq ($(BUILD),dev)
else # ifeq ($(BUILD),dev)
CPPFLAGS += -DWARN_ON # brlib bug.h
CPPFLAGS += -DBUG_ON # brlib bug.h
@@ -127,18 +127,27 @@ CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wshadow
CFLAGS += -Wmissing-declarations
CFLAGS += -march=native
### dev OR release
ifeq ($(BUILD),release)
CFLAGS += -O3
CFLAGS += -march=native
CFLAGS += -flto
CFLAGS += -g
CFLAGS += -ginline-points # inlined funcs debug info
CFLAGS += -funroll-loops
CFLAGS += -flto
else ifeq ($(BUILD),dev)
CFLAGS += -Og
CFLAGS += -g # symbols (gdb, perf, etc.)
CFLAGS += -ginline-points # inlined funcs debug info
#CFLAGS += -pg # gprof
# Next one may be useful for valgrind (when invalid instructions)
#CFLAGS += -mno-tbm
else ifeq ($(BUILD),perf)
CFLAGS += -O3
CFLAGS += -g # symbols (gdb, perf, etc.)
CFLAGS += -ginline-points # inlined funcs debug info
CFLAGS += -funroll-loops
# for gprof
#CFLAGS += -pg
# Next one may be useful for valgrind (when invalid instructions)
@@ -198,7 +207,7 @@ $(sort all $(MAKECMDGOALS)):
else
##################################### General targets
.PHONY: all release dev compile clean cleanall
.PHONY: all release dev perf compile clean cleanall
all: testing $(TARGET)
@@ -208,6 +217,9 @@ release:
dev:
$(MAKE) BUILD=dev clean all
perf:
$(MAKE) BUILD=perf clean all
compile: brlib objs
libs: brlib
@@ -337,7 +349,7 @@ cleanasmcpp:
%.s: %.c
@echo "generating $@ (asm)."
@$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
##################################### LSP (ccls)
.PHONY: ccls
@@ -380,11 +392,11 @@ TEST += movedo-test perft-test tt-test
PIECE_OBJS := piece.o
FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \
hyperbola-quintessence.o attack.o hash.o init.o
hyperbola-quintessence.o attack.o hash.o init.o misc.o
BB_OBJS := $(FEN_OBJS)
MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o
ATTACK_OBJS := $(MOVEGEN_OBJS)
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o misc.o
MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o
PERFT_OBJS := $(MOVEDO_OBJS) search.o
TT_OBJS := $(MOVEDO_OBJS)

2
brlib

Submodule brlib updated: 8ff163dcf5...553dc6bd07

View File

@@ -61,7 +61,7 @@ struct command commands[] = {
{ "position", do_position, "position startpos|fen [moves ...]" },
{ "perft", do_perft, "(not UCI) perft [divide] depth" },
{ "perft", do_perft, "(not UCI) perft [divide] [alt] depth" },
{ "moves", do_moves, "(not UCI) moves ..." },
{ "diagram", do_diagram, "(not UCI) print current position diagram" },
@@ -318,17 +318,25 @@ int do_diagram(pos_t *pos, __unused char *arg)
int do_perft(__unused pos_t *pos, __unused char *arg)
{
char *saveptr, *token;
int divide = 0, depth = 6;
int divide = 0, depth = 6, alt = 0;
token = strtok_r(arg, " ", &saveptr);
if (!strcmp(token, "divide")) {
divide = 1;
token = strtok_r(NULL, " ", &saveptr);
}
if (!strcmp(token, "alt")) {
alt = 1;
token = strtok_r(NULL, " ", &saveptr);
}
depth = atoi(token);
printf("perft: divide=%d depth=%d\n", divide, depth);
if (depth > 0)
perft(pos, depth, 1, divide);
printf("perft: divide=%d alt=%d depth=%d\n", divide, alt, depth);
if (depth > 0) {
if (!alt)
perft(pos, depth, 1, divide);
else
perft_alt(pos, depth, 1, divide);
}
return 1;
}

View File

@@ -21,9 +21,7 @@
#include <bug.h>
#include "chessdefs.h"
#include "util.h"
//#include "piece.h"
//#include "bitboard.h"
#include "misc.h"
#include "position.h"
#include "fen.h"

View File

@@ -18,7 +18,7 @@
#include <bitops.h>
#include "chessdefs.h"
#include "util.h"
#include "misc.h"
#include "position.h"
#include "piece.h"
#include "hash.h"

View File

@@ -14,7 +14,7 @@
#ifndef HASH_H
#define HASH_H
//#include <bug.h>
#include <bug.h>
#include "chessdefs.h"
@@ -121,7 +121,7 @@ bool zobrist_verify(pos_t *pos);
*/
static inline void tt_prefetch(hkey_t key)
{
// bug_on(!hash_tt.keys);
bug_on(!hash_tt.keys);
__builtin_prefetch(hash_tt.keys + (key & hash_tt.mask));
}

View File

@@ -26,7 +26,6 @@
#include "attack.h"
#include "move-gen.h"
/**
* pseudo_is_legal() - check if a move is legal.
* @pos: position
@@ -36,13 +35,18 @@
*/
bool pseudo_is_legal(const pos_t *pos, const move_t move)
{
color_t us = pos->turn, them = OPPONENT(us);
square_t from = move_from(move), to = move_to(move);
square_t king = pos->king[us];
color_t us = pos->turn;
color_t them = OPPONENT(us);
square_t from = move_from(move);
square_t to = move_to(move);
square_t kingsq = pos->king[us];
square_t ep = pos->en_passant;
bitboard_t kingbb = pos->bb[us][KING];
bitboard_t occ = pos_occ(pos);
u64 pinned = BIT(from) & pos->blockers;
u64 checkers = pos->checkers;
bitboard_t occ = pos_occ(pos);
u64 pinned = BIT(from) & pos->blockers;
u64 checkers = pos->checkers;
bug_on(pos->board[from] == NO_PIECE || COLOR(pos->board[from]) != us);
/* (1) - Castling & King
* For castling, we need to check intermediate squares attacks only.
@@ -50,60 +54,52 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move)
* king from occupation bitboard (to catch king moving away from checker
* on same line) !
*/
if (unlikely(from == king)) {
if (unlikely(is_castle(move))) {
square_t dir = to > from? 1: -1;
if (sq_is_attacked(pos, occ, from + dir, them))
return false;
}
if (is_castle(move)) {
int dir = to > from? 1: -1;
if (sq_is_attacked(pos, occ, from + dir, them))
return false;
}
if (from == kingsq) {
return !sq_is_attacked(pos, occ ^ kingbb, to, them);
}
/* (2) - King is in check
* Double-check is already handled in (1), as only K moves were generated
* by pseudo legal move generator.
* Here, allowed dest squares are only on King-checker line, or on checker
* square.
* attacker.
* Special cases:
* e.p., legal if the grabbed pawn is giving check
* pinned piece: always illegal
* Special cases (illegal):
* - e.p., if the grabbed pawn is *not* giving check
* - piece is pinned
*/
if (checkers) {
if (pinned)
return false;
if (bb_multiple(checkers))
return false;
square_t checker = ctz64(checkers);
if (is_enpassant(move)) {
return pos->en_passant + sq_up(them) == checker;
return ep + sq_up(them) == ctz64(checkers);
}
return true;
//bitboard_t between = bb_between[king][checker] | pos->checkers;
//return mask(to) & between;
}
/* (3) - pinned pieces
* We verify here that pinned piece P stays on line King-P.
* We verify here that pinned piece P stays on line between K & dest square.
*/
if (BIT(from) & pos->blockers) {
return bb_line[from][king] & BIT(to); /* is to on pinner line ? */
if (pinned) {
return bb_line[from][kingsq] & BIT(to); /* is to on pinner line ? */
}
/* (4) - En-passant
* pinned pieces are handled in pinned section.
* pinned piece is already handled in (3).
* One case not handled anywhere else: when the two "disappearing" pawns
* would discover a R/Q horizontal check.
* Note: grabbed pawn *cannot* discover a check (impossible position).
*/
if (unlikely(is_enpassant(move))) {
if (is_enpassant(move)) {
bitboard_t rank5 = bb_rel_rank(RANK_5, us);
if (unlikely((pos->bb[us][KING] & rank5))) {
bitboard_t exclude = BIT(pos->en_passant - sq_up(us)) | BIT(from);
if (kingbb & rank5) {
bitboard_t exclude = BIT(ep + sq_up(them)) | BIT(from);
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
if (hyperbola_rank_moves(occ ^ exclude, king) & rooks)
return false;
return !(hyperbola_rank_moves(occ ^ exclude, kingsq) & rooks);
}
}
return true;
@@ -349,12 +345,12 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
bitboard_t dest_squares = ~my_pieces;
bitboard_t occ = my_pieces | enemy_pieces;
bitboard_t empty = ~occ;
move_t *moves = movelist->move;
square_t king = pos->king[us];
bitboard_t from_bb, to_bb;
bitboard_t tmp_bb;
move_t *moves = movelist->move;
square_t from, to;
square_t king = pos->king[us];
/* king - MUST BE FIRST */
to_bb = bb_king_moves(dest_squares, king);
@@ -379,6 +375,8 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
* To square attack check will be done in gen_is_legal.
*/
if (can_oo(pos->castle, us)) {
/* CHANGE HERE, either with bitmask >> or direct sq check */
bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb);
if (!(occ & occmask)) {
*moves++ = move_make_flags(king, king + 2, M_CASTLE_K);

View File

@@ -27,7 +27,7 @@
#include "hyperbola-quintessence.h"
#include "fen.h"
#include "piece.h"
#include "util.h"
#include "misc.h"
#include "board.h"
#include "attack.h"

View File

@@ -19,7 +19,7 @@
#include <brlib.h>
#include <bitops.h>
#include <struct-group.h>
// #include <bug.h>
#include <bug.h>
#include "chessdefs.h"
#include "hash.h"

View File

@@ -1,18 +0,0 @@
/* util.c - various util functions.
*
* Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "util.h"
#include "bitboard.h"

View File

@@ -279,13 +279,14 @@ int main(int ac, char**av)
s64 ms, lps;
int opt, depth = 6, run = 3, tt, newtt = HASH_SIZE_DEFAULT;
struct {
s64 count, ms;
s64 count, countskipped, ms;
s64 minlps, maxlps;
int skipped;
int err;
} res[3] = {
{ .minlps=LONG_MAX },
{ .minlps=LONG_MAX },
{ .minlps=LONG_MAX },
{ .minlps = LONG_MAX },
{ .minlps = LONG_MAX },
{ .minlps = LONG_MAX },
};
while ((opt = getopt(ac, av, "cd:mp:st:")) != -1) {
@@ -362,6 +363,7 @@ int main(int ac, char**av)
ms = clock_elapsed_ms(&clock);
if (!ms) {
res[2].skipped++;
res[2].countskipped += sf_count;
lps = 0;
} else {
lps = sf_count * 1000l / ms;
@@ -382,6 +384,7 @@ int main(int ac, char**av)
ms = clock_elapsed_ms(&clock);
if (!ms) {
res[0].skipped++;
res[0].countskipped += my_count;
lps = 0;
} else {
lps = my_count * 1000l / ms;
@@ -399,6 +402,7 @@ int main(int ac, char**av)
tt_stats();
} else {
printf("perft : perft:%'lu ***ERROR***\n", my_count);
res[0].err++;
}
}
@@ -408,6 +412,7 @@ int main(int ac, char**av)
ms = clock_elapsed_ms(&clock);
if (!ms) {
res[1].skipped++;
res[1].countskipped += my_count;
lps = 0;
} else {
lps = my_count * 1000l / ms;
@@ -424,6 +429,7 @@ int main(int ac, char**av)
my_count, ms, lps);
} else {
printf("perft_alt : perft:%'lu ***ERROR***\n", my_count);
res[1].err++;
}
}
printf("\n");
@@ -434,30 +440,30 @@ int main(int ac, char**av)
res[2].ms = 1;
printf("total Stockfish : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n",
res[2].count, res[2].ms,
res[2].count + res[2].countskipped, res[2].ms,
res[2].count * 1000l / res[2].ms,
res[2].minlps, res[2].maxlps,
res[0].skipped, curtest);
res[2].skipped, curtest);
}
if (run & 1) {
if (!res[0].ms)
res[0].ms = 1;
printf("total perft : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n",
res[0].count, res[0].ms,
"(pos:%d skipped:%d err:%d)\n",
res[0].count + res[0].countskipped, res[0].ms,
res[0].count * 1000l / res[0].ms,
res[0].minlps, res[0].maxlps,
res[0].skipped, curtest);
curtest, res[0].skipped, res[0].err);
}
if (run & 2) {
if (!res[1].ms)
res[1].ms = 1;
printf("total perft_alt : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n",
res[1].count, res[1].ms,
"(pos:%d skipped:%d err:%d)\n",
res[1].count + res[1].countskipped, res[1].ms,
res[1].count * 1000l / res[1].ms,
res[1].minlps, res[1].maxlps,
res[0].skipped, curtest);
curtest, res[1].skipped, res[1].err);
}
return 0;
}