54 Commits

Author SHA1 Message Date
e630a73f26 remove test FEN dups 2024-07-22 09:16:27 +02:00
c8fd3b87ac add Rodent-III FEN tests 2024-07-22 09:03:31 +02:00
14a2cae072 eval-simple.c: game phases, multiple PST 2024-07-21 18:10:33 +02:00
30ac647fe5 update bug_on (brlib + hash.c + position.h), new alloc.[ch] 2024-07-15 08:23:11 +02:00
ca76b28b00 Makefile: simplify flags/build, adapt Emacs .dirs-local.el 2024-07-15 08:13:39 +02:00
f8bb5c06e5 comment move_find_in_movelist() limitations 2024-07-10 07:51:29 +02:00
f52454903c cleanup 2024-07-10 07:50:31 +02:00
5401e83db8 Memory allocation: moved to alloc.[ch] 2024-07-10 07:49:44 +02:00
3100504fa2 Makefile: add 'build=' option 2024-07-10 07:47:02 +02:00
470109768f finalize hyperbola funcs/files rename: Makefile, wrong calls, etc... 2024-07-06 20:44:25 +02:00
96be21231b improve git-split.sh (multiple splits, etc...) 2024-07-06 19:27:22 +02:00
7ce64c3aee rename hyperbola-quintessence files to hq 2024-07-06 19:16:47 +02:00
23051cb427 rename hyperbola functions to hq 2024-07-06 19:11:56 +02:00
8483ffa101 cleanup 2024-07-05 08:23:16 +02:00
a8f7bd12b8 add tricky FEN from talkchess 2024-07-03 21:13:15 +02:00
73d09ec37f perft: fix divide (untested for ages!). perft-test: SF uses divide 2024-07-03 21:10:41 +02:00
2870101896 move_from_str(): fix new move_t promotion 2024-07-03 21:09:00 +02:00
91abc3e26d convert piece_t, square_t etc. to u8 (no more typed enum. See C23 ?). 2024-07-03 08:49:54 +02:00
902c224aa9 simplify promotion generation 2024-07-02 17:28:35 +02:00
44f604abac cleanup 2024-07-01 14:06:51 +02:00
a2451d79db finish fitting move_t in 16 bits 2024-07-01 13:56:13 +02:00
58c985f52f eval.c, eval-simple.c: start to migrate from 0x88 (does not compile) 2024-06-30 10:00:35 +02:00
4d1870ffb3 eval_t: s16 + add in pos_t + remove useless opening pieces values 2024-06-30 09:59:18 +02:00
e18a237347 empty MEMO.org 2024-06-29 11:47:02 +02:00
6fc1ebcc9a add 'hist' command, fix strkok fails, use move_find_in_movelist 2024-06-29 11:37:16 +02:00
8c94c6beb1 add hist_link, hist_push: remove 'move' parameter 2024-06-29 11:35:33 +02:00
a44483e36c init_all: add output for all steps 2024-06-29 11:33:50 +02:00
4e6885f26f makefile: default build: 'dev' 2024-06-29 11:31:48 +02:00
bb13eae0b8 move-do: save move in state, pos-print: print last move 2024-06-28 11:44:38 +02:00
b8f0f6a120 remove MOVE_NO_MOVE (use only MOVE_NONE) 2024-06-28 11:43:52 +02:00
b4f008b223 Emacs .dirs-local.el: change default make target 2024-06-28 09:41:17 +02:00
46f42ae59b move.c: complete move_from_str(), add move_find_in_movelist() 2024-06-28 09:35:56 +02:00
cffb0f7b95 hash.h: fix hash_short(), and hentry_t move size 2024-06-28 09:33:13 +02:00
c5a1936e3b UCI moves && games states list 2024-06-27 10:11:24 +02:00
46aed01079 hash: add hash_short macro, state_s: add prev and move 2024-06-27 08:36:08 +02:00
ffd5d056cc move_t flags: mask -> value, unique castling flag (1 bit saved) 2024-06-25 15:33:56 +02:00
5cb90f5396 remove move-test 2024-06-25 13:16:47 +02:00
da489bad65 update include syntax 2024-06-25 13:07:33 +02:00
f4280dfa13 perft-test: add error and skipped counts 2024-06-24 09:01:55 +02:00
d1cc7a8066 movegen: cleanup + change casling/king moves handling 2024-06-24 09:00:24 +02:00
cfa8b42077 add UCI "perft_alt" command 2024-06-24 08:52:23 +02:00
0c2d30c938 put back bug_on() following brlib change 2024-06-23 19:52:59 +02:00
3a6c1d11c0 rename util.h -> misc.h (2) 2024-06-23 19:22:22 +02:00
a7311a546f add perf target 2024-06-23 19:16:05 +02:00
84b6c41107 update brlib 2024-06-23 19:15:34 +02:00
19d10fdfa8 rename util.h -> misc.h 2024-06-23 19:15:14 +02:00
6e38de58cb brchess: remove any readline dependancy (issue with static linking) 2024-06-22 21:06:06 +02:00
0c15be28b1 remove bug.h include in any .h file 2024-06-20 09:13:28 +02:00
879bda850c pos_ok, remove unused var warnings for 'release' target 2024-06-20 09:04:54 +02:00
0a0c3227b8 Makefile: add release & dev targets 2024-06-20 09:04:28 +02:00
242b501404 cleanup 2024-06-20 05:36:42 +02:00
f530a13481 prepare brchess, eval, eval-simple for future use 2024-06-19 11:01:48 +02:00
243805f11f add git-split.sh (NOT WORKING!) 2024-06-18 06:38:04 +02:00
ae198c891f Merge branch 'tt' 2024-06-17 07:51:45 +02:00
46 changed files with 2307 additions and 1348 deletions

View File

@@ -1,3 +1,3 @@
((nil . ((compile-command . (concat "make -C " ((nil . ((compile-command . (concat "make -C "
(vc-root-dir) (vc-root-dir)
" -k -j4 testing"))))) " -k -j4 build=dev")))))

1
.gitignore vendored
View File

@@ -20,3 +20,4 @@ perf.data
valgrind.out valgrind.out
gmon.out gmon.out
compile_commands.json compile_commands.json
.lastbuild

View File

@@ -1,2 +1,23 @@
** Some current ideas ** Some current ideas
- helpers for square, pieces, etc: validity, conversions - Test popbit/square_of with intrinsincs, something like :
bitboard_t popbit64(bitboard_t *bb)
{
bitboard_t first = _blsi_u64(*bb);
*bb ^= lsb;
return first;
}
square_t square_of(bitboard_t bb) {
return _tzcnt_u64(bb);
}
loop:
while (bb) {
bitboard_t first = popbit(bb);
square_t sq = square_of(first);
}
Or maybe faster:
for (; bb; bb &= bb - 1) {
sq = _tzcnt_u64(bb);
}

264
Makefile
View File

@@ -11,9 +11,7 @@
# #
SHELL := /bin/bash SHELL := /bin/bash
CC := gcc
#CC := gcc-13
#CC := clang
BEAR := bear BEAR := bear
TOUCH := touch TOUCH := touch
RM := rm RM := rm
@@ -41,7 +39,7 @@ OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
TSTSRC := $(wildcard $(TSTDIR)/*.c) TSTSRC := $(wildcard $(TSTDIR)/*.c)
LIB := br_$(shell uname -m) # library name LIB := br_$(shell uname -m) # library name
LIBS := $(strip -l$(LIB) -lreadline) LIBS := $(strip -l$(LIB))
DEP_FN := $(SRC_FN) DEP_FN := $(SRC_FN)
DEP := $(addprefix $(DEPDIR)/,$(DEP_FN:.c=.d)) DEP := $(addprefix $(DEPDIR)/,$(DEP_FN:.c=.d))
@@ -52,83 +50,140 @@ TARGET := $(addprefix $(BINDIR)/,$(TARGET_FN))
ASMFILES := $(SRC:.c=.s) $(TSTSRC:.c=.s) ASMFILES := $(SRC:.c=.s) $(TSTSRC:.c=.s)
CPPFILES := $(SRC:.c=.i) $(TSTSRC:.c=.i) CPPFILES := $(SRC:.c=.i) $(TSTSRC:.c=.i)
##################################### Check for compiler and requested build
BUILDS := release dev perf debug
# last compilation build
BUILDFILE := .lastbuild
lastbuild := $(file < $(BUILDFILE))
# default to gcc
CC ?= cc
ifeq ($(CC),cc)
CC = gcc
endif
# if no build specified, use last one
ifeq ($(build),)
build := $(lastbuild)
endif
# if build is still undefined, set a default
ifeq ($(build),)
build := release
endif
# check for valid build
ifeq ($(filter $(build),$(BUILDS)),)
$(error Error: Unknown build=`$(build)`. Possible builds are: $(BUILDS))
endif
# if new build, rewrite BUILDFILE
ifeq ($(build),$(lastbuild))
$(info Using last used build:`$(build)`.)
else
$(info Using new build:`$(build)` (previous:$(lastbuild)))
$(file >$(BUILDFILE),$(build))
endif
##################################### set a version string
# inspired from:
# https://eugene-babichenko.github.io/blog/2019/09/28/nightly-versions-makefiles/
# last commit and date
COMMIT := $(shell git rev-parse --short HEAD)
DATE := $(shell git log -1 --format=%cd --date=format:"%Y%m%d")
# get last commit w/ tag & associated tag, if any
TAG_COMM := $(shell git rev-list --abbrev-commit --tags --max-count=1)
ifneq ($(TAG_COMMIT),)
TAG := $(shell git describe --abbrev=0 --tags ${TG_COMM} 2>/dev/null || true)
VERSION := $(TAG:v%=%)
endif
# if no version, use last commit and date.
# else, if last commit != last tag commit, add commit and date to version number
ifeq ($(VERSION),)
VERSION := $(build)-$(COMMIT)-$(DATE)
else ifneq ($(COMMIT), $(TAG_COMMIT))
VERSION := $(VERSION)-next-$(build)-$(COMMIT)-$(DATE)
endif
# if uncommited changes, add "dirty" indicator
ifneq ($(shell git status --porcelain),)
VERSION := $(VERSION)-dirty
endif
##################################### pre-processor flags ##################################### pre-processor flags
CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR) CPPFLAGS := -I$(BRINCDIR) -I$(INCDIR) -DVERSION=\"$(VERSION)\"
CPPFLAGS += -DNDEBUG # assert (unused)
CPPFLAGS += -DWARN_ON # brlib bug.h
CPPFLAGS += -DBUG_ON # brlib bug.h
#CPPFLAGS += -DDEBUG # global - unused
#CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
#CPPFLAGS += -DDEBUG_DEBUG_C # enable log() settings
#CPPFLAGS += -DDEBUG_POOL # memory pools management
#CPPFLAGS += -DDEBUG_POS # position.c
#CPPFLAGS += -DDEBUG_MOVE # move generation
# fen.c
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
# hash / TT
#CPPFLAGS += -DZOBRIST_VERIFY # double chk zobrist
#CPPFLAGS += -DPERFT_MOVE_HISTORY # perft, keep prev moves
# attack.c
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
#CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
#CPPFLAGS += -DDEBUG_EVAL # eval functions
#CPPFLAGS += -DDEBUG_PIECE # piece list management
#CPPFLAGS += -DDEBUG_SEARCH # move search
CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams CPPFLAGS += -DDIAGRAM_SYM # UTF8 symbols in diagrams
ifeq ($(build),release)
CPPFLAGS += -DNDEBUG # assert (unused)
else # ifeq ($(build),dev)
CPPFLAGS += -DBUG_ON # brlib bug.h
# fen.c
#CPPFLAGS += -DDEBUG_FEN # FEN decoding
# hash / TT
#CPPFLAGS += -DZOBRIST_VERIFY # double chk zobrist
#CPPFLAGS += -DPERFT_MOVE_HISTORY # perft, keep prev moves
# attack.c
#CPPFLAGS += -DDEBUG_ATTACK_ATTACKERS # sq_attackers
#CPPFLAGS += -DDEBUG_ATTACK_PINNERS # sq_pinners details
# eval.c eval-simple.c
CPPFLAGS += -DEVAL # eval
# old unused flags
#CPPFLAGS += -DDEBUG_POS # position.c
#CPPFLAGS += -DDEBUG_MOVE # move generation
#CPPFLAGS += -DDEBUG_EVAL # eval functions
endif
# remove extraneous spaces (due to spaces before comments) # remove extraneous spaces (due to spaces before comments)
CPPFLAGS := $(strip $(CPPFLAGS)) CPPFLAGS := $(strip $(CPPFLAGS))
##################################### compiler flags ##################################### compiler / linker flags
CFLAGS := -std=gnu11 CFLAGS := -std=gnu11
### dev OR release CFLAGS += -Wall -Wextra -Wshadow -Wmissing-declarations
# dev
CFLAGS += -g # symbols (gdb, perf, etc.)
CFLAGS += -ginline-points # inlined funcs debug info
#CFLAGS += -Og
# for gprof
#CFLAGS += -pg
# Next one may be useful for valgrind (when invalid instructions)
#CFLAGS += -mno-tbm
# release
CFLAGS += -O3
CFLAGS += -march=native CFLAGS += -march=native
CFLAGS += -flto
CFLAGS += -funroll-loops
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wshadow
CFLAGS += -Wmissing-declarations
CFLAGS := $(strip $(CFLAGS))
# development CFLAGS - unused - TODO
#DEV_CFLAGS := -Og
#DEV_CFLAGS += -g
# release CFLAGS - unused - TODO
#REL_CFLAGS := -Ofast
##################################### linker flags
LDFLAGS := --static LDFLAGS := --static
LDFLAGS += -L$(BRLIBDIR) LDFLAGS += -L$(BRLIBDIR)
LDFLAGS += -flto
### dev OR release
ifeq ($(build),release)
CFLAGS += -O3
CFLAGS += -funroll-loops
CFLAGS += -flto
#CFLAGS += -g
#CFLAGS += -ginline-points # inlined funcs debug info
LDFLAGS += -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
else ifeq ($(build),debug)
CFLAGS += -Og
CFLAGS += -g # symbols (gdb, perf, etc.)
CFLAGS += -ginline-points # inlined funcs debug info
# for gprof
#CFLAGS += -pg
# Next one may be useful for valgrind (when invalid instructions)
#CFLAGS += -mno-tbm
endif
CFLAGS := $(strip $(CFLAGS))
LDFLAGS := $(strip $(LDFLAGS)) LDFLAGS := $(strip $(LDFLAGS))
##################################### archiver/dependency flags ##################################### dependency flags
ARFLAGS := rcs
DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$*.d DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$*.d
##################################### archiver/dependency flags ##################################### archiver/dependency flags
@@ -168,9 +223,21 @@ $(sort all $(MAKECMDGOALS)):
else else
##################################### General targets ##################################### General targets
.PHONY: all compile clean cleanall .PHONY: all release dev perf debug compile libs clean cleanall
all: $(TARGET) all: libs testing $(TARGET)
release:
$(MAKE) BUILD=release clean all
dev:
$(MAKE) BUILD=dev clean all
perf:
$(MAKE) BUILD=perf clean all
debug:
$(MAKE) BUILD=debug clean all
compile: brlib objs compile: brlib objs
@@ -234,7 +301,8 @@ $(ALLDIRS): $@
-include $(wildcard $(DEP)) -include $(wildcard $(DEP))
# Don't use $(DEPDIR)/*.d, to control mismatches between dep and src files. # Don't use "rm $(DEPDIR)/*.d", to understand mismatches between dep/ and src/
# files.
# See second rule below. # See second rule below.
cleandep: cleandep:
$(call rmfiles,$(DEP),depend) $(call rmfiles,$(DEP),depend)
@@ -258,9 +326,10 @@ cleanobjdir: cleanobj
# The part right of '|' are "order-only prerequisites": They are build as # The part right of '|' are "order-only prerequisites": They are build as
# "normal" ones, but do not imply to rebuild target. # "normal" ones, but do not imply to rebuild target.
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(DEPDIR) $(OBJDIR)/%.o: $(BUILDFILE)
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(BUILDFILE) | $(OBJDIR) $(DEPDIR)
@echo compiling brchess module: $< "->" $@. @echo compiling brchess module: $< "->" $@.
@$(CC) -c $(ALL_CFLAGS) $< -o $@ $(CC) -c $(ALL_CFLAGS) $< -o $@
##################################### brlib libraries ##################################### brlib libraries
.PHONY: cleanbrlib cleanallbrlib brlib .PHONY: cleanbrlib cleanallbrlib brlib
@@ -271,9 +340,11 @@ cleanbrlib:
cleanallbrlib: cleanallbrlib:
$(MAKE) -C $(BRLIB) cleanall $(MAKE) -C $(BRLIB) cleanall
export build
brlib: brlib:
$(MAKE) -C $(BRLIB) libs $(info calling with build=$(build))
$(MAKE) -e -C $(BRLIB) lib-static
unexport build
##################################### brchess binaries ##################################### brchess binaries
.PHONY: targets cleanbin cleanbindir .PHONY: targets cleanbin cleanbindir
@@ -286,7 +357,7 @@ cleanbindir:
$(call rmdir,$(BINDIR),binaries) $(call rmdir,$(BINDIR),binaries)
$(TARGET): libs $(OBJ) | $(BINDIR) $(TARGET): libs $(OBJ) | $(BINDIR)
@echo generating $@. @echo linking $@.
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@ $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
##################################### pre-processed (.i) and assembler (.s) output ##################################### pre-processed (.i) and assembler (.s) output
@@ -301,7 +372,7 @@ cleanasmcpp:
%.s: %.c %.s: %.c
@echo "generating $@ (asm)." @echo "generating $@ (asm)."
@$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@ $(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
##################################### LSP (ccls) ##################################### LSP (ccls)
.PHONY: ccls .PHONY: ccls
@@ -319,7 +390,7 @@ $(CCLSROOT):
# maybe run cleanobj cleanlibobj in commands ? # maybe run cleanobj cleanlibobj in commands ?
$(CCLSFILE): cleanobj cleanbrlib libs | $(CCLSROOT) $(CCLSFILE): cleanobj cleanbrlib libs | $(CCLSROOT)
@echo "Generating ccls compile commands file ($@)." @echo "Generating ccls compile commands file ($@)."
@$(BEAR) -- $(MAKE) testing @$(BEAR) -- $(MAKE)
##################################### valgrind (mem check) ##################################### valgrind (mem check)
.PHONY: memcheck .PHONY: memcheck
@@ -337,18 +408,18 @@ memcheck: targets
@$(VALGRIND) $(VALGRINDFLAGS) $(BINDIR)/brchess @$(VALGRIND) $(VALGRINDFLAGS) $(BINDIR)/brchess
##################################### test binaries ##################################### test binaries
.PHONY: testing test .PHONY: testing
TEST := piece-test fen-test bitboard-test movegen-test attack-test TEST := piece-test fen-test bitboard-test movegen-test attack-test
TEST += movedo-test perft-test tt-test TEST += movedo-test perft-test tt-test
PIECE_OBJS := piece.o PIECE_OBJS := piece.o
FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \ FEN_OBJS := $(PIECE_OBJS) fen.o position.o bitboard.o board.o \
hyperbola-quintessence.o attack.o hash.o init.o hq.o attack.o hash.o init.o misc.o alloc.o move.o eval-simple.o
BB_OBJS := $(FEN_OBJS) BB_OBJS := $(FEN_OBJS)
MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o MOVEGEN_OBJS := $(BB_OBJS) move-gen.o
ATTACK_OBJS := $(MOVEGEN_OBJS) 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 PERFT_OBJS := $(MOVEDO_OBJS) search.o
TT_OBJS := $(MOVEDO_OBJS) TT_OBJS := $(MOVEDO_OBJS)
@@ -363,53 +434,50 @@ MOVEDO_OBJS := $(addprefix $(OBJDIR)/,$(MOVEDO_OBJS))
PERFT_OBJS := $(addprefix $(OBJDIR)/,$(PERFT_OBJS)) PERFT_OBJS := $(addprefix $(OBJDIR)/,$(PERFT_OBJS))
TT_OBJS := $(addprefix $(OBJDIR)/,$(TT_OBJS)) TT_OBJS := $(addprefix $(OBJDIR)/,$(TT_OBJS))
test:
echo TEST=$(TEST)
echo FEN_OBJS=$(FEN_OBJS)
testing: $(TEST) testing: $(TEST)
bin/piece-test: test/piece-test.c $(FEN_OBJS) bin/piece-test: test/piece-test.c $(FEN_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(FEN_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(FEN_OBJS) $(ALL_LDFLAGS) -o $@
bin/fen-test: test/fen-test.c test/common-test.h $(FEN_OBJS) bin/fen-test: test/fen-test.c test/common-test.h $(FEN_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(FEN_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(FEN_OBJS) $(ALL_LDFLAGS) -o $@
bin/bitboard-test: test/bitboard-test.c test/common-test.h $(BB_OBJS) bin/bitboard-test: test/bitboard-test.c test/common-test.h $(BB_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(BB_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(BB_OBJS) $(ALL_LDFLAGS) -o $@
bin/movegen-test: test/movegen-test.c test/common-test.h $(MOVEGEN_OBJS) bin/movegen-test: test/movegen-test.c test/common-test.h $(MOVEGEN_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(MOVEGEN_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(MOVEGEN_OBJS) $(ALL_LDFLAGS) -o $@
bin/attack-test: test/attack-test.c test/common-test.h $(ATTACK_OBJS) bin/attack-test: test/attack-test.c test/common-test.h $(ATTACK_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(ATTACK_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(ATTACK_OBJS) $(ALL_LDFLAGS) -o $@
bin/movedo-test: test/movedo-test.c test/common-test.h $(MOVEDO_OBJS) bin/movedo-test: test/movedo-test.c test/common-test.h $(MOVEDO_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(MOVEDO_OBJS) $(ALL_LDFLAGS) -o $@
bin/perft-test: test/perft-test.c test/common-test.h $(PERFT_OBJS) bin/perft-test: test/perft-test.c test/common-test.h $(PERFT_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(PERFT_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(PERFT_OBJS) $(ALL_LDFLAGS) -o $@
bin/tt-test: test/tt-test.c test/common-test.h $(TT_OBJS) bin/tt-test: test/tt-test.c test/common-test.h $(TT_OBJS)
@echo compiling $@ test executable. @echo linking $@ test executable.
@$(CC) $(ALL_CFLAGS) $< $(TT_OBJS) $(ALL_LDFLAGS) -o $@ @$(CC) $(ALL_CFLAGS) $< $(TT_OBJS) $(ALL_LDFLAGS) -o $@
##################################### Makefile debug ##################################### Makefile debug
.PHONY: showflags wft .PHONY: showflags wft
showflags: info:
@echo CFLAGS: "$(CFLAGS)" @printf "CFLAGS: +%s+\n" "$(CFLAGS)"
@echo CPPFLAGS: $(CPPFLAGS) @printf "CPPFLAGS: +%s+\n" "$(CPPFLAGS)"
@echo DEPFLAGS: $(DEPFLAGS) @printf "DEPFLAGS: +%s+\n" "$(DEPFLAGS)"
@echo LDFLAGS: $(LDFLAGS) @printf "LDFLAGS: +%s+\n" "$(LDFLAGS)"
@echo DEPFLAGS: $(DEPFLAGS) @printf "DEPFLAGS: +%s+\n" "$(DEPFLAGS)"
@printf "VERSION: +%s+\n" "$(VERSION)"
wtf: wtf:
@printf "BRLIBDIR=%s\n" "$(BRLIBDIR)" @printf "BRLIBDIR=%s\n" "$(BRLIBDIR)"
@@ -422,7 +490,7 @@ wtf:
@#echo LIBSRC=$(LIBSRC) @#echo LIBSRC=$(LIBSRC)
zob: zob:
$(CC) $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $< $(LIBS) src/util.c -o util @#$(CC) $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $< $(LIBS) src/util.c -o util
##################################### End of multi-targets ##################################### End of multi-targets
endif endif

2
brlib

Submodule brlib updated: 8ff163dcf5...180839c960

102
scripts/git-split.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env bash
#
# git-split.sh - duplicate GIT file, with history (well, sort of)
# Sources:
# https://stackoverflow.com/a/53849613/3079831
# https://stackoverflow.com/a/75942970/3079831
#
# (C) Bruno Raoult ("br"), 2024
# 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>
CMDNAME=${0##*/} # script name
if (( $# == 0 || $# % 2 )); then
printf "Usage: %s orig1 copy [orig2 copy2 ...]\n" "$CMDNAME"
exit 1
fi
yes_or_no() {
while true; do
read -rp "$* [y/N]: " yn
case $yn in
[Yy])
return 0
;;
[Nn]|"")
printf "Aborted.\n"
return 1
;;
esac
done
# not reached
}
# prints out and run a command.
echorun () {
printf ">>> %s\n" "$*"
"$@"
return $?
}
declare -A files
declare -a from # to keep order
while (($#)); do
if [[ ! -f "$1" ]]; then
printf "Missing '%s'. Aborting.\n" "$1"
exit 1
elif [[ -f "$2" ]]; then
printf "'%s' already exists. Aborting.\n" "$2"
exit 1
fi
files["$1"]="$2"
from+=("$1")
shift 2
done
printf "The following files will be split :\n"
for file in "${from[@]}"; do
printf "%s -> %s\n" "$file" "${files[$file]}"
done
yes_or_no "Proceed (y/N)? " || exit 1
branch="split-file"
printf -v msg1 "Splitting '%s'" "${from[0]}"
printf -v msg2 "Restore duplicated %s" "${from[0]}"
if (( ${#from[@]} > 1 )); then
msg1+=" and $(( ${#from[@]} - 1 )) others"
msg2+=" and $(( ${#from[@]} - 1 )) others"
fi
printf "%s using branch '$branch'.\n" "$msg1"
if git show-ref --verify --quiet "refs/heads/$branch"; then
echorun git switch "$branch"
echorun git merge master
else
echorun git switch -c "$branch"
fi
for file in "${from[@]}"; do # make the duplicates
echorun git mv "$file" "${files[$file]}"
done
echorun git commit -m "$msg1" # ... and commit
for file in "${from[@]}"; do # bring back the original
echorun git checkout HEAD~ "$file"
done
echorun git commit -m "$msg2" # ... and commit
echorun git checkout - # switch back to source branch
echorun git merge --no-ff "$branch" -m "Merge $branch" # merge dup into source branch
exit 0

174
src/alloc.c Normal file
View File

@@ -0,0 +1,174 @@
/* alloc.c - various memory allocation helpers
*
* 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 <sys/mman.h>
#include <brlib.h>
#include <bitops.h>
#include <bug.h>
#include "chessdefs.h"
#include "alloc.h"
/* values for linux
* PAGE_SIZE can be obtained with getpagesize(2), but unfortunately nothing for
* HUGE_PAGE_SIZE (except looking in /proc/meminfo or such).
*/
#define PAGE_SIZE (4 * 1024) /* 4 Kb */
#define HUGE_PAGE_SIZE (2 * 1024 * 1024) /* 2 Mb */
/**
* alloc() - allocate memory.
* @size: size to allocate
*
* Allocate memory on the heap.
*
* @return: memory address if success, NULL otherwise.
*/
void *alloc(size_t size)
{
return malloc(size);
}
/**
* alloc_aligned() - allocate aligned memory.
* @align: alignment, in bytes
* @size: size to allocate
*
* Allocate aligned memory on the heap. @align must be a power of 2 and
* a multiple of sizeof(void *). See aligned_alloc(3) for details.
*
* @return: memory address if success, NULL otherwise.
*/
void *alloc_aligned(size_t align, size_t size)
{
bug_on(!size || !align ||
align & (align - 1) || align % sizeof (void *));
return aligned_alloc(align, size);
}
/**
* alloc_page_aligned() - allocate page-aligned memory.
* @size: size to allocate
*
* Allocate page-aligned memory on the heap.
*
* @return: memory address if success, NULL otherwise.
*/
void *alloc_aligned_page(size_t size)
{
/* round size (up) to alignment */
//size_t rounded = (size + PAGE_SIZE - 1) & -PAGE_SIZE;
void *mem = alloc_aligned(PAGE_SIZE, size);
return mem;
}
/**
* alloc_huge_page_aligned() - allocate huge-page-aligned memory.
* @size: size to allocate
*
* Allocate page-aligned memory on the heap.
*
* @return: memory address if success, NULL otherwise.
*/
void *alloc_aligned_hugepage(size_t size)
{
/* round size (up) to alignment */
size_t rounded = (size + PAGE_SIZE - 1) & -PAGE_SIZE;
void *mem = alloc_aligned(PAGE_SIZE, rounded);
printf("size=%zu rounded=%zu\n", size, rounded);
//void *mem = aligned_alloc(HUGE_PAGE_SIZE, size);
if (mem) {
if (madvise(mem, rounded, MADV_HUGEPAGE | MADV_RANDOM))
perror("madvise");
}
return mem;
}
/**
* safe_alloc() - allocate memory or fail.
* @size: size to allocate
*
* Allocate memory on the heap. This function does not return if allocation
* fails.
*
* @return: memory address (if success only).
*/
void *safe_alloc(size_t size)
{
void *mem = malloc(size);
bug_on_always(mem == NULL);
return mem;
}
/**
* safe_alloc_aligned() - allocate aligned memory or fail.
* @align: alignment.
* @size: size to allocate
*
* Allocate aligned memory on the heap.
* This function does not return if allocation fails. See alloc_aligned()
* for more details.
*
* @return: memory address (if success only).
*/
void *safe_alloc_aligned(size_t align, size_t size)
{
void *mem = alloc_aligned(align, size);
bug_on_always(mem == NULL);
return mem;
}
/**
* safe_alloc_aligned_page() - allocate page-aligned memory or fail.
* @size: size to allocate
*
* Allocate memory on the heap. This function does not return if allocation
* fails. See alloc_aligned() for more details.
*
* @return: memory address (if success only).
*/
void *safe_alloc_aligned_page(size_t size)
{
void *mem = alloc_aligned_page(size);
bug_on_always(mem == NULL);
return mem;
}
/**
* safe_alloc_aligned_hugepage() - allocate huge page aligned memory or fail.
* @size: size to allocate
*
* Allocate memory on the heap. This function does not return if allocation
* fails. See alloc_aligned() for more details.
*
* @return: memory address (if success only).
*/
void *safe_alloc_aligned_hugepage(size_t size)
{
/* round size (up) to alignment */
//size_t rounded = (size + HUGE_PAGE_SIZE - 1) & -HUGE_PAGE_SIZE;
//void *mem = aligned_alloc(rounded, HUGE_PAGE_SIZE);
void *mem = alloc_aligned_hugepage(size);
bug_on_always(mem == NULL);
return mem;
}
void safe_free(void *ptr)
{
bug_on_always(ptr == NULL);
free(ptr);
}

30
src/alloc.h Normal file
View File

@@ -0,0 +1,30 @@
/* alloc.h - various memory allocation helpers
*
* 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>
*
*/
#ifndef _ALLOC_H
#define _ALLOC_H
#include "chessdefs.h"
void *alloc(size_t size);
void *alloc_aligned(size_t align, size_t size);
void *alloc_aligned_page(size_t size);
void *alloc_aligned_hugepage(size_t size);
void *safe_alloc(size_t size);
void *safe_alloc_aligned(size_t align, size_t size);
void *safe_alloc_aligned_page(size_t size);
void *safe_alloc_aligned_hugepage(size_t size);
void safe_free(void *ptr);
#endif /* _ALLOC_H */

View File

@@ -17,7 +17,7 @@
#include "chessdefs.h" #include "chessdefs.h"
#include "bitboard.h" #include "bitboard.h"
#include "position.h" #include "position.h"
#include "hyperbola-quintessence.h" #include "hq.h"
#include "attack.h" #include "attack.h"
@@ -52,11 +52,11 @@ bool sq_is_attacked(const pos_t *pos, const bitboard_t occ, const square_t sq, c
*/ */
/* bishop / queen */ /* bishop / queen */
if (hyperbola_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN])) if (hq_bishop_moves(occ, sq) & (pos->bb[c][BISHOP] | pos->bb[c][QUEEN]))
return true; return true;
/* rook / queen */ /* rook / queen */
if (hyperbola_rook_moves(occ, sq) & (pos->bb[c][ROOK] | pos->bb[c][QUEEN])) if (hq_rook_moves(occ, sq) & (pos->bb[c][ROOK] | pos->bb[c][QUEEN]))
return true; return true;
/* knight */ /* knight */
@@ -137,7 +137,7 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
/* bishop / queen */ /* bishop / queen */
to = pos->bb[c][BISHOP] | pos->bb[c][QUEEN]; to = pos->bb[c][BISHOP] | pos->bb[c][QUEEN];
tmp = hyperbola_bishop_moves(occ, sq) & to; tmp = hq_bishop_moves(occ, sq) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att bishop/queen", tmp); bb_print("att bishop/queen", tmp);
@@ -145,7 +145,7 @@ bitboard_t sq_attackers(const pos_t *pos, const bitboard_t occ, const square_t s
/* rook / queen */ /* rook / queen */
to = pos->bb[c][ROOK] | pos->bb[c][QUEEN]; to = pos->bb[c][ROOK] | pos->bb[c][QUEEN];
tmp = hyperbola_rook_moves(occ, sq) & to; tmp = hq_rook_moves(occ, sq) & to;
attackers |= tmp; attackers |= tmp;
# ifdef DEBUG_ATTACK_ATTACKERS # ifdef DEBUG_ATTACK_ATTACKERS
bb_print("att rook/queen", tmp); bb_print("att rook/queen", tmp);

View File

@@ -14,7 +14,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "brlib.h" #include <brlib.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "piece.h" #include "piece.h"
@@ -30,7 +30,7 @@ bitboard_t bb_line[64][64];
bitboard_t bb_knight[64], bb_king[64], bb_pawn_attacks[2][64]; bitboard_t bb_knight[64], bb_king[64], bb_pawn_attacks[2][64];
/* vectors are clockwise from N */ /* vectors are clockwise from N */
static int knight_vector[] = { static int knight_vector[8] = {
NORTH_EAST + NORTH, NORTH_EAST + EAST, NORTH_EAST + NORTH, NORTH_EAST + EAST,
SOUTH_EAST + EAST, SOUTH_EAST + SOUTH, SOUTH_EAST + EAST, SOUTH_EAST + SOUTH,
SOUTH_WEST + SOUTH, SOUTH_WEST + WEST, SOUTH_WEST + SOUTH, SOUTH_WEST + WEST,
@@ -217,7 +217,7 @@ void bb_print(const char *title, const bitboard_t bitboard)
//char c = p? p: 'X'; //char c = p? p: 'X';
if (title) if (title)
printf("%s\n", title); printf("%s\n", title);
for (rank_t r = RANK_8; r >= RANK_1; --r) { for (rank_t r = RANK_8 + 1; r --> RANK_1;) { /* "downto"" op." */
printf("%d ", r + 1); printf("%d ", r + 1);
for (file_t f = FILE_A; f <= FILE_H; ++f) { for (file_t f = FILE_A; f <= FILE_H; ++f) {
printf(" %c", bitboard & bb_sq[sq_make(f, r)] ? 'X': '.'); printf(" %c", bitboard & bb_sq[sq_make(f, r)] ? 'X': '.');
@@ -252,7 +252,7 @@ void bb_print_multi(const char *title, int n, ...)
if (title) if (title)
printf("%s\n", title); printf("%s\n", title);
for (rank_t r = RANK_8; r >= RANK_1; --r) { for (rank_t r = RANK_8 + 1; r --> RANK_1;) {
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
printf("%d ", r + 1); printf("%d ", r + 1);
for (file_t f = FILE_A; f <= FILE_H; ++f) { for (file_t f = FILE_A; f <= FILE_H; ++f) {

View File

@@ -115,7 +115,7 @@ void board_print_mask(const piece_t *board, const bitboard_t mask)
*/ */
void board_print_raw(const piece_t *board, const int type) void board_print_raw(const piece_t *board, const int type)
{ {
for (rank_t r = RANK_8; r >= RANK_1; --r) { for (rank_t r = RANK_8 + 1; r --> RANK_1;) {
for (file_t f = FILE_A; f <= FILE_H; ++f) { for (file_t f = FILE_A; f <= FILE_H; ++f) {
piece_t p = board[sq_make(f, r)]; piece_t p = board[sq_make(f, r)];
if (type) { if (type) {

View File

@@ -14,7 +14,7 @@
#ifndef _BOARD_H #ifndef _BOARD_H
#define _BOARD_H #define _BOARD_H
#include "brlib.h" #include <brlib.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "piece.h" #include "piece.h"
@@ -56,8 +56,8 @@ static __always_inline rank_t sq_rank(square_t square)
return square >> 3; return square >> 3;
} }
#define sq_ok(sq) ((sq) >= A1 && (sq) <= H8) #define sq_ok(sq) ((sq) <= H8)
#define sq_coord_ok(c) ((c) >= 0 && (c) < 8) #define sq_coord_ok(c) ((c) < 8)
/** /**
* sq_dist() - Chebyshev (king) distance between two squares (macro). * sq_dist() - Chebyshev (king) distance between two squares (macro).

View File

@@ -1,6 +1,6 @@
/* brchess.c - main loop. /* brchess.c - main loop.
* *
* Copyright (C) 2021-2023 Bruno Raoult ("br") * Copyright (C) 2021-2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later. * Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING. * Some rights reserved. See COPYING.
* *
@@ -12,25 +12,23 @@
*/ */
#include <err.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <readline/readline.h> #include <ctype.h>
#include <readline/history.h> #include <unistd.h>
#include <brlib.h> #include <brlib.h>
#include <list.h>
#include <debug.h>
#include "brchess.h"
#include "chessdefs.h" #include "chessdefs.h"
#include "board.h" #include "position.h"
#include "piece.h" #include "brchess.h"
#include "move.h" #include "hash.h"
#include "fen.h" #include "fen.h"
#include "eval.h"
#include "eval-simple.h"
#include "search.h" #include "search.h"
#include "hist.h"
#include "move-gen.h"
#include "move-do.h"
struct command { struct command {
char *name; /* User printable name */ char *name; /* User printable name */
@@ -38,289 +36,148 @@ struct command {
char *doc; /* function doc */ char *doc; /* function doc */
}; };
/* readline example inspired by : int execute_line (pos_t *, struct command *, char *);
* - https://thoughtbot.com/blog/tab-completion-in-gnu-readline
* - http://web.mit.edu/gnu/doc/html/rlman_2.html
*/
char **commands_completion(const char *, int, int);
char *commands_generator(const char *, int);
char *escape(const char *);
int quote_detector(char *, int);
int execute_line (pos_t *, char *line);
struct command *find_command (char *); struct command *find_command (char *);
char *stripwhite (char *string); int string_trim (char *str);
/* The names of functions that actually do the manipulation. */ /* The names of functions that actually do the manipulation. */
int do_help(pos_t *, char*);
int do_fen(pos_t *, char*); /* standard UCI commands */
int do_init(pos_t *, char*); int do_ucinewgame(pos_t *, char *);
int do_pos(pos_t *, char*); int do_uci(pos_t *, char *);
int do_genmoves(pos_t *, char*); int do_isready(pos_t *, char *);
int do_prmoves(pos_t *, char*);
//int do_prmovepos(pos_t *pos, char *arg); int do_position(pos_t *, char *);
int do_prpieces(pos_t *pos, char *arg);
int do_memstats(pos_t *, char*); /* commands *NOT* in UCI standard */
int do_eval(pos_t *, char*); int do_moves(pos_t *, char *);
int do_simple_eval(pos_t *, char*); int do_diagram(pos_t *, char *);
int do_move(pos_t *, char*); int do_perft(pos_t *, char *);
int do_quit(pos_t *, char*);
int do_debug(pos_t *, char*); int do_hist(pos_t *, char *);
int do_depth(pos_t *, char*); int do_help(pos_t *, char *);
int do_search(pos_t *, char*); int do_quit(pos_t *, char *);
int do_pvs(pos_t *, char*);
struct command commands[] = { struct command commands[] = {
{ "help", do_help, "Display this text" }, { "help", do_help, "(not UCI) This help" },
{ "?", do_help, "Synonym for 'help'" }, { "?", do_help, "(not UCI) This help" },
{ "fen", do_fen, "Set position to FEN" },
{ "init", do_init, "Set position to normal start position" },
{ "pos", do_pos, "Print current position" },
{ "quit", do_quit, "Quit" }, { "quit", do_quit, "Quit" },
{ "genmove", do_genmoves, "Generate move list for " },
{ "prmoves", do_prmoves, "Print position move list" }, { "uci", do_uci, "" },
// { "prmovepos", do_prmovepos, "Print Nth move resulting position" }, { "ucinewgame", do_ucinewgame, "" },
{ "prpieces", do_prpieces, "Print Pieces (from pieces lists)" }, { "isready", do_isready, "" },
{ "memstats", do_memstats, "Generate next move list" },
{ "eval", do_eval, "Eval current position" }, { "position", do_position, "position startpos|fen [moves ...]" },
{ "simple-eval", do_simple_eval, "Simple eval current position" },
{ "do_move", do_move, "execute nth move on current position" }, { "perft", do_perft, "(not UCI) perft [divide] [alt] depth" },
{ "debug", do_debug, "Set log level to LEVEL" }, { "moves", do_moves, "(not UCI) moves ..." },
{ "depth", do_depth, "Set search depth to N" }, { "diagram", do_diagram, "(not UCI) print current position diagram" },
{ "search", do_search, "Search best move (negamax)" }, { "hist", do_hist, "(not UCI) print history states" },
{ "pvs", do_pvs, "Search best move (Principal Variation Search)" },
{ NULL, (int(*)()) NULL, NULL } { NULL, (int(*)()) NULL, NULL }
}; };
static int done=0; static int done = 0;
static int depth=1;
int brchess(pos_t *pos) int brchess(pos_t *pos)
{ {
char *buffer, *s; char *str = NULL, *saveptr, *token, *args;
int len;
size_t lenstr = 0;
struct command *command;
rl_attempted_completion_function = commands_completion; while (!done && getline(&str, &lenstr, stdin) >= 0) {
rl_completer_quote_characters = "'\""; if (!(len = string_trim(str)))
rl_completer_word_break_characters = " "; continue;
rl_char_is_quoted_p = &quote_detector; token = strtok_r(str, " ", &saveptr);
if (! (command= find_command(token))) {
while (!done) { fprintf(stderr, "Unknown [%s] command. Try 'help'.\n", token);
buffer = readline("chess> "); continue;
if (!buffer)
break;
/* Remove leading and trailing whitespace from the line.
* Then, if there is anything left, add it to the history list
* and execute it.
*/
s = stripwhite(buffer);
if (*s) {
add_history(s);
execute_line(pos, s);
} }
free(buffer); args = strtok_r(NULL, "", &saveptr);
execute_line(pos, command, args);
} }
if (str)
free(str);
return 0; return 0;
} }
//char **commands_completion(const char *text, int start, int end)
char **commands_completion(const char *text, __unused int start, __unused int end)
{
rl_attempted_completion_over = 1;
return rl_completion_matches(text, commands_generator);
}
char *commands_generator(const char *text, int state)
{
static int list_index, len;
char *name;
if (!state) {
list_index = 0;
len = strlen(text);
}
while ((name = commands[list_index++].name)) {
if (rl_completion_quote_character) {
name = strdup(name);
} else {
name = escape(name);
}
if (strncmp(name, text, len) == 0) {
return name;
} else {
free(name);
}
}
return NULL;
}
char *escape(const char *original)
{
size_t original_len;
size_t i, j;
char *escaped, *resized_escaped;
original_len = strlen(original);
if (original_len > SIZE_MAX / 2) {
errx(1, "string too long to escape");
}
if ((escaped = malloc(2 * original_len + 1)) == NULL) {
err(1, NULL);
}
for (i = 0, j = 0; i < original_len; ++i, ++j) {
if (original[i] == ' ') {
escaped[j++] = '\\';
}
escaped[j] = original[i];
}
escaped[j] = '\0';
if ((resized_escaped = realloc(escaped, j)) == NULL) {
free(escaped);
resized_escaped = NULL;
err(1, NULL);
}
return resized_escaped;
}
int quote_detector(char *line, int index)
{
return index > 0
&& line[index - 1] == '\\'
&&!quote_detector(line, index - 1);
}
/* Execute a command line. */ /* Execute a command line. */
int execute_line(pos_t *pos, char *line) int execute_line(pos_t *pos, struct command *command, char *args)
{ {
register int i; return (*command->func)(pos, args);
struct command *command;
char *word;
/* Isolate the command word. */
i = 0;
while (line[i] && whitespace(line[i]))
i++;
word = line + i;
while (line[i] && !whitespace(line[i]))
i++;
if (line[i])
line[i++] = '\0';
command = find_command(word);
if (!command) {
fprintf(stderr, "%s: Unknown command.\n", word);
return -1;
}
/* Get argument to command, if any. */
while (whitespace(line[i]))
i++;
word = line + i;
/* return command number */
return (*command->func)(pos, word);
} }
/* Look up NAME as the name of a command, and return a pointer to that /**
command. Return a NULL pointer if NAME isn't a command name. */ * find_command - lookup UCI command.
* @name: &command string
*
* Look up NAME as the name of a command, and return a pointer to that
* command. Return a NULL pointer if NAME isn't a command name.
*/
struct command *find_command(char *name) struct command *find_command(char *name)
{ {
register int i; register int i;
for (i = 0; commands[i].name; i++) for (i = 0; commands[i].name; i++)
if (strcmp(name, commands[i].name) == 0) if (!strcmp(name, commands[i].name))
return &commands[i]; return commands + i;
return (struct command *)NULL; return NULL;
} }
/* Strip whitespace from the start and end of STRING. Return a pointer /*
into STRING. */ * int do_eval(__unused pos_t *pos, __unused char *arg)
char *stripwhite(char *string) * {
{ * eval_t material[2], control[2], mobility[2];
register char *s, *t; * for (int color = WHITE; color <= BLACK; ++color) {
* material[color] = eval_material(pos, color);
* control[color] = eval_square_control(pos, color);
* mobility[color] = eval_mobility(pos, color);
* printf("%s: material=%d mobility=%d controlled=%d\n",
* color? "Black": "White", material[color],
* mobility[color], control[color]);
* }
* eval_t res = eval(pos);
* printf("eval = %d centipawns\n", res);
* return 1;
* }
*
* int do_simple_eval(__unused pos_t *pos, __unused char *arg)
* {
* eval_t eval = eval_simple(pos);
* printf("eval = %d centipawns\n", eval);
* return 1;
* }
*/
for (s = string; whitespace(*s); s++) /*
; * int do_init(pos_t *pos, __unused char *arg)
* {
* startpos(pos);
* return 1;
* }
*/
if (*s == 0) /*
return s; * int do_genmoves(pos_t *pos, __unused char *arg)
* {
t = s + strlen(s) - 1; * moves_gen_all(pos);
while (t > s && whitespace(*t)) * return 1;
t--; * }
*++t = '\0'; *
* int do_prmoves(pos_t *pos, __unused char *arg)
return s; * {
} * uint debug_level = debug_level_get();
* debug_level_set(1);
int do_eval(__unused pos_t *pos, __unused char *arg) * moves_print(pos, M_PR_SEPARATE | M_PR_NUM | M_PR_LONG);
{ * debug_level_set(debug_level);
eval_t material[2], control[2], mobility[2]; * return 1;
for (int color = WHITE; color <= BLACK; ++color) { * }
material[color] = eval_material(pos, color); */
control[color] = eval_square_control(pos, color);
mobility[color] = eval_mobility(pos, color);
printf("%s: material=%d mobility=%d controlled=%d\n",
color? "Black": "White", material[color],
mobility[color], control[color]);
}
eval_t res = eval(pos);
printf("eval = %d centipawns\n", res);
return 1;
}
int do_simple_eval(__unused pos_t *pos, __unused char *arg)
{
eval_t eval = eval_simple(pos);
printf("eval = %d centipawns\n", eval);
return 1;
}
int do_fen(pos_t *pos, char *arg)
{
fen2pos(pos, arg);
return 1;
}
int do_init(pos_t *pos, __unused char *arg)
{
pos_startpos(pos);
return 1;
}
int do_pos(pos_t *pos, __unused char *arg)
{
pos_print(pos);
return 1;
}
int do_genmoves(pos_t *pos, __unused char *arg)
{
moves_gen_all(pos);
return 1;
}
int do_prmoves(pos_t *pos, __unused char *arg)
{
uint debug_level = debug_level_get();
debug_level_set(1);
moves_print(pos, M_PR_SEPARATE | M_PR_NUM | M_PR_LONG);
debug_level_set(debug_level);
return 1;
}
/* /*
* int do_prmovepos(pos_t *pos, char *arg) * int do_prmovepos(pos_t *pos, char *arg)
@@ -342,145 +199,302 @@ int do_prmoves(pos_t *pos, __unused char *arg)
* } * }
*/ */
int do_prpieces(pos_t *pos, __unused char *arg) /*
* int do_prpieces(pos_t *pos, __unused char *arg)
* {
* log_f(1, "%s\n", arg);
* pos_pieces_print(pos);
* return 1;
* }
*
* int do_memstats(__unused pos_t *pos,__unused char *arg)
* {
* moves_pool_stats();
* piece_pool_stats();
* pos_pool_stats();
* return 1;
* }
*/
/*
* int do_move(__unused pos_t *pos, __unused char *arg)
* {
* int i = 1, nmove = atoi(arg);
* move_t *move;
* pos_t *newpos;
*
* if (list_empty(&pos->moves[pos->turn])) {
* log_f(1, "No moves list.\n");
* return 0;
* }
* list_for_each_entry(move, &pos->moves[pos->turn], list) {
* if (i == nmove)
* goto doit;
* i++;
* }
* log_f(1, "Invalid <%d> move, should be <1-%d>.\n", nmove, i);
* return 0;
* doit:
* newpos = move_do(pos, move);
* pos_print(newpos);
*
* return 1;
* }
*/
int do_ucinewgame(__unused pos_t *pos, __unused char *arg)
{ {
log_f(1, "%s\n", arg); pos_clear(pos);
pos_pieces_print(pos); tt_clear();
return 1; return 1;
} }
int do_memstats(__unused pos_t *pos,__unused char *arg) int do_uci(__unused pos_t *pos, __unused char *arg)
{ {
moves_pool_stats(); printf("id name brchess " VERSION "\n");
piece_pool_stats(); printf("id author Bruno Raoult\n");
pos_pool_stats(); printf("option option name Hash type spin default %d min %d max %d\n",
hash_tt.mb, HASH_SIZE_MIN, HASH_SIZE_MAX);
printf("uciok\n");
return 1; return 1;
} }
int do_move(__unused pos_t *pos, __unused char *arg) int do_isready(__unused pos_t *pos, __unused char *arg)
{ {
int i = 1, nmove = atoi(arg); printf("readyok\n");
move_t *move;
pos_t *newpos;
if (list_empty(&pos->moves[pos->turn])) {
log_f(1, "No moves list.\n");
return 0;
}
list_for_each_entry(move, &pos->moves[pos->turn], list) {
if (i == nmove)
goto doit;
i++;
}
log_f(1, "Invalid <%d> move, should be <1-%d>.\n", nmove, i);
return 0;
doit:
newpos = move_do(pos, move);
pos_print(newpos);
return 1; return 1;
} }
int do_position(pos_t *pos, char *arg)
{
char *saveptr, *token, *fen, *moves;
hist_init();
/* separate "moves" section */
if ((moves = strstr(arg, "moves"))) {
*(moves - 1) = 0;
}
saveptr = NULL;
token = strtok_r(arg, " ", &saveptr);
if (!strcmp(token, "startpos")) {
startpos(pos);
do_diagram(pos, "");
} else if (!strcmp(token, "fen")) {
fen = strtok_r(NULL, "", &saveptr); /* full fen (till '\0') */
//printf("fen=%s\n", fen);
if (!fen)
return 1;
if (!fen2pos(pos, fen))
return 1;
//do_diagram(pos, "");
} else {
return 1;
}
//puts("zob");
//move_t move_none = MOVE_NONE;
//hist_push(&pos->state, &move_none);
if (moves) {
//puts("zobi");
saveptr = NULL;
moves = strtok_r(moves, " ", &saveptr); /* skip "moves" */
moves = strtok_r(NULL, "", &saveptr); /* all moves (till '\0') */
//printf("moves = %s\n", moves);
do_moves(pos, moves);
}
/* link last position t history */
//hist_pop();
hist_link(pos);
return 1;
}
int do_moves(__unused pos_t *pos, char *arg)
{
char *saveptr = NULL, *token, check[8];
move_t move;
state_t state;
movelist_t movelist;
saveptr = NULL;
token = strtok_r(arg, " ", &saveptr);
while (token) {
move = move_from_str(token);
move_to_str(check, move, 0);
printf("move: [%s] %s\n", token, check);
pos_set_checkers_pinners_blockers(pos);
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
move = move_find_in_movelist(move, &movelist);
if (move == MOVE_NONE) {
/* should we reset here ? */
return 1;
}
//printf("move: %s\n", move_to_str(check, move, 0));
hist_push(&pos->state); /* push previous state */
move_do(pos, move, &state);
pos_print(pos);
hist_static_print();
token = strtok_r(NULL, " ", &saveptr);
}
//hist_static_print();
return 1;
}
int do_diagram(pos_t *pos, __unused char *arg)
{
pos_print(pos);
return 1;
}
int do_perft(__unused pos_t *pos, __unused char *arg)
{
char *saveptr, *token;
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 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;
}
int do_hist(__unused pos_t *pos, __unused char *arg)
{
hist_static_print();
return 0;
}
int do_help(__unused pos_t *pos, __unused char *arg)
{
for (struct command *cmd = commands; cmd->name; ++cmd) {
printf("%12s:\t%s\n", cmd->name, cmd->doc);
/* Print in six columns. */
}
return 0;
}
int do_quit(__unused pos_t *pos, __unused char *arg) int do_quit(__unused pos_t *pos, __unused char *arg)
{ {
return done = 1; return done = 1;
} }
int do_debug(__unused pos_t *pos, __unused char *arg) /*
* int do_depth(__unused pos_t *pos, char *arg)
* {
* depth = atoi(arg);
* printf("depth = %d\n", depth);
* return 1;
*
* }
*
* int do_search(pos_t *pos, __unused char *arg)
* {
* int debug_level = debug_level_get();
* float timer1, timer2, nodes_sec;
*
* timer1 = debug_timer_elapsed();
* negamax(pos, depth, pos->turn == WHITE ? 1 : -1);
* timer2 = debug_timer_elapsed();
* nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
* log(1, "best=");
* debug_level_set(1);
* move_print(0, pos->bestmove, 0);
* debug_level_set(debug_level);
* log(1, " negamax=%d\n", pos->bestmove->negamax);
* printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth,
* pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000);
* return 1;
* }
*/
/*
* int do_pvs(pos_t *pos, __unused char *arg)
* {
* int debug_level = debug_level_get();
* float timer1, timer2, nodes_sec;
* eval_t _pvs;
*
* timer1 = debug_timer_elapsed();
* moves_gen_eval_sort(pos);
* _pvs = pvs(pos, depth, EVAL_MIN, EVAL_MAX, pos->turn == WHITE ? 1 : -1);
* timer2 = debug_timer_elapsed();
* nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
* log(1, "best=");
* if (pos->bestmove) {
* debug_level_set(1);
* move_print(0, pos->bestmove, 0);
* debug_level_set(debug_level);
* log(1, " pvs=%d stored=%d\n", _pvs, pos->bestmove->negamax);
* } else {
* log(1, "<no-best-move>");
* }
* printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth,
* pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000);
* return 1;
* }
*/
/**
* string_trim - cleanup (trim) blank characters in string.
* @str: &string to clean
*
* str is cleaned and packed with the following rules:
* - Leading and trailing blank characters are removed.
* - consecutive blank characters are replaced by one space.
* - non printable characters are removed.
*
* "blank" means characters as understood by isspace(3): space, form-feed ('\f'),
* newline ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical
* tab ('\v').
*
* @return: new @str len.
*/
int string_trim(char *str)
{ {
debug_level_set(atoi(arg)); char *to = str, *from = str;
return 1; int state = 1;
while (*from) {
switch (state) {
case 1: /* blanks */
while (*from && isspace(*from))
from++;
state = 0;
break;
case 0: /* token */
while (*from && !isspace(*from)) {
if (isprint(*from))
*to++ = *from;
from++;
}
*to++ = ' ';
state = 1;
}
}
if (to > str)
to--;
*to = 0;
return to - str;
} }
/* Print out help for ARG, or for all of the commands if ARG is
not present. */
int do_help(__unused pos_t *pos, __unused char *arg)
{
int i;
int printed = 0;
for (i = 0; commands[i].name; i++) { /**
if (!*arg || (strcmp(arg, commands[i].name) == 0)) { * usage - brchess usage function.
printf("%-11.11s%s.\n", commands[i].name, commands[i].doc);
printed++;
}
}
if (!printed) {
printf("No commands match `%s'. Possibilties are:\n", arg);
for (i = 0; commands[i].name; i++) {
/* Print in six columns. */
if (printed == 6) {
printed = 0;
printf("\n");
}
printf("%s\t", commands[i].name);
printed++;
}
if (printed)
printf("\n");
}
return 0;
}
int do_depth(__unused pos_t *pos, char *arg)
{
depth = atoi(arg);
printf("depth = %d\n", depth);
return 1;
}
int do_search(pos_t *pos, __unused char *arg)
{
int debug_level = debug_level_get();
float timer1, timer2, nodes_sec;
timer1 = debug_timer_elapsed();
negamax(pos, depth, pos->turn == WHITE ? 1 : -1);
timer2 = debug_timer_elapsed();
nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
log(1, "best=");
debug_level_set(1);
move_print(0, pos->bestmove, 0);
debug_level_set(debug_level);
log(1, " negamax=%d\n", pos->bestmove->negamax);
printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth,
pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000);
return 1;
}
int do_pvs(pos_t *pos, __unused char *arg)
{
int debug_level = debug_level_get();
float timer1, timer2, nodes_sec;
eval_t _pvs;
timer1 = debug_timer_elapsed();
moves_gen_eval_sort(pos);
_pvs = pvs(pos, depth, EVAL_MIN, EVAL_MAX, pos->turn == WHITE ? 1 : -1);
timer2 = debug_timer_elapsed();
nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
log(1, "best=");
if (pos->bestmove) {
debug_level_set(1);
move_print(0, pos->bestmove, 0);
debug_level_set(debug_level);
log(1, " pvs=%d stored=%d\n", _pvs, pos->bestmove->negamax);
} else {
log(1, "<no-best-move>");
}
printf("Depth:%d Nodes:%luK time:%.02fs (%.0f kn/s)\n", depth,
pos->node_count / 1000, (timer2 - timer1)/NANOSEC, nodes_sec/1000);
return 1;
}
/** main()
* options:
int brchess(pos_t *pos)
* *
*/ */
static int usage(char *prg) static int usage(char *prg)
@@ -489,24 +503,28 @@ static int usage(char *prg)
return 1; return 1;
} }
#include <unistd.h>
int main(int ac, char **av) int main(int ac, char **av)
{ {
pos_t *pos; pos_t *pos;
int opt; int opt;
piece_pool_init(); init_all();
moves_pool_init(); pos = pos_new();
pos_pool_init(); hist_link(pos);
pos = pos_get(); printf("\nWelcome to brchess " VERSION "\nEngine ready.\n");
debug_init(1, stderr, true);
eval_simple_init();
// size_t len = 0;
// char *str = NULL;
//while (getline(&str, &len, stdin) >= 0) {
// printf("[%s] -> ", str);
// int newlen = string_trim(str);
// printf("%d [%s]\n", newlen, str);
//}
//exit(0);
while ((opt = getopt(ac, av, "d:f:")) != -1) { while ((opt = getopt(ac, av, "d:f:")) != -1) {
switch (opt) { switch (opt) {
case 'd': case 'd':
debug_level_set(atoi(optarg)); //debug_level_set(atoi(optarg));
break; break;
case 'f': case 'f':
fen2pos(pos, optarg); fen2pos(pos, optarg);

View File

@@ -14,7 +14,7 @@
#ifndef _CHESSDEFS_H #ifndef _CHESSDEFS_H
#define _CHESSDEFS_H #define _CHESSDEFS_H
#include "brlib.h" /* brlib types */ #include <brlib.h> /* brlib types */
#define ONE 1ul #define ONE 1ul
#define U64(const_u64) const_u64##UL #define U64(const_u64) const_u64##UL
@@ -81,9 +81,11 @@ typedef enum {
/* game phases /* game phases
*/ */
#define OPENING 0 typedef enum {
#define MIDDLEGAME 1 MIDGAME,
#define ENDGAME 2 ENDGAME,
PHASE_NB
} phase_t;
/* forward defs */ /* forward defs */
typedef struct __pos_s pos_t; typedef struct __pos_s pos_t;
@@ -91,17 +93,16 @@ typedef struct __movelist_s movelist_t;
/* basic types /* basic types
*/ */
typedef u64 bitboard_t; typedef u64 bitboard_t;
typedef s16 eval_t;
/* eval type /* forward enum definition is impossible in C11.
* To simplify cross-dependancies, all important enum are moved here.
*/ */
//typedef s32 eval_t;
/* forward enum definition is impossible in C11, to simplify enum {
* cross-dependancies, all important enum are moved here. //_SSQUARE_ = -1, /* force signed enum */
*/
typedef enum {
_SSQUARE_ = -1, /* force signed enum */
A1 = 0, B1, C1, D1, E1, F1, G1, H1, A1 = 0, B1, C1, D1, E1, F1, G1, H1,
A2, B2, C2, D2, E2, F2, G2, H2, A2, B2, C2, D2, E2, F2, G2, H2,
A3, B3, C3, D3, E3, F3, G3, H3, A3, B3, C3, D3, E3, F3, G3, H3,
@@ -110,23 +111,26 @@ typedef enum {
A6, B6, C6, D6, E6, F6, G6, H6, A6, B6, C6, D6, E6, F6, G6, H6,
A7, B7, C7, D7, E7, F7, G7, H7, A7, B7, C7, D7, E7, F7, G7, H7,
A8, B8, C8, D8, E8, F8, G8, H8, A8, B8, C8, D8, E8, F8, G8, H8,
SQUARE_MAX = 64, SQUARE_NB = 64,
SQUARE_NONE = 64 SQUARE_NONE = 64
} square_t; };
typedef u8 square_t;
typedef enum { enum {
_SFILE_ = -1, /* force signed enum */ //_SFILE_ = -1, /* force signed enum */
FILE_A = 0, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_A = 0, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H,
FILE_MAX, FILE_NB,
} file_t; };
typedef u8 file_t;
typedef enum { enum {
_SRANK_ = -1, /* force signed enum */ //_SRANK_ = -1, /* force signed enum */
RANK_1 = 0, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_1 = 0, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8,
RANK_MAX, RANK_NB,
} rank_t; };
typedef u8 rank_t;
typedef enum { enum {
NORTH = 8, NORTH = 8,
EAST = 1, EAST = 1,
SOUTH = -NORTH, SOUTH = -NORTH,
@@ -136,7 +140,8 @@ typedef enum {
SOUTH_EAST = (SOUTH + EAST), SOUTH_EAST = (SOUTH + EAST),
SOUTH_WEST = (SOUTH + WEST), SOUTH_WEST = (SOUTH + WEST),
NORTH_WEST = (NORTH + WEST), NORTH_WEST = (NORTH + WEST),
} dir_t; };
typedef u8 dir_t;
/* define diff for relative squares */ /* define diff for relative squares */
#define sq_up(c) ((c) == WHITE ? NORTH: SOUTH) #define sq_up(c) ((c) == WHITE ? NORTH: SOUTH)

View File

@@ -11,20 +11,175 @@
* *
*/ */
#include "br.h" #include <brlib.h>
#include "debug.h"
#include "chessdefs.h"
#include "piece.h" #include "piece.h"
#include "eval-simple.h"
#include "position.h" #include "position.h"
#include "eval-simple.h"
/* /*
* Tables are from https://www.chessprogramming.org/Simplified_Evaluation_Function * Piece-square tables. For easier reading, they are defined for black side:
* *
* Attention! Tables are black point of view (to be visually easier to read). * {
* A8 .... H8
* ..........
* ..........
* A1 .... H1
* }
*/ */
const struct pc_sq pc_sq_def[] = {
static int mg_pawn[] = { {
/*
* rofchade:
* https://www.talkchess.com/forum3/viewtopic.php?f=2&t=68311&start=19
*/
"rofchade",
{
[PAWN] = {
{ /* midgame */
0, 0, 0, 0, 0, 0, 0, 0,
98, 134, 61, 95, 68, 126, 34, -11,
-6, 7, 26, 31, 65, 56, 25, -20,
-14, 13, 6, 21, 23, 12, 17, -23,
-27, -2, -5, 12, 17, 6, 10, -25,
-26, -4, -4, -10, 3, 3, 33, -12,
-35, -1, -20, -23, -15, 24, 38, -22,
0, 0, 0, 0, 0, 0, 0, 0,
},
{ /* endgame */
0, 0, 0, 0, 0, 0, 0, 0,
178, 173, 158, 134, 147, 132, 165, 187,
94, 100, 85, 67, 56, 53, 82, 84,
32, 24, 13, 5, -2, 4, 17, 17,
13, 9, -3, -7, -7, -8, 3, -1,
4, 7, -6, 1, 0, -5, -1, -8,
13, 8, 8, 10, 13, 0, 2, -7,
0, 0, 0, 0, 0, 0, 0, 0,
}
},
[KNIGHT] = {
{ /* midgame */
-167, -89, -34, -49, 61, -97, -15, -107,
-73, -41, 72, 36, 23, 62, 7, -17,
-47, 60, 37, 65, 84, 129, 73, 44,
-9, 17, 19, 53, 37, 69, 18, 22,
-13, 4, 16, 13, 28, 19, 21, -8,
-23, -9, 12, 10, 19, 17, 25, -16,
-29, -53, -12, -3, -1, 18, -14, -19,
-105, -21, -58, -33, -17, -28, -19, -23,
},
{ /* endgame */
-58, -38, -13, -28, -31, -27, -63, -99,
-25, -8, -25, -2, -9, -25, -24, -52,
-24, -20, 10, 9, -1, -9, -19, -41,
-17, 3, 22, 22, 22, 11, 8, -18,
-18, -6, 16, 25, 16, 17, 4, -18,
-23, -3, -1, 15, 10, -3, -20, -22,
-42, -20, -10, -5, -2, -20, -23, -44,
-29, -51, -23, -15, -22, -18, -50, -64,
}
},
[BISHOP] = {
{ /* midgame */
-29, 4, -82, -37, -25, -42, 7, -8,
-26, 16, -18, -13, 30, 59, 18, -47,
-16, 37, 43, 40, 35, 50, 37, -2,
-4, 5, 19, 50, 37, 37, 7, -2,
-6, 13, 13, 26, 34, 12, 10, 4,
0, 15, 15, 15, 14, 27, 18, 10,
4, 15, 16, 0, 7, 21, 33, 1,
-33, -3, -14, -21, -13, -12, -39, -21,
},
{ /* endgame */
-14, -21, -11, -8, -7, -9, -17, -24,
-8, -4, 7, -12, -3, -13, -4, -14,
2, -8, 0, -1, -2, 6, 0, 4,
-3, 9, 12, 9, 14, 10, 3, 2,
-6, 3, 13, 19, 7, 10, -3, -9,
-12, -3, 8, 10, 13, 3, -7, -15,
-14, -18, -7, -1, 4, -9, -15, -27,
-23, -9, -23, -5, -9, -16, -5, -17,
},
},
[ROOK] = {
{ /* midgame */
32, 42, 32, 51, 63, 9, 31, 43,
27, 32, 58, 62, 80, 67, 26, 44,
-5, 19, 26, 36, 17, 45, 61, 16,
-24, -11, 7, 26, 24, 35, -8, -20,
-36, -26, -12, -1, 9, -7, 6, -23,
-45, -25, -16, -17, 3, 0, -5, -33,
-44, -16, -20, -9, -1, 11, -6, -71,
-19, -13, 1, 17, 16, 7, -37, -26,
},
{ /* endgame */
13, 10, 18, 15, 12, 12, 8, 5,
11, 13, 13, 11, -3, 3, 8, 3,
7, 7, 7, 5, 4, -3, -5, -3,
4, 3, 13, 1, 2, 1, -1, 2,
3, 5, 8, 4, -5, -6, -8, -11,
-4, 0, -5, -1, -7, -12, -8, -16,
-6, -6, 0, 2, -9, -9, -11, -3,
-9, 2, 3, -1, -5, -13, 4, -20,
},
},
[QUEEN] = {
{ /* midgame */
-28, 0, 29, 12, 59, 44, 43, 45,
-24, -39, -5, 1, -16, 57, 28, 54,
-13, -17, 7, 8, 29, 56, 47, 57,
-27, -27, -16, -16, -1, 17, -2, 1,
-9, -26, -9, -10, -2, -4, 3, -3,
-14, 2, -11, -2, -5, 2, 14, 5,
-35, -8, 11, 2, 8, 15, -3, 1,
-1, -18, -9, 10, -15, -25, -31, -50,
},
{ /* endgame */
-9, 22, 22, 27, 27, 19, 10, 20,
-17, 20, 32, 41, 58, 25, 30, 0,
-20, 6, 9, 49, 47, 35, 19, 9,
3, 22, 24, 45, 57, 40, 57, 36,
-18, 28, 19, 47, 31, 34, 39, 23,
-16, -27, 15, 6, 9, 17, 10, 5,
-22, -23, -30, -16, -16, -23, -36, -32,
-33, -28, -22, -43, -5, -32, -20, -41,
},
},
[KING] = { /* midgame */
{
-65, 23, 16, -15, -56, -34, 2, 13,
29, -1, -20, -7, -8, -4, -38, -29,
-9, 24, 2, -16, -20, 6, 22, -22,
-17, -20, -12, -27, -30, -25, -14, -36,
-49, -1, -27, -39, -46, -44, -33, -51,
-14, -14, -22, -46, -44, -30, -15, -27,
1, 7, -8, -64, -43, -16, 9, 8,
-15, 36, 12, -54, 8, -28, 24, 14,
},
{ /* endgame */
-74, -35, -18, -18, -11, 15, 4, -17,
-12, 17, 14, 17, 17, 38, 23, 11,
10, 17, 23, 15, 20, 45, 44, 13,
-8, 22, 24, 27, 26, 33, 26, 3,
-18, -4, 21, 24, 27, 23, 9, -11,
-19, -3, 11, 21, 23, 16, 7, -9,
-27, -11, 4, 13, 14, 4, -5, -17,
-53, -34, -21, -11, -28, -14, -24, -43
}
}
}
}, /* CPW */
{
/*
* CPW:
* https://www.chessprogramming.org/Simplified_Evaluation_Function
* Note: ≠ https://github.com/nescitus/cpw-engine
*/
"cpw",
{
[PAWN] = {
{ /* midgame */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
10, 10, 20, 30, 30, 20, 10, 10, 10, 10, 20, 30, 30, 20, 10, 10,
@@ -32,10 +187,21 @@ static int mg_pawn[] = {
0, 0, 0, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 0, 0, 0,
5, -5, -10, 0, 0, -10, -5, 5, 5, -5, -10, 0, 0, -10, -5, 5,
5, 10, 10, -20, -20, 10, 10, 5, 5, 10, 10, -20, -20, 10, 10, 5,
0, 0, 0, 0, 0, 0, 0, 0 0, 0, 0, 0, 0, 0, 0, 0,
}; },
{ /* endgame */
static int mg_knight[] = { 0, 0, 0, 0, 0, 0, 0, 0,
50, 50, 50, 50, 50, 50, 50, 50,
10, 10, 20, 30, 30, 20, 10, 10,
5, 5, 10, 25, 25, 10, 5, 5,
0, 0, 0, 20, 20, 0, 0, 0,
5, -5, -10, 0, 0, -10, -5, 5,
5, 10, 10, -20, -20, 10, 10, 5,
0, 0, 0, 0, 0, 0, 0, 0,
},
},
[KNIGHT] = {
{ /* midgame */
-50, -40, -30, -30, -30, -30, -40, -50, -50, -40, -30, -30, -30, -30, -40, -50,
-40, -20, 0, 0, 0, 0, -20, -40, -40, -20, 0, 0, 0, 0, -20, -40,
-30, 0, 10, 15, 15, 10, 0, -30, -30, 0, 10, 15, 15, 10, 0, -30,
@@ -44,9 +210,20 @@ static int mg_knight[] = {
-30, 5, 10, 15, 15, 10, 5, -30, -30, 5, 10, 15, 15, 10, 5, -30,
-40, -20, 0, 5, 5, 0, -20, -40, -40, -20, 0, 5, 5, 0, -20, -40,
-50, -40, -30, -30, -30, -30, -40, -50 -50, -40, -30, -30, -30, -30, -40, -50
}; },
{ /* endgame */
static int mg_bishop[] = { -50, -40, -30, -30, -30, -30, -40, -50,
-40, -20, 0, 0, 0, 0, -20, -40,
-30, 0, 10, 15, 15, 10, 0, -30,
-30, 5, 15, 20, 20, 15, 5, -30,
-30, 0, 15, 20, 20, 15, 0, -30,
-30, 5, 10, 15, 15, 10, 5, -30,
-40, -20, 0, 5, 5, 0, -20, -40,
-50, -40, -30, -30, -30, -30, -40, -50
},
},
[BISHOP] = {
{ /* midgame */
-20, -10, -10, -10, -10, -10, -10, -20, -20, -10, -10, -10, -10, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, 0, 0, 0, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10, -10, 0, 5, 10, 10, 5, 0, -10,
@@ -54,10 +231,21 @@ static int mg_bishop[] = {
-10, 0, 10, 10, 10, 10, 0, -10, -10, 0, 10, 10, 10, 10, 0, -10,
-10, 10, 10, 10, 10, 10, 10, -10, -10, 10, 10, 10, 10, 10, 10, -10,
-10, 5, 0, 0, 0, 0, 5, -10, -10, 5, 0, 0, 0, 0, 5, -10,
-20, -10, -10, -10, -10, -10, -10, -20 -20, -10, -10, -10, -10, -10, -10, -20,
}; },
{ /* endgame */
static int mg_rook[] = { -20, -10, -10, -10, -10, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 5, 5, 10, 10, 5, 5, -10,
-10, 0, 10, 10, 10, 10, 0, -10,
-10, 10, 10, 10, 10, 10, 10, -10,
-10, 5, 0, 0, 0, 0, 5, -10,
-20, -10, -10, -10, -10, -10, -10, -20,
},
},
[ROOK] = {
{ /* midgame */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5, 5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5,
@@ -65,10 +253,21 @@ static int mg_rook[] = {
-5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5, -5, 0, 0, 0, 0, 0, 0, -5,
0, 0, 0, 5, 5, 0, 0, 0 0, 0, 0, 5, 5, 0, 0, 0,
}; },
{ /* endgame */
static int mg_queen[] = { 0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
0, 0, 0, 5, 5, 0, 0, 0,
},
},
[QUEEN] = {
{ /* midgame */
-20, -10, -10, -5, -5, -10, -10, -20, -20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, 0, 0, 0, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10, -10, 0, 5, 5, 5, 5, 0, -10,
@@ -76,10 +275,21 @@ static int mg_queen[] = {
0, 0, 5, 5, 5, 5, 0, -5, 0, 0, 5, 5, 5, 5, 0, -5,
-10, 5, 5, 5, 5, 5, 0, -10, -10, 5, 5, 5, 5, 5, 0, -10,
-10, 0, 5, 0, 0, 0, 0, -10, -10, 0, 5, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20 -20, -10, -10, -5, -5, -10, -10, -20,
}; },
{ /* endgame */
static int mg_king[] = { -20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 0, 0, 0, 0, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10,
-5, 0, 5, 5, 5, 5, 0, -5,
0, 0, 5, 5, 5, 5, 0, -5,
-10, 5, 5, 5, 5, 5, 0, -10,
-10, 0, 5, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20,
},
},
[KING] = { /* midgame */
{
-30, -40, -40, -50, -50, -40, -40, -30, -30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30, -30, -40, -40, -50, -50, -40, -40, -30,
-30, -40, -40, -50, -50, -40, -40, -30, -30, -40, -40, -50, -50, -40, -40, -30,
@@ -87,10 +297,9 @@ static int mg_king[] = {
-20, -30, -30, -40, -40, -30, -30, -20, -20, -30, -30, -40, -40, -30, -30, -20,
-10, -20, -20, -20, -20, -20, -20, -10, -10, -20, -20, -20, -20, -20, -20, -10,
20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20,
20, 30, 10, 0, 0, 10, 30, 20 20, 30, 10, 0, 0, 10, 30, 20,
}; },
{ /* endgame */
static int eg_king[] = {
-50, -40, -30, -20, -20, -30, -40, -50, -50, -40, -30, -20, -20, -30, -40, -50,
-30, -20, -10, 0, 0, -10, -20, -30, -30, -20, -10, 0, 0, -10, -20, -30,
-30, -10, 20, 30, 30, 20, -10, -30, -30, -10, 20, 30, 30, 20, -10, -30,
@@ -98,52 +307,219 @@ static int eg_king[] = {
-30, -10, 30, 40, 40, 30, -10, -30, -30, -10, 30, 40, 40, 30, -10, -30,
-30, -10, 20, 30, 30, 20, -10, -30, -30, -10, 20, 30, 30, 20, -10, -30,
-30, -30, 0, 0, 0, 0, -30, -30, -30, -30, 0, 0, 0, 0, -30, -30,
-50, -30, -30, -30, -30, -30, -30, -50 -50, -30, -30, -30, -30, -30, -30, -50,
}; }
}
/* as pieces bitboard tables start at position 2; we make these tables }
* bigger. }, /* CPW */
{
/*
* sjeng: https://github.com/gcp/sjeng
* Rook and Queen from CPW.
*/ */
static int *mg_tables[] = { "sjeng",
NULL, {
NULL, [PAWN] = {
mg_pawn, { /* midgame */
mg_knight, 0, 0, 0, 0, 0, 0, 0, 0,
mg_bishop, 5, 10, 15, 20, 20, 15, 10, 5,
mg_rook, 4, 8, 12, 16, 16, 12, 8, 4,
mg_queen, 3, 6, 9, 14, 14, 9, 6, 3,
mg_king 2, 4, 6, 12, 12, 6, 4, 2,
1, 2, 3, 10, 10, 3, 2, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
},
{ /* endgame */
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 15, 20, 20, 15, 10, 5,
4, 8, 12, 16, 16, 12, 8, 4,
3, 6, 9, 14, 14, 9, 6, 3,
2, 4, 6, 12, 12, 6, 4, 2,
1, 2, 3, 10, 10, 3, 2, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
},
},
[KNIGHT] = {
{ /* midgame */
-20, -10, -10, -10, -10, -10, -10, -20,
-10, 0, 0, 3, 3, 0, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 3, 3, 0, 0, -10,
-20, -10, -10, -10, -10, -10, -10, -20,
},
{ /* endgame */
-20, -10, -10, -10, -10, -10, -10, -20,
-10, 0, 0, 3, 3, 0, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 5, 10, 10, 5, 0, -10,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 3, 3, 0, 0, -10,
-20, -10, -10, -10, -10, -10, -10, -20,
},
},
[BISHOP] = {
{ /* midgame */
-2, -2, -2, -2, -2, -2, -2, -2,
-2, 8, 5, 5, 5, 5, 8, -2,
-2, 3, 3, 5, 5, 3, 3, -2,
-2, 2, 5, 4, 4, 5, 2, -2,
-2, 2, 5, 4, 4, 5, 2, -2,
-2, 3, 3, 5, 5, 3, 3, -2,
-2, 8, 5, 5, 5, 5, 8, -2,
-2, -2, -2, -2, -2, -2, -2, -2,
},
{ /* endgame */
-2, -2, -2, -2, -2, -2, -2, -2,
-2, 8, 5, 5, 5, 5, 8, -2,
-2, 3, 3, 5, 5, 3, 3, -2,
-2, 2, 5, 4, 4, 5, 2, -2,
-2, 2, 5, 4, 4, 5, 2, -2,
-2, 3, 3, 5, 5, 3, 3, -2,
-2, 8, 5, 5, 5, 5, 8, -2,
-2, -2, -2, -2, -2, -2, -2, -2,
},
},
[ROOK] = {
{ /* midgame */
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
0, 0, 0, 5, 5, 0, 0, 0,
},
{ /* endgame */
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 10, 10, 10, 10, 10, 5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
-5, 0, 0, 0, 0, 0, 0, -5,
0, 0, 0, 5, 5, 0, 0, 0,
},
},
[QUEEN] = {
{ /* midgame */
-20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 5, 0, 0, 0, 0, -10,
-10, 5, 5, 5, 5, 5, 0, -10,
0, 0, 5, 5, 5, 5, 0, -5,
-5, 0, 5, 5, 5, 5, 0, -5,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20,
},
{ /* endgame */
-20, -10, -10, -5, -5, -10, -10, -20,
-10, 0, 5, 0, 0, 0, 0, -10,
-10, 5, 5, 5, 5, 5, 0, -10,
0, 0, 5, 5, 5, 5, 0, -5,
-5, 0, 5, 5, 5, 5, 0, -5,
-10, 0, 5, 5, 5, 5, 0, -10,
-10, 0, 0, 0, 0, 0, 0, -10,
-20, -10, -10, -5, -5, -10, -10, -20,
},
},
[KING] = { /* midgame */
{
-55, -55, -89, -89, -89, -89, -55, -55,
-34, -34, -55, -55, -55, -55, -34, -34,
-21, -21, -34, -34, -34, -34, -21, -21,
-13, -13, -21, -21, -21, -21, -13, -13,
-8, -8, -13, -13, -13, -13, -8, -8,
-5, -5, -8, -8, -8, -8, -5, -5,
-3, -5, -6, -6, -6, -6, -5, -3,
2, 14, 0, 0, 0, 9, 14, 2,
},
{ /* endgame */
-5, -3, -1, 0, 0, -1, -3, -5,
-3, 10, 10, 10, 10, 10, 10, -3,
-1, 10, 25, 25, 25, 25, 10, -1,
0, 10, 25, 30, 30, 25, 10, 0,
0, 10, 25, 30, 30, 25, 10, 0,
-1, 10, 25, 25, 25, 25, 10, -1,
-3, 10, 10, 10, 10, 10, 10, -3,
-5, -3, -1, 0, 0, -1, -3, -5,
}
}
},
}, /* sjeng */
}; };
static int *eg_tables[] = { const int nb_pc_sq = ARRAY_SIZE(pc_sq_def); /* # of predefined pc_sq tables */
NULL, int pc_sq_current = 0;
NULL, int pc_sq_mg[COLOR_NB][PT_NB][SQUARE_NB];
mg_pawn, int pc_sq_eg[COLOR_NB][PT_NB][SQUARE_NB];
mg_knight,
mg_bishop,
mg_rook,
mg_queen,
eg_king
};
/* to flip vertically a square, we need to XOR it with 56 /* phase calculation from Fruit:
*/ * https://github.com/Warpten/Fruit-2.1
static int mg_table[2][6 + 2][64]; */
static int eg_table[2][6 + 2][64]; int phase;
static u16 piece_phase[] = { 0, 1, 1, 2, 4, 0 };
static const int p_phase = 0;
static const int n_phase = 1;
static const int b_phase = 1;
static const int r_phase = 2;
static const int q_phase = 4;
static const int total_phase = p_phase * 16 + n_phase * 4 +
b_phase * 4 + r_phase * 4 + q_phase * 2;
int calc_phase(pos_t *pos)
{
phase = total_phase;
phase -= p_phase * popcount64(pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]);
phase -= n_phase * popcount64(pos->bb[WHITE][KNIGHT] | pos->bb[BLACK][KNIGHT]);
phase -= b_phase * popcount64(pos->bb[WHITE][BISHOP] | pos->bb[BLACK][BISHOP]);
phase -= r_phase * popcount64(pos->bb[WHITE][ROOK] | pos->bb[BLACK][ROOK]);
phase -= q_phase * popcount64(pos->bb[WHITE][QUEEN] | pos->bb[BLACK][QUEEN]);
phase = max(phase, 0);
return (phase * 256 + (total_phase / 2)) / total_phase;
}
int eval_simple_find(char *str)
{
for (int i = 0; i < nb_pc_sq; ++i)
if (!strcmp(pc_sq_def[i].name, str))
return i;
return -1;
}
void eval_simple_set(int set)
{
const struct pc_sq *cur = pc_sq_def + set;
# ifdef DEBUG_EVAL
printf("initializing piece-square tables %d\n", set);
# endif
pc_sq_current = set;
for (piece_type_t pt = PAWN; pt < PT_NB; ++pt) {
for (square_t sq = 0; sq < SQUARE_NB; ++sq) {
pc_sq_mg[BLACK][pt][sq] = cur->val[MIDGAME][pt][sq];
pc_sq_mg[WHITE][pt][sq] = cur->val[MIDGAME][pt][FLIP_V(sq)];
pc_sq_eg[BLACK][pt][sq] = cur->val[ENDGAME][pt][sq];
pc_sq_eg[WHITE][pt][sq] = cur->val[ENDGAME][pt][FLIP_V(sq)];
}
}
}
void eval_simple_init(void) void eval_simple_init(void)
{ {
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(1, "initializing piece tables\n"); printf("initializing eval_simple\n");
# endif # endif
for (int piece = BB_PAWN; piece <= BB_KING; ++piece) { eval_simple_set(pc_sq_current);
for (int square = 0; square < 64; ++square) {
mg_table[WHITE][piece][square] = mg_tables[piece][FLIP_V(square)];
eg_table[WHITE][piece][square] = eg_tables[piece][FLIP_V(square)];
mg_table[BLACK][piece][square] = mg_tables[piece][square];
eg_table[BLACK][piece][square] = eg_tables[piece][square];
}
}
} }
/** /**
@@ -152,47 +528,43 @@ void eval_simple_init(void)
* *
* This function is normally used only during initialization, * This function is normally used only during initialization,
* or when changing phase (middlegame <--> endgame), as the eval * or when changing phase (middlegame <--> endgame), as the eval
* will be done increntally when doing moves. * will be done incrementally when doing moves.
* *
* @return: the @pos evaluation in centipawns * @return: the @pos evaluation in centipawns
*/ */
eval_t eval_simple(pos_t *pos) eval_t eval_simple(pos_t *pos)
{ {
eval_t eval[2] = { 0, 0 }; eval_t eval[2] = { 0, 0 };
int eg = simple_is_endgame(pos); eval_t mg_eval[2], eg_eval[2];
int (*gg)[6 + 2][64]= eg? eg_table: mg_table; //struct pc_sq = sq_ int (*gg)[6 + 2][64] = eg? pc_sq_eg: pc_sq_mg;
pos->eval_simple_phase = ENDGAME; //pos->eval_simple_phase = ENDGAME;
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(5, "phase = %s.\n", eg? "endgame": "midgame"); log_f(5, "phase = %d\n", eg? "endgame": "midgame");
# endif # endif
for (int color = WHITE; color <= BLACK; ++color) { for (color_t color = WHITE; color < COLOR_NB; ++color) {
for (uint piece = PAWN; piece <= KING; piece <<= 1) { mg_eval[color] = 0;
int bb = PIECETOBB(piece), cur; eg_eval[color] = 0;
u64 _t; for (piece_type_t pt = PAWN; pt < KING; pt++) {
bitboard_t bb = pos->bb[color][pt];
# ifdef DEBUG_EVAL while (bb) {
log_f(5, "p=%u bb=%d %s %s: count=%d val=%ld ", piece, bb, color? "black": "white", square_t sq = bb_next(&bb);
P_SYM(piece), popcount64(pos->bb[color][bb]), mg_eval[color] += pc_sq_mg[color][pt][sq];
popcount64(pos->bb[color][bb]) * P_VALUE(piece)); eg_eval[color] += pc_sq_eg[color][pt][sq];
# endif
eval[color] += popcount64(pos->bb[color][bb]) * P_LETTER(piece);
bit_for_each64(cur, _t, pos->bb[color][bb]) {
# ifdef DEBUG_EVAL
log(5, "sq=%d:%d ", cur, gg[color][bb][cur]);
# endif
eval[color] += gg[color][bb][cur];
} }
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log(5, "\n"); printf("c=%d p=%d mg=%ld eg=%ld\n", color, pt,
popcount64(pos->bb[color][pt]),
mg_eval[color], eg_eval[color]);
# endif # endif
} }
} }
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(2, "eval:%d white:%d black:%d\n", eval[WHITE] - eval[BLACK], printf("phase:%d mg[WHITE]:%d mg[BLACK]:%d eg[WHITE]:%d eg[BLACK]:%d\n",
eval[WHITE], eval[BLACK]); mg_eval[WHITE], mg_eval[BLACK], eg_eval[WHITE], eg_eval[BLACK]);
# endif # endif
return eval[WHITE] - eval[BLACK]; return eval[WHITE] - eval[BLACK];

View File

@@ -1,6 +1,6 @@
/* eval-simple.h - simple position evaluation. /* eval-simple.h - simple position evaluation.
* *
* Copyright (C) 2021 Bruno Raoult ("br") * Copyright (C) 2021-2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later. * Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING. * Some rights reserved. See COPYING.
* *
@@ -16,19 +16,35 @@
#include "chessdefs.h" #include "chessdefs.h"
#include "piece.h"
struct pc_sq {
char *name; /* one word only, no spaces */
int val[PIECE_TYPE_NB][PHASE_NB][SQUARE_NB]; /* MG then EG */
};
/**
* pc_sq - pre-defined piece-square tables.
*/
extern const struct pc_sq pc_sq_def[];
extern const int nb_pc_sq; /* # of pc_sq_def */
extern int pc_sq_current;
extern int pc_sq_mg[COLOR_NB][PT_NB][SQUARE_NB];
extern int pc_sq_eg[COLOR_NB][PT_NB][SQUARE_NB];
/* no queen on board */ /* no queen on board */
#define simple_no_queen(p, c) \ #define simple_no_queen(p, c) \
( !(p)->bb[c][BB_QUEEN] ) ( !(p)->bb[c][QUEEN] )
#define simple_one_queen(p, c) \ #define simple_one_queen(p, c) \
( popcount64((p)->bb[c][BB_QUEEN]) == 1 ) ( popcount64((p)->bb[c][QUEEN]) == 1 )
#define simple_no_rook(p, c) \ #define simple_no_rook(p, c) \
(!(p)->bb[c][BB_ROOK]) (!(p)->bb[c][ROOK])
#define simple_one_minor_piece(p, c) \ #define simple_one_minor_piece(p, c) \
(popcount64((p)->bb[c][BB_KNIGHT] | (p)->bb[c][BB_BISHOP]) == 1) (popcount64((p)->bb[c][KNIGHT] | (p)->bb[c][BISHOP]) == 1)
#define simple_is_endgame(p) \ #define simple_is_endgame(p) \
( (simple_no_queen(p, WHITE) || \ ( (simple_no_queen(p, WHITE) || \
@@ -41,6 +57,9 @@
simple_no_rook(p, BLACK) && \ simple_no_rook(p, BLACK) && \
simple_one_minor_piece(p, BLACK))) ) simple_one_minor_piece(p, BLACK))) )
int calc_phase(pos_t *pos);
int eval_simple_find(char *str);
void eval_simple_set(int set);
void eval_simple_init(void); void eval_simple_init(void);
eval_t eval_simple(pos_t *pos); eval_t eval_simple(pos_t *pos);

View File

@@ -1,6 +1,6 @@
/* eval.c - static position evaluation. /* eval.c - static position evaluation.
* *
* Copyright (C) 2021-2023 Bruno Raoult ("br") * Copyright (C) 2021-2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later. * Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING. * Some rights reserved. See COPYING.
* *
@@ -13,9 +13,9 @@
#include <stdio.h> #include <stdio.h>
#include <list.h> #include <brlib.h>
#include <debug.h>
#include "chessdefs.h"
#include "position.h" #include "position.h"
#include "eval.h" #include "eval.h"
#include "eval-simple.h" #include "eval-simple.h"
@@ -27,35 +27,39 @@ inline eval_t eval_material(pos_t *pos, bool color)
/* I need to do something about the king, if it can be potentially taken /* I need to do something about the king, if it can be potentially taken
* if pseudo-moves include a pinned piece on King. * if pseudo-moves include a pinned piece on King.
*/ */
for (uint piece = PAWN; piece < KING; piece <<= 1) { for (piece_type_t pt = PAWN; pt < KING; ++pt) {
uint bb = PIECETOBB(piece);
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(2, "color=%u piece=%u bb=%u=%c count=%ul val=%ld\n", log_f(2, "color=%u piece=%u bb=%u=%c count=%ul val=%ld\n",
color, piece, bb, P_LETTER(piece), popcount64(pos->bb[color][bb]), color, piece, bb, P_LETTER(piece), popcount64(pos->bb[color][bb]),
P_VALUE(piece)); P_VALUE(piece));
# endif # endif
/* attention here */ res += popcount64(pos->bb[color][pt]) * piece_val(pt);
res += popcount64(pos->bb[color][bb]) * P_VALUE(piece);
} }
return res; return res;
} }
inline eval_t eval_mobility(pos_t *pos, bool color)
{
return pos->mobility[color];
}
inline eval_t eval_square_control(pos_t *pos, bool color)
{ /*
return popcount64(pos->controlled[color]); * inline eval_t eval_mobility(pos_t *pos, bool color)
} * {
* return pos->mobility[color];
* }
*
*
* inline eval_t eval_square_control(pos_t *pos, bool color)
* {
* return popcount64(pos->controlled[color]);
* }
*/
eval_t eval(pos_t *pos) eval_t eval(pos_t *pos)
{ {
eval_t simple = 0, control[2] = {0}; //eval_t simple = 0, control[2] = {0};
eval_t simple = 0;
if (pos->eval != EVAL_INVALID) //if (pos->eval != EVAL_INVALID)
return pos->eval; // return pos->eval;
/* 1) pieces value */ /* 1) pieces value */
//material[WHITE] = eval_material(pos, WHITE); //material[WHITE] = eval_material(pos, WHITE);
@@ -67,8 +71,8 @@ eval_t eval(pos_t *pos)
# endif # endif
/* 2) square control: 10 square controls diff = 1 pawn */ /* 2) square control: 10 square controls diff = 1 pawn */
control[WHITE] = eval_square_control(pos, WHITE); //control[WHITE] = eval_square_control(pos, WHITE);
control[BLACK] = eval_square_control(pos, BLACK); //control[BLACK] = eval_square_control(pos, BLACK);
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(2, "square control: W:%d B:%d diff=%d\n", log_f(2, "square control: W:%d B:%d diff=%d\n",
@@ -84,12 +88,12 @@ eval_t eval(pos_t *pos)
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10); (pos->mobility[WHITE] - pos->mobility[BLACK]) * 10);
# endif # endif
eval_t res = simple + //eval_t res = simple +
(control[WHITE] - control[BLACK]) * 10 + // (control[WHITE] - control[BLACK]) * 10 +
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10; // (pos->mobility[WHITE] - pos->mobility[BLACK]) * 10;
# ifdef DEBUG_EVAL # ifdef DEBUG_EVAL
log_f(2, "eval: %d\n", res); log_f(2, "eval: %d\n", res);
# endif # endif
pos->eval = res; pos->eval = simple;
return res; return simple;
} }

View File

@@ -17,16 +17,16 @@
#include <limits.h> #include <limits.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "piece.h"
/* max pieces eval is KING_VALUE + 9*QUEEN_VALUE + 2*ROOK_VALUE + 2*BISHOP_VALUE /* max pieces eval is 9*QUEEN_VALUE + 2*ROOK_VALUE + 2*BISHOP_VALUE
* + 2*KNIGHT_VALUE which around 30000. * + 2*KNIGHT_VALUE which is (for a pawn valued at 100) well less than 10,000.
* We are on secure side with -50000/+50000
*/ */
#define EVAL_MAX (50000) #define EVAL_MAX (SHRT_MAX) /* 32767 */
#define EVAL_MIN (-EVAL_MAX) #define EVAL_MIN (-EVAL_MAX)
#define EVAL_INVALID INT_MIN
#define EVAL_MATE EVAL_MAX #define EVAL_INVALID EVAL_MIN
#define EVAL_MATE 30000
eval_t eval_material(pos_t *pos, bool color); eval_t eval_material(pos_t *pos, bool color);
eval_t eval_mobility(pos_t *pos, bool color); eval_t eval_mobility(pos_t *pos, bool color);

View File

@@ -21,9 +21,7 @@
#include <bug.h> #include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "util.h" #include "alloc.h"
//#include "piece.h"
//#include "bitboard.h"
#include "position.h" #include "position.h"
#include "fen.h" #include "fen.h"
@@ -290,11 +288,11 @@ char *pos2fen(const pos_t *pos, char *fen)
int cur = 0; int cur = 0;
if (!fen) if (!fen)
fen = safe_malloc(92); fen = safe_alloc(92);
/* 1) position /* 1) position
*/ */
for (rank_t r = RANK_8; r >= RANK_1; --r) { for (rank_t r = RANK_8 + 1; r --> RANK_1;) {
for (file_t f = FILE_A; f <= FILE_H;) { for (file_t f = FILE_A; f <= FILE_H;) {
square_t sq = sq_make(f, r); square_t sq = sq_make(f, r);
piece_t piece = pos->board[sq]; piece_t piece = pos->board[sq];

View File

@@ -16,9 +16,10 @@
#include <brlib.h> #include <brlib.h>
#include <bitops.h> #include <bitops.h>
#include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "util.h" #include "alloc.h"
#include "position.h" #include "position.h"
#include "piece.h" #include "piece.h"
#include "hash.h" #include "hash.h"
@@ -101,13 +102,6 @@ hkey_t zobrist_calc(pos_t *pos)
*/ */
#ifdef ZOBRIST_VERIFY #ifdef ZOBRIST_VERIFY
#pragma push_macro("BUG_ON") /* force BUG_ON and WARN_ON */
#pragma push_macro("WARN_ON")
#undef BUG_ON
#define BUG_ON
#undef WARN_ON
#define WARN_ON
bool zobrist_verify(pos_t *pos) bool zobrist_verify(pos_t *pos)
{ {
hkey_t diff, key = zobrist_calc(pos); hkey_t diff, key = zobrist_calc(pos);
@@ -147,12 +141,10 @@ bool zobrist_verify(pos_t *pos)
} }
warn(true, "zobrist diff %lx is unknown\n", diff); warn(true, "zobrist diff %lx is unknown\n", diff);
end: end:
bug_on(false); bug_on_always(false);
/* not reached */ /* not reached */
return true; return true;
} }
#pragma pop_macro("WARN_ON")
#pragma pop_macro("BUG_ON")
#endif #endif
@@ -191,7 +183,6 @@ int tt_create(s32 sizemb)
if (sizemb <= 0) if (sizemb <= 0)
sizemb = HASH_SIZE_DEFAULT; sizemb = HASH_SIZE_DEFAULT;
sizemb = clamp(sizemb, HASH_SIZE_MIN, HASH_SIZE_MAX); sizemb = clamp(sizemb, HASH_SIZE_MIN, HASH_SIZE_MAX);
//printf("-> %'6d ", sizemb);
bytes = sizemb * 1024ull * 1024ull; /* bytes wanted */ bytes = sizemb * 1024ull * 1024ull; /* bytes wanted */
target_nbuckets = bytes / sizeof(bucket_t); /* target buckets */ target_nbuckets = bytes / sizeof(bucket_t); /* target buckets */
@@ -199,7 +190,7 @@ int tt_create(s32 sizemb)
nbits = msb64(target_nbuckets); /* adjust to power of 2 */ nbits = msb64(target_nbuckets); /* adjust to power of 2 */
if (hash_tt.nbits != nbits) { if (hash_tt.nbits != nbits) {
if (hash_tt.nbits) if (hash_tt.keys)
tt_delete(); tt_delete();
hash_tt.nbits = nbits; hash_tt.nbits = nbits;
@@ -212,7 +203,7 @@ int tt_create(s32 sizemb)
hash_tt.mask = -1ull >> (64 - nbits); hash_tt.mask = -1ull >> (64 - nbits);
hash_tt.keys = safe_malloc(hash_tt.bytes); hash_tt.keys = safe_alloc_aligned_hugepage(hash_tt.bytes);
//printf("bits=%2d size=%'15lu/%'6d Mb/%'14lu buckets ", //printf("bits=%2d size=%'15lu/%'6d Mb/%'14lu buckets ",
// hash_tt.nbits, hash_tt.bytes, hash_tt.mb, hash_tt.nbuckets); // hash_tt.nbits, hash_tt.bytes, hash_tt.mb, hash_tt.nbuckets);

View File

@@ -14,14 +14,16 @@
#ifndef HASH_H #ifndef HASH_H
#define HASH_H #define HASH_H
#include <brlib.h>
#include <bug.h> #include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "move.h"
#define ENTRIES_PER_BUCKET 4 /* buckets per hash table entry */ #define ENTRIES_PER_BUCKET 4 /* buckets per hash table entry */
#define HASH_SIZE_DEFAULT 32 /* default: 32Mb */ #define HASH_SIZE_DEFAULT 16 /* default: 16Mb */
#define HASH_SIZE_MIN 4 #define HASH_SIZE_MIN 1
#define HASH_SIZE_MAX 32768 /* 32Gb */ #define HASH_SIZE_MAX 32768 /* 32Gb */
#define TT_MISS NULL #define TT_MISS NULL
@@ -30,6 +32,11 @@
typedef u64 hkey_t; /* cannot use typedef for key_t */ typedef u64 hkey_t; /* cannot use typedef for key_t */
/**
* hash_short: get the most significant 7 nibble of a 64 bits value.
*/
#define hash_short(hash) ((hash) >> (64 - 4 * 7))
/** /**
* hentry_t: hashtable bucket. * hentry_t: hashtable bucket.
* *
@@ -43,9 +50,9 @@ typedef struct {
struct { struct {
u16 depth; /* ply in search */ u16 depth; /* ply in search */
s16 eval; s16 eval;
u16 move; move_t move;
u8 flags; /* maybe for locking, etc... */ //u8 flags; /* maybe for locking, etc... */
u8 filler; //u8 filler;
}; };
}; };
} hentry_t; } hentry_t;

165
src/hist.c Normal file
View File

@@ -0,0 +1,165 @@
/* hist.c - history management.
*
* 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 <brlib.h>
#include <bug.h>
#include "position.h"
#include "hash.h"
#include "move.h"
#include "hist.h"
hist_t hist = {
.nstates = 1,
{ { .move = MOVE_NONE, .key = U64(0), .prev = &hist.state[0] } },
};
/**
* hist_init() - initialize history states data.
*
* This should be done every time a new position must be handled.
*/
void hist_init(void)
{
hist.nstates = 1;
hist.state[0].key = U64(0);
hist.state[0].move = MOVE_NONE;
hist.state[0].prev = &hist.state[0];
}
/**
* hist_push() - add a state to hist list
* @st: &state_t to add
*
* Used to add moves when the UCI "position" command includes moves.
* These moves, but last one, should be pushed. Last move should be
* linked to hist with @hist_link().
*/
void hist_push(state_t *st) //, move_t *move)
{
int last = hist.nstates++;
bug_on(last >= HIST_SIZE);
hist.state[last] = *st;
hist.state[last].prev = &hist.state[last - 1];
// hist.state[last].move = *move;
}
/**
* hist_link() - link a position to last hist element.
* @pos: &pos_t to link
*
* Used to add position resulting from last "move" in UCI "position" command.
* All other moves in UCI "position" command should be pushed instead, with
* hist_push().
*/
void hist_link(pos_t *pos)
{
pos->prev = hist_last();
}
/**
* hist_pop() - return last state from hist entry, and remove it from list
*
* Not used, only for debug.
*/
state_t *hist_pop(void)
{
if (hist.nstates > 1)
hist.nstates--;
return hist_last();
}
/**
* hist_last() - return last state from hist.
*/
state_t *hist_last(void)
{
return hist.state + hist.nstates - 1;
}
/**
* hist_prev() - return a state's ancestor.
* @st: &state_t state
*
* No test is done on ancestor. Caller should check it is different
* from HIST_START.
*/
state_t *hist_prev(state_t *st)
{
return st->prev;
}
/**
* hist_prev2() - return a state's second ancestor.
* @st: &state_t state
*
* No test is done on ancestors. Caller should check it is different
* from HIST_START.
*/
state_t *hist_prev2(state_t *st)
{
return st->prev->prev;
}
/**
* hist_prev4() - return a state's 4th ancestor.
* @st: &state_t state
*
* No test is done on ancestors. Caller should check it is different
* from HIST_START.
*/
state_t *hist_prev4(state_t *st)
{
return st->prev->prev->prev->prev;
}
/**
* hist_static_print() - print hist entries
*/
void hist_static_print(void)
{
char movestr[8];
state_t *st = hist_last();
printf("UCI state history: ");
while (true) {
printf("%s(#%lx) ",
move_to_str(movestr, st->move, 0),
hash_short(st->key));
if (st == HIST_START)
break;
st = hist_prev(st);
}
printf("\n");
}
/**
* hist_print() - print position history
* @pos: &pos to start from
*/
void hist_print(pos_t *pos)
{
char movestr[8];
state_t *st = &pos->state;
printf("position states history: ");
while (true) {
printf("%s(#%lx) ",
move_to_str(movestr, st->move, 0),
hash_short(st->key));
if (st == HIST_START)
break;
st = hist_prev(st);
}
printf("\n");
}

61
src/hist.h Normal file
View File

@@ -0,0 +1,61 @@
/* hist.h - history management.
*
* 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>
*
*/
#ifndef HIST_H
#define HIST_H
#include <brlib.h>
#include <bug.h>
#include "position.h"
#include "hash.h"
#define HIST_SIZE 4096 /* I know, I know... */
/**
* hist - history states data.
*
* This variable is of type hist_t, which contains:
* @state: state_t array, size HIST_SIZE
* @nstates: current number of @state
*
* hist contains moves already played.
*
* Only HIST_SIZE - 1 hist elements are available, as the first element is
* used as a sentinel value (hist[0].state.prev = &hist[0].state).
* This first element allows multiple backards searches (p->prev->prev).
*
* hist is only written by main thread, and read by other threads/processes,
* therefore is never duplicated (even after a fork(), due to COW).
*/
typedef struct {
int nstates;
state_t state[HIST_SIZE];
} hist_t;
extern hist_t hist;
#define HIST_START (hist.state)
void hist_init(void);
void hist_push(state_t *st); //, move_t *move);
void hist_link(pos_t *pos);
state_t *hist_pop(void);
state_t *hist_last(void);
state_t *hist_prev(state_t *st);
state_t *hist_prev2(state_t *st);
state_t *hist_prev4(state_t *st);
void hist_static_print(void);
void hist_print(pos_t *pos);
#endif /* HIST_H */

View File

@@ -1,4 +1,4 @@
/* hyperbola-quintessence.c - hyperbola quintessence functions. /* hq.c - hyperbola quintessence functions.
* *
* Copyright (C) 2024 Bruno Raoult ("br") * Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later. * Licensed under the GNU General Public License v3.0 or later.
@@ -14,18 +14,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include "brlib.h" #include <brlib.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "board.h" #include "board.h"
#include "bitboard.h" #include "bitboard.h"
#include "hyperbola-quintessence.h" #include "hq.h"
uchar bb_rank_attacks[64 * 8]; uchar bb_rank_attacks[64 * 8];
/** /**
* hyperbola_init() - init hyperbola quintessence attack bitboards * hq_init() - init hyperbola quintessence attack bitboards
* *
* See: https://www.chessprogramming.org/Kindergarten_Bitboards * See: https://www.chessprogramming.org/Kindergarten_Bitboards
* and https://www.chessprogramming.org/Hyperbola_Quintessence * and https://www.chessprogramming.org/Hyperbola_Quintessence
@@ -45,18 +45,17 @@ uchar bb_rank_attacks[64 * 8];
* (O <<= 2) * (O <<= 2)
* *
* TODO ? create masks excluding slider (eg. bb_diag ^ bb_sq[square]), * TODO ? create masks excluding slider (eg. bb_diag ^ bb_sq[square]),
* to save one operation in hyperbola_moves(). * to save one operation in hq_moves().
* TODO ? replace rank attack with this idea, mapping rank to diagonal ? * TODO ? replace rank attack with this idea, mapping rank to diagonal ?
* See http://timcooijmans.blogspot.com/2014/04/ * See http://timcooijmans.blogspot.com/2014/04/
*/ */
void hyperbola_init() void hq_init()
{ {
/* generate rank attacks, not handled by HQ /* generate rank attacks, not handled by HQ
*/ */
for (int occ = 0; occ < 64; ++occ) { for (int occ = 0; occ < 64; ++occ) {
for (int file = 0; file < 8; ++file) { for (int file = 0; file < 8; ++file) {
int attacks = 0; int attacks = 0;
//int o = mask << 1; /* skip right square */
/* set f left attacks */ /* set f left attacks */
for (int slide = file - 1; slide >= 0; --slide) { for (int slide = file - 1; slide >= 0; --slide) {
@@ -70,23 +69,15 @@ void hyperbola_init()
int b = bb_sq[slide]; int b = bb_sq[slide];
attacks |= b; attacks |= b;
if ((occ << 1) & b) /* piece on b, we stop */ if ((occ << 1) & b) /* piece on b, we stop */
//if ((o & b) == b)
break; break;
} }
bb_rank_attacks[(occ << 3) + file] = attacks; bb_rank_attacks[(occ << 3) + file] = attacks;
//if (((occ << 3) + file) == 171) {
//char str[64], str2[64];
//printf("mask=%x=%s file=%d att=%x=%s\n",
// occ, bitboard_rank_sprint(str, occ), file,
// attacks, bitboard_rank_sprint(str2, attacks));
//}
} }
} }
} }
/** /**
* hyperbola_rank_moves() - get rank moves for a sliding piece. * hq_rank_moves() - get rank moves for a sliding piece.
* @pieces: occupation bitboard * @pieces: occupation bitboard
* @sq: piece square * @sq: piece square
* *
@@ -95,22 +86,16 @@ void hyperbola_init()
* *
* @Return: bitboard of @piece available pseudo-moves. * @Return: bitboard of @piece available pseudo-moves.
*/ */
bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq) bitboard_t hq_rank_moves(bitboard_t occ, square_t sq)
{ {
u32 rank = sq & SQ_RANKMASK; u32 rank = sq & SQ_RANKMASK;
u32 file = sq & SQ_FILEMASK; u32 file = sq & SQ_FILEMASK;
u64 o = (occ >> rank) & 0176; /* 01111110 clear bits 0 & 7 */ u64 o = (occ >> rank) & 0176; /* 01111110 clear bits 0 & 7 */
//char zob[128], zob2[128];
//printf("rank_moves: occ=%lx=%s file=%d o=%lx=%s index=%ld=%ld attack=%lx=%s\n", occ,
// bitboard_rank_sprint(zob, occ), file, o,
// bitboard_rank_sprint(zob, o), (o << 2) + file, (o * 4) + file,
// (bitboard_t)bb_rank_attacks[(o << 2) + file] << rank,
// bitboard_rank_sprint(zob2, (bitboard_t)bb_rank_attacks[(o << 2) + file] << rank));
return ((bitboard_t)bb_rank_attacks[(o << 2) + file]) << rank; return ((bitboard_t)bb_rank_attacks[(o << 2) + file]) << rank;
} }
/** /**
* hyperbola_moves() - get hyperbola pseudo-moves for a sliding piece * hq_moves() - get hyperbola pseudo-moves for a sliding piece
* @pieces: occupation bitboard * @pieces: occupation bitboard
* @sq: piece square * @sq: piece square
* @mask: the appropriate mask (pre-calculated) * @mask: the appropriate mask (pre-calculated)
@@ -122,7 +107,7 @@ bitboard_t hyperbola_rank_moves(bitboard_t occ, square_t sq)
* *
* @Return: bitboard of piece available pseudo-moves. * @Return: bitboard of piece available pseudo-moves.
*/ */
bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq, bitboard_t hq_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask) const bitboard_t mask)
{ {
bitboard_t o = pieces & mask; bitboard_t o = pieces & mask;
@@ -135,67 +120,67 @@ bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
} }
/** /**
* hyperbola_file_moves() - get file pseudo-moves for a sliding piece. * hq_file_moves() - get file pseudo-moves for a sliding piece.
* @pieces: occupation bitboard * @pieces: occupation bitboard
* @sq: piece square * @sq: piece square
* *
* @Return: bitboard of piece available pseudo-moves on its file. * @Return: bitboard of piece available pseudo-moves on its file.
*/ */
bitboard_t hyperbola_file_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_file_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_moves(occ, sq, bb_sqfile[sq]); return hq_moves(occ, sq, bb_sqfile[sq]);
} }
/** /**
* hyperbola_diag_moves() - get diagonal pseudo-moves for a sliding piece. * hq_diag_moves() - get diagonal pseudo-moves for a sliding piece.
* @pieces: occupation bitboard * @pieces: occupation bitboard
* @sq: piece square * @sq: piece square
* *
* @Return: bitboard of piece available pseudo-moves on its diagonal. * @Return: bitboard of piece available pseudo-moves on its diagonal.
*/ */
bitboard_t hyperbola_diag_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_diag_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_moves(occ, sq, bb_sqdiag[sq]); return hq_moves(occ, sq, bb_sqdiag[sq]);
} }
/** /**
* hyperbola_anti_moves() - get anti-diagonal pseudo-moves for a sliding piece. * hq_anti_moves() - get anti-diagonal pseudo-moves for a sliding piece.
* @pieces: occupation bitboard * @pieces: occupation bitboard
* @sq: piece square * @sq: piece square
* *
* @Return: bitboard of piece available pseudo-moves on its anti-diagonal. * @Return: bitboard of piece available pseudo-moves on its anti-diagonal.
*/ */
bitboard_t hyperbola_anti_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_anti_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_moves(occ, sq, bb_sqanti[sq]); return hq_moves(occ, sq, bb_sqanti[sq]);
} }
/** /**
* hyperbola_bishop_moves() - get bitboard of bishop pseudo-moves * hq_bishop_moves() - get bitboard of bishop pseudo-moves
* @occ: occupation bitboard * @occ: occupation bitboard
* @sq: bishop square * @sq: bishop square
* *
* @Return: bitboard of bishop available pseudo-moves. * @Return: bitboard of bishop available pseudo-moves.
*/ */
bitboard_t hyperbola_bishop_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_bishop_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_diag_moves(occ, sq) | hyperbola_anti_moves(occ, sq); return hq_diag_moves(occ, sq) | hq_anti_moves(occ, sq);
} }
/** /**
* hyperbola_rook_moves() - get bitboard of rook pseudo-moves * hq_rook_moves() - get bitboard of rook pseudo-moves
* @occ: occupation bitboard * @occ: occupation bitboard
* @sq: rook square * @sq: rook square
* *
* @Return: bitboard of rook available pseudo-moves. * @Return: bitboard of rook available pseudo-moves.
*/ */
bitboard_t hyperbola_rook_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_rook_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_file_moves(occ, sq) | hyperbola_rank_moves(occ, sq); return hq_file_moves(occ, sq) | hq_rank_moves(occ, sq);
} }
/** /**
* hyperbola_queen_moves() - get bitboard of queen pseudo-moves * hq_queen_moves() - get bitboard of queen pseudo-moves
* @occ: occupation bitboard * @occ: occupation bitboard
* @sq: queen square * @sq: queen square
* *
@@ -204,7 +189,7 @@ bitboard_t hyperbola_rook_moves(const bitboard_t occ, const square_t sq)
* *
* @Return: bitboard of queen available pseudo-moves. * @Return: bitboard of queen available pseudo-moves.
*/ */
bitboard_t hyperbola_queen_moves(const bitboard_t occ, const square_t sq) bitboard_t hq_queen_moves(const bitboard_t occ, const square_t sq)
{ {
return hyperbola_bishop_moves(occ, sq) | hyperbola_rook_moves(occ, sq); return hq_bishop_moves(occ, sq) | hq_rook_moves(occ, sq);
} }

33
src/hq.h Normal file
View File

@@ -0,0 +1,33 @@
/* hq.h - hyperbola-quintessence definitions.
*
* 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>
*
*/
#ifndef _HQ_H
#define _HQ_H
#include "board.h"
#include "bitboard.h"
void hq_init(void);
bitboard_t hq_rank_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask);
bitboard_t hq_file_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_diag_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_anti_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_bishop_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_rook_moves(const bitboard_t occ, const square_t sq);
bitboard_t hq_queen_moves(const bitboard_t occ, const square_t sq);
#endif /* _HQ_H */

View File

@@ -1,33 +0,0 @@
/* hyperbola-quintessence.h - hyperbola-quintessence definitions.
*
* 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>
*
*/
#ifndef _HYPERBOLA_QUINTESSENCE_H
#define _HYPERBOLA_QUINTESSENCE_H
#include "board.h"
#include "bitboard.h"
void hyperbola_init(void);
bitboard_t hyperbola_rank_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_moves(const bitboard_t pieces, const square_t sq,
const bitboard_t mask);
bitboard_t hyperbola_file_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_diag_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_anti_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_bishop_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_rook_moves(const bitboard_t occ, const square_t sq);
bitboard_t hyperbola_queen_moves(const bitboard_t occ, const square_t sq);
#endif /* _HYPERBOLA_QUINTESSENCE_H */

View File

@@ -12,31 +12,49 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <locale.h> #include <locale.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "bitboard.h" #include "bitboard.h"
#include "hyperbola-quintessence.h" #include "hq.h"
#include "eval-simple.h"
#include "hash.h" #include "hash.h"
#include "hist.h"
#define printff(x) ({ printf(x); fflush(stdout); })
void init_all(void) void init_all(void)
{ {
/* for printf() numeric thousands separator */
setlocale(LC_NUMERIC, "");
/* line-buffered stdout */ /* line-buffered stdout */
printff("initiazing stdout buffering... ");
setlinebuf(stdout); setlinebuf(stdout);
/* for printf() numeric thousands separator */
printff("locale... ");
setlocale(LC_NUMERIC, "");
/* pseudo random generator seed */ /* pseudo random generator seed */
printff("random generator... ");
rand_init(RAND_SEED_DEFAULT); rand_init(RAND_SEED_DEFAULT);
/* bitboards & hq */ /* bitboards & hq */
printff("bitboards... ");
bitboard_init(); bitboard_init();
hyperbola_init();
printff("hq bitboards... ");
hq_init();
/* zobrist tables & default tt hashtable */ /* zobrist tables & default tt hashtable */
printff("zobrist tables... ");
zobrist_init(); zobrist_init();
printff("transposition tables... ");
tt_create(HASH_SIZE_DEFAULT); tt_create(HASH_SIZE_DEFAULT);
/* eval tables */
printf("eval data... ");
eval_simple_init();
printf("done.\n");
} }

View File

@@ -1,4 +1,4 @@
/* util.c - various util functions. /* util.h - various util functions.
* *
* Copyright (C) 2024 Bruno Raoult ("br") * Copyright (C) 2024 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later. * Licensed under the GNU General Public License v3.0 or later.
@@ -11,8 +11,8 @@
* *
*/ */
#include <stdio.h> #ifndef _UTIL_H
#include <stdlib.h> #define _UTIL_H
#include "util.h"
#include "bitboard.h" #endif /* UTIL_H */

View File

@@ -15,9 +15,9 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include "brlib.h" #include <brlib.h>
#include "likely.h" #include <likely.h>
#include "bug.h" #include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "move.h" #include "move.h"
@@ -70,6 +70,7 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state)
pos->en_passant = SQUARE_NONE; pos->en_passant = SQUARE_NONE;
pos->turn = them; pos->turn = them;
pos->captured = captured; pos->captured = captured;
pos->move = move;
bug_on(COLOR(piece) != us); bug_on(COLOR(piece) != us);
@@ -80,13 +81,12 @@ pos_t *move_do(pos_t *pos, const move_t move, state_t *state)
if (captured != EMPTY) { if (captured != EMPTY) {
pos->clock_50 = 0; pos->clock_50 = 0;
//pos->captured = pos->board[to]; /* save capture info */
bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them); bug_on(pos->board[to] == EMPTY || COLOR(pos->captured) != them);
key ^= zobrist_pieces[captured][to]; key ^= zobrist_pieces[captured][to];
pos_clr_sq(pos, to); /* clear square */ pos_clr_sq(pos, to); /* clear square */
} else if (is_castle(move)) { /* handle rook move */ } else if (is_castle(move)) { /* handle rook move */
square_t rookfrom, rookto; square_t rookfrom, rookto;
if (is_castle_K(move)) { if (to > from) {
rookfrom = sq_rel(H1, us); rookfrom = sq_rel(H1, us);
rookto = sq_rel(F1, us); rookto = sq_rel(F1, us);
} else { } else {
@@ -193,7 +193,7 @@ pos_t *move_undo(pos_t *pos, const move_t move, const state_t *state)
pos_set_sq(pos, to, pos->captured); /* restore captured piece */ pos_set_sq(pos, to, pos->captured); /* restore captured piece */
} else if (is_castle(move)) { /* make reverse rook move */ } else if (is_castle(move)) { /* make reverse rook move */
square_t rookfrom, rookto; square_t rookfrom, rookto;
if (is_castle_K(move)) { if (to > from) {
rookfrom = sq_rel(F1, us); rookfrom = sq_rel(F1, us);
rookto = sq_rel(H1, us); rookto = sq_rel(H1, us);
} else { } else {
@@ -238,6 +238,7 @@ pos_t *move_do_alt(pos_t *pos, const move_t move, state_t *state)
pos->en_passant = SQUARE_NONE; pos->en_passant = SQUARE_NONE;
pos->turn = them; pos->turn = them;
pos->captured = captured; pos->captured = captured;
pos->move = move;
bug_on(COLOR(piece) != us); bug_on(COLOR(piece) != us);
@@ -254,7 +255,7 @@ pos_t *move_do_alt(pos_t *pos, const move_t move, state_t *state)
pos_clr_sq(pos, to); /* clear square */ pos_clr_sq(pos, to); /* clear square */
} else if (is_castle(move)) { /* handle rook move */ } else if (is_castle(move)) { /* handle rook move */
square_t rookfrom, rookto; square_t rookfrom, rookto;
if (is_castle_K(move)) { if (to > from) {
rookfrom = sq_rel(H1, us); rookfrom = sq_rel(H1, us);
rookto = sq_rel(F1, us); rookto = sq_rel(F1, us);
} else { } else {
@@ -344,7 +345,7 @@ pos_t *move_undo_alt(pos_t *pos, const move_t move, const state_t *state)
pos_set_sq(pos, to, pos->captured); /* restore captured piece */ pos_set_sq(pos, to, pos->captured); /* restore captured piece */
} else if (is_castle(move)) { /* make reverse rook move */ } else if (is_castle(move)) { /* make reverse rook move */
square_t rookfrom, rookto; square_t rookfrom, rookto;
if (is_castle_K(move)) { if (to > from) {
rookfrom = sq_rel(F1, us); rookfrom = sq_rel(F1, us);
rookto = sq_rel(H1, us); rookto = sq_rel(H1, us);
} else { } else {

View File

@@ -22,11 +22,10 @@
#include "piece.h" #include "piece.h"
#include "position.h" #include "position.h"
#include "move.h" #include "move.h"
#include "hyperbola-quintessence.h" #include "hq.h"
#include "attack.h" #include "attack.h"
#include "move-gen.h" #include "move-gen.h"
/** /**
* pseudo_is_legal() - check if a move is legal. * pseudo_is_legal() - check if a move is legal.
* @pos: position * @pos: position
@@ -36,74 +35,71 @@
*/ */
bool pseudo_is_legal(const pos_t *pos, const move_t move) bool pseudo_is_legal(const pos_t *pos, const move_t move)
{ {
color_t us = pos->turn, them = OPPONENT(us); color_t us = pos->turn;
square_t from = move_from(move), to = move_to(move); color_t them = OPPONENT(us);
square_t king = pos->king[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 kingbb = pos->bb[us][KING];
bitboard_t occ = pos_occ(pos); bitboard_t occ = pos_occ(pos);
u64 pinned = BIT(from) & pos->blockers; u64 pinned = BIT(from) & pos->blockers;
u64 checkers = pos->checkers; u64 checkers = pos->checkers;
bug_on(pos->board[from] == NO_PIECE || COLOR(pos->board[from]) != us);
/* (1) - Castling & King /* (1) - Castling & King
* For castling, we need to check intermediate squares attacks only. * For castling, we need to check intermediate squares attacks only.
* Attention: To test if K is in check after moving, we need to exclude * Attention: To test if K is in check after moving, we need to exclude
* king from occupation bitboard (to catch king moving away from checker * king from occupation bitboard (to catch king moving away from checker
* on same line) ! * on same line) !
*/ */
if (unlikely(from == king)) { if (is_castle(move)) {
if (unlikely(is_castle(move))) { int dir = to > from? 1: -1;
square_t dir = to > from? 1: -1;
if (sq_is_attacked(pos, occ, from + dir, them)) if (sq_is_attacked(pos, occ, from + dir, them))
return false; return false;
} }
if (from == kingsq) {
return !sq_is_attacked(pos, occ ^ kingbb, to, them); return !sq_is_attacked(pos, occ ^ kingbb, to, them);
} }
/* (2) - King is in check /* (2) - King is in check
* Double-check is already handled in (1), as only K moves were generated * Double-check is already handled in (1), as only K moves were generated
* by pseudo legal move generator. * by pseudo legal move generator.
* Here, allowed dest squares are only on King-checker line, or on checker * Special cases (illegal):
* square. * - e.p., if the grabbed pawn is *not* giving check
* attacker. * - piece is pinned
* Special cases:
* e.p., legal if the grabbed pawn is giving check
* pinned piece: always illegal
*/ */
if (checkers) { if (checkers) {
if (pinned) if (pinned)
return false; return false;
if (bb_multiple(checkers))
return false;
square_t checker = ctz64(checkers);
if (is_enpassant(move)) { if (is_enpassant(move)) {
return pos->en_passant + sq_up(them) == checker; return ep + sq_up(them) == ctz64(checkers);
} }
return true; return true;
//bitboard_t between = bb_between[king][checker] | pos->checkers;
//return mask(to) & between;
} }
/* (3) - pinned pieces /* (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) { if (pinned) {
return bb_line[from][king] & BIT(to); /* is to on pinner line ? */ return bb_line[from][kingsq] & BIT(to); /* is to on pinner line ? */
} }
/* (4) - En-passant /* (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 * One case not handled anywhere else: when the two "disappearing" pawns
* would discover a R/Q horizontal check. * 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); bitboard_t rank5 = bb_rel_rank(RANK_5, us);
if (unlikely((pos->bb[us][KING] & rank5))) { if (kingbb & rank5) {
bitboard_t exclude = BIT(pos->en_passant - sq_up(us)) | BIT(from); bitboard_t exclude = BIT(ep + sq_up(them)) | BIT(from);
bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5; bitboard_t rooks = (pos->bb[them][ROOK] | pos->bb[them][QUEEN]) & rank5;
if (hyperbola_rank_moves(occ ^ exclude, king) & rooks) return !(hq_rank_moves(occ ^ exclude, kingsq) & rooks);
return false;
} }
} }
return true; return true;
@@ -216,12 +212,9 @@ static inline __unused move_t *gen_pseudo_king(move_t *moves, square_t from,
* - castling, if king is in check * - castling, if king is in check
* - castling, if king passes an enemy-controlled square (not final square). * - castling, if king passes an enemy-controlled square (not final square).
* When immediately known, a few move flags are also applied in these cases: * When immediately known, a few move flags are also applied in these cases:
* - castling: M_CASTLE_{K,Q} * - castling: M_CASTLE
* - capture (excl. en-passant): M_CAPTURE
* - en-passant: M_EN_PASSANT * - en-passant: M_EN_PASSANT
* - pawn double push: M_DPUSH
* - promotion: M_PROMOTION * - promotion: M_PROMOTION
* - promotion and capture
* *
* TODO: move code to specific functions (especially castling, pawn push/capture) * TODO: move code to specific functions (especially castling, pawn push/capture)
* *
@@ -266,7 +259,8 @@ static inline __unused move_t *gen_pseudo_king(move_t *moves, square_t from,
* *
* @Return: New @moves. * @Return: New @moves.
*/ */
static inline __unused move_t *moves_gen_flags(move_t *moves, square_t from, bitboard_t to_bb, static inline __unused move_t *moves_gen_flags(move_t *moves, square_t from,
bitboard_t to_bb,
__unused move_flags_t flags) __unused move_flags_t flags)
{ {
square_t to; square_t to;
@@ -285,12 +279,15 @@ static inline __unused move_t *moves_gen_flags(move_t *moves, square_t from, bit
* *
* Generate (at address @moves) all promotion (Q/R/B/N) moves on @to for * Generate (at address @moves) all promotion (Q/R/B/N) moves on @to for
* pawn @from. * pawn @from.
* Actual promoted piece type is encoded as piece - 2, i.e. N = 0, B = 1,
* R = 2, Q = 3.
* *
* @Return: New @moves. * @Return: New @moves.
*/ */
static inline move_t *move_gen_promotions(move_t *moves, square_t from, square_t to) static inline move_t *move_gen_promotions(move_t *moves, square_t from, square_t to)
{ {
for (piece_type_t pt = QUEEN; pt >= KNIGHT; --pt) /* your attention: "downto operator" */
for (piece_type_t pt = QUEEN - 1; pt --> KNIGHT - 2;)
*moves++ = move_make_promote(from, to, pt); *moves++ = move_make_promote(from, to, pt);
return moves; return moves;
} }
@@ -331,7 +328,6 @@ static inline move_t *moves_gen(move_t *moves, square_t from, bitboard_t to_bb)
* - castling: M_CASTLE_{K,Q} * - castling: M_CASTLE_{K,Q}
* - capture (excl. en-passant): M_CAPTURE * - capture (excl. en-passant): M_CAPTURE
* - en-passant: M_EN_PASSANT * - en-passant: M_EN_PASSANT
* - pawn double push: M_DPUSH
* - promotion: M_PROMOTION * - promotion: M_PROMOTION
* - promotion and capture * - promotion and capture
* *
@@ -349,12 +345,12 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
bitboard_t dest_squares = ~my_pieces; bitboard_t dest_squares = ~my_pieces;
bitboard_t occ = my_pieces | enemy_pieces; bitboard_t occ = my_pieces | enemy_pieces;
bitboard_t empty = ~occ; bitboard_t empty = ~occ;
move_t *moves = movelist->move;
square_t king = pos->king[us];
bitboard_t from_bb, to_bb; bitboard_t from_bb, to_bb;
bitboard_t tmp_bb; bitboard_t tmp_bb;
move_t *moves = movelist->move;
square_t from, to; square_t from, to;
square_t king = pos->king[us];
/* king - MUST BE FIRST */ /* king - MUST BE FIRST */
to_bb = bb_king_moves(dest_squares, king); to_bb = bb_king_moves(dest_squares, king);
@@ -379,15 +375,17 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
* To square attack check will be done in gen_is_legal. * To square attack check will be done in gen_is_legal.
*/ */
if (can_oo(pos->castle, us)) { if (can_oo(pos->castle, us)) {
/* CHANGE HERE, either with bitmask >> or direct sq check */
bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb); bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb);
if (!(occ & occmask)) { if (!(occ & occmask)) {
*moves++ = move_make_flags(king, king + 2, M_CASTLE_K); *moves++ = move_make_flags(king, king + 2, M_CASTLE);
} }
} }
if (can_ooo(pos->castle, us)) { if (can_ooo(pos->castle, us)) {
bitboard_t occmask = rel_rank1 & (FILE_Bbb | FILE_Cbb | FILE_Dbb); bitboard_t occmask = rel_rank1 & (FILE_Bbb | FILE_Cbb | FILE_Dbb);
if (!(occ & occmask)) { // && if (!(occ & occmask)) { // &&
*moves++ = move_make_flags(king, king - 2, M_CASTLE_Q); *moves++ = move_make_flags(king, king - 2, M_CASTLE);
} }
} }
} }
@@ -396,13 +394,13 @@ movelist_t *pos_gen_pseudo(pos_t *pos, movelist_t *movelist)
from_bb = pos->bb[us][BISHOP] | pos->bb[us][QUEEN]; from_bb = pos->bb[us][BISHOP] | pos->bb[us][QUEEN];
while (from_bb) { while (from_bb) {
from = bb_next(&from_bb); from = bb_next(&from_bb);
to_bb = hyperbola_bishop_moves(occ, from) & dest_squares; to_bb = hq_bishop_moves(occ, from) & dest_squares;
moves = moves_gen(moves, from, to_bb); moves = moves_gen(moves, from, to_bb);
} }
from_bb = pos->bb[us][ROOK] | pos->bb[us][QUEEN]; from_bb = pos->bb[us][ROOK] | pos->bb[us][QUEEN];
while (from_bb) { while (from_bb) {
from = bb_next(&from_bb); from = bb_next(&from_bb);
to_bb = hyperbola_rook_moves(occ, from) & dest_squares; to_bb = hq_rook_moves(occ, from) & dest_squares;
moves = moves_gen(moves, from, to_bb); moves = moves_gen(moves, from, to_bb);
} }

View File

@@ -17,7 +17,7 @@
#include "bitops.h" #include "bitops.h"
#include "bitboard.h" #include "bitboard.h"
#include "hyperbola-quintessence.h" #include "hq.h"
#include "piece.h" #include "piece.h"
#include "move.h" #include "move.h"

View File

@@ -94,6 +94,8 @@
* @move: move * @move: move
* @flags: moves selection and display options. * @flags: moves selection and display options.
* *
* @dst should be large enough to contain move string + '\0' terminator.
*
* Possible flags are: * Possible flags are:
* M_PR_CAPT: print move if capture * M_PR_CAPT: print move if capture
* M_PR_NCAPT: print move if non capture * M_PR_NCAPT: print move if non capture
@@ -104,18 +106,78 @@
*/ */
char *move_to_str(char *dst, const move_t move, __unused const int flags) char *move_to_str(char *dst, const move_t move, __unused const int flags)
{ {
if (move == MOVE_NONE) {
strcpy(dst, "none");
} else if (move == MOVE_NULL) {
strcpy(dst, "null");
} else {
square_t from = move_from(move); square_t from = move_from(move);
square_t to = move_to(move); square_t to = move_to(move);
int len; int len;
sprintf(dst, "%s%s%n", sq_to_string(from), sq_to_string(to), &len); sprintf(dst, "%s%s%n", sq_to_string(from), sq_to_string(to), &len);
if (is_promotion(move)) { if (is_promotion(move)) {
piece_t promoted = (piece_t) move_promoted(move); piece_t promoted = (piece_t) move_promoted(move);
sprintf(dst + len, "%s", piece_to_low(promoted)); sprintf(dst + len, "%s", piece_to_low(promoted));
} }
}
return dst; return dst;
} }
/**
* move_from_str() - create a move from an UCI move string
* @str: uci move string
*
* Only from/to squares and promotion information are filled.
* To get a full move, @move_find_in_movelist() can be called,
* with a list of moves to choose from.
*
* @return: partial move.
*/
move_t move_from_str(const char *str)
{
move_t move;
square_t from = sq_from_string(str);
square_t to = sq_from_string(str + 2);
piece_type_t promoted = piece_t_from_char(*(str+4));
if (promoted != NO_PIECE_TYPE) { /* promotion */
move = move_make_promote(from, to, promoted - 2);
} else {
move = move_make(from, to);
}
return move;
}
/**
* move_find_in_movelist() - find a partial move in movelist.
* @move: move (may be partial)
* @movelist: &movelist_t to search
*
* Look for @target into @list, by comparing its from, to, and promotion
* information.
*
* @return: move in @movelist if match found, MOVE_NONE otherwise.
*/
move_t move_find_in_movelist(move_t target, movelist_t *list)
{
move_t *move = list->move, *last = move + list->nmoves;
for (; move < last; ++move) {
/* note that we compare promoted piece without checking if the move
* is a promotion. But, in our move representation "promoted Knight"
* is encoded as zero, same as when there is no promotion. This can
* lead to false match is @target or some @list moves are invalid,
* which we do not consider.
*/
if (move_fromto(target) == move_fromto(*move) &&
move_promoted(target) == move_promoted(*move))
return *move;
}
return MOVE_NONE;
}
/** /**
* moves_print() - print movelist moves. * moves_print() - print movelist moves.
* @moves: &movelist_t moves list * @moves: &movelist_t moves list
@@ -148,12 +210,13 @@ static int _moves_cmp_bysquare(const void *p1, const void *p2)
square_t t2 = move_to(m2); square_t t2 = move_to(m2);
piece_type_t prom1 = move_promoted(m1); piece_type_t prom1 = move_promoted(m1);
piece_type_t prom2 = move_promoted(m2); piece_type_t prom2 = move_promoted(m2);
/* We compare origin square first */
if (f1 < f2) return -1; if (f1 < f2) return -1;
if (f1 > f2) return 1; if (f1 > f2) return 1;
/* f1 == f2 */ /* f1 == f2, we compare destination squares */
if (t1 < t2) return -1; if (t1 < t2) return -1;
if (t1 > t2) return 1; if (t1 > t2) return 1;
/* t1 == t2 */ /* t1 == t2, we compare promoted piece */
if (prom1 < prom2) return -1; if (prom1 < prom2) return -1;
if (prom1 > prom2) return 1; if (prom1 > prom2) return 1;
return 0; return 0;

View File

@@ -19,53 +19,45 @@
#include "board.h" #include "board.h"
/* move structure: /* move structure:
* 3 3 2 2 1 1 1 1 1 1 * 11 11 1
* 1 0 4 3 8 7 5 4 2 1 6 5 0 * 54 32 1 6 5 0
* S UUUUUUU FFFFFF ccc ppp tttttt ffffff * FF pp tttttt ffffff
* *
* bits len off range type mask get desc * bits len off range type mask get desc
* ffffff 6 0 0-5 square_t 077 &077 from * ffffff 6 0 0-5 square_t 077 &077 from
* tttttt 6 6 6-11 square_t 07700 (>>6) &077 to * tttttt 6 6 6-11 square_t 07700 (>>6) &077 to
* ppp 3 12 12-14 piece_type_t 070000 (>>12) &07 promoted * pp 2 12 12-13 piece_type_t 030000 (>>12) &03 promoted
* ccc 3 15 15-17 piece_type_t 0700000 (>>15) &07 captured * FF 2 14 14-15 move_flags_t 0140000 (>>14) &03 flags
* FFFFFF 6 18 18-23 move_flags_t 077000000 (>>18) &077 N/A flags
* UUUUUUU 7 24 24-30 unused 017700000000 future usage
* S 1 31 31-31 - 020000000000 sign
*/ */
typedef s32 move_t; typedef u16 move_t;
/* special move_t values */
#define MOVE_NONE ((move_t) -1)
#define MOVE_NULL ((move_t) 0) /* hack: from = to = A1 */
enum { enum {
M_OFF_FROM = 0, M_OFF_FROM = 0,
M_OFF_TO = 6, M_OFF_TO = 6,
M_OFF_PROMOTED = 12, M_OFF_PROMOTED = 12,
// M_OFF_CAPTURED = 15, M_OFF_FLAGS = 14
M_OFF_FLAGS = 15
}; };
typedef enum { typedef enum {
M_PROMOTION = 070000, M_PROMOTED_MASK = 0030000,
// M_CAPTURE = BIT(M_OFF_FLAGS + 0), M_FLAGS_MASK = 0140000,
M_ENPASSANT = BIT(M_OFF_FLAGS + 0),
M_CASTLE_K = BIT(M_OFF_FLAGS + 1), /* maybe only one ? */ M_ENPASSANT = 040000, /* 1 << M_OFF_FLAGS */
M_CASTLE_Q = BIT(M_OFF_FLAGS + 2), /* maybe only one ? */ M_CASTLE = 0100000, /* 2 << M_OFF_FLAGS */
M_CHECK = BIT(M_OFF_FLAGS + 3), /* maybe unknown/useless ? */ M_PROMOTION = 0140000, /* 3 << M_OFF_FLAGS */
// M_DPUSH = BIT(M_OFF_FLAGS + 7) /* pawn double push */
} move_flags_t; } move_flags_t;
#define move_set_flags(move, flags) ((move) | (flags)) /* special move_t values */
#define MOVE_NULL 0 /* hack: from = to = A1 */
#define MOVE_NONE 07777 /* hack: from = to = H8 */
//#define is_capture(m) ((m) & M_CAPTURE) #define move_set_flags(move, flags) ((move) | (flags))
#define is_enpassant(m) ((m) & M_ENPASSANT) #define move_flags(move) ((move) & M_FLAGS_MASK)
#define is_promotion(m) ((m) & M_PROMOTION)
#define is_castle(m) ((m) & (M_CASTLE_K | M_CASTLE_Q)) #define is_promotion(m) (move_flags(m) == M_PROMOTION)
#define is_castle_K(m) ((m) & M_CASTLE_K) #define is_enpassant(m) (move_flags(m) == M_ENPASSANT)
#define is_castle_Q(m) ((m) & M_CASTLE_Q) #define is_castle(m) (move_flags(m) == M_CASTLE)
#define is_check(m) ((m) & M_CHECK) // #define is_check(m) (move_flags(m) == M_CHECK)
//#define is_dpush(m) ((m) & M_DPUSH)
#define MOVES_MAX 256 #define MOVES_MAX 256
@@ -84,9 +76,14 @@ static inline square_t move_to(move_t move)
return (move >> M_OFF_TO) & 077; return (move >> M_OFF_TO) & 077;
} }
static inline move_t move_fromto(move_t move)
{
return move & 07777;
}
static inline piece_type_t move_promoted(move_t move) static inline piece_type_t move_promoted(move_t move)
{ {
return (move >> M_OFF_PROMOTED) & 07; return ((move >> M_OFF_PROMOTED) & 03) + KNIGHT;
} }
/* /*
@@ -122,7 +119,7 @@ static inline move_t move_make_enpassant(square_t from, square_t to)
static inline move_t move_make_promote(square_t from, square_t to, static inline move_t move_make_promote(square_t from, square_t to,
piece_type_t promoted) piece_type_t promoted)
{ {
return move_make(from, to) | (promoted << M_OFF_PROMOTED); return move_make_flags(from, to, M_PROMOTION) | (promoted << M_OFF_PROMOTED);
} }
/* /*
@@ -151,8 +148,9 @@ static inline move_t move_make_promote(square_t from, square_t to,
#define M_PR_SEPARATE 0x40 /* separate captures */ #define M_PR_SEPARATE 0x40 /* separate captures */
#define M_PR_LONG 0x80 #define M_PR_LONG 0x80
//int move_print(int movenum, move_t *move, move_flags_t flags);
char *move_to_str(char *dst, const move_t move, __unused const int flags); char *move_to_str(char *dst, const move_t move, __unused const int flags);
move_t move_from_str(const char *str);
move_t move_find_in_movelist(move_t target, movelist_t *list);
void moves_print(movelist_t *moves, int flags); void moves_print(movelist_t *moves, int flags);
void move_sort_by_sq(movelist_t *moves); void move_sort_by_sq(movelist_t *moves);

View File

@@ -24,23 +24,23 @@
/** /**
* piece_details * piece_details
*/ */
const struct piece_details piece_details[PIECE_MAX] = { const struct piece_details piece_details[PIECE_NB] = {
/* cap low fen sym name values */ /* cap low fen sym name midgame val endgame val */
[EMPTY] = { "", "", "", "", "", 0, 0, 0 }, [EMPTY] = { "", "", "", "", "", 0, 0 },
[W_PAWN] = { "", "", "P", "", "Pawn", P_VAL_OPN, P_VAL_MID, P_VAL_END }, [W_PAWN] = { "", "", "P", "", "Pawn", P_VAL_MID, P_VAL_END },
[W_KNIGHT] = { "N", "n", "N", "", "Knight", N_VAL_OPN, N_VAL_MID, N_VAL_END }, [W_KNIGHT] = { "N", "n", "N", "", "Knight", N_VAL_MID, N_VAL_END },
[W_BISHOP] = { "B", "b", "B", "", "Bishop", B_VAL_OPN, B_VAL_MID, B_VAL_END }, [W_BISHOP] = { "B", "b", "B", "", "Bishop", B_VAL_MID, B_VAL_END },
[W_ROOK] = { "R", "r", "R", "", "Rook", R_VAL_OPN, R_VAL_MID, R_VAL_END }, [W_ROOK] = { "R", "r", "R", "", "Rook", R_VAL_MID, R_VAL_END },
[W_QUEEN] = { "Q", "q", "Q", "", "Queen", Q_VAL_OPN, Q_VAL_MID, Q_VAL_END }, [W_QUEEN] = { "Q", "q", "Q", "", "Queen", Q_VAL_MID, Q_VAL_END },
[W_KING] = { "K", "k", "K", "", "King", K_VAL_OPN, K_VAL_MID, K_VAL_END }, [W_KING] = { "K", "k", "K", "", "King", K_VAL_MID, K_VAL_END },
[7] = { "", "", "", "", "", 0, 0, 0 }, [7] = { "", "", "", "", "", 0, 0 },
[8] = { "", "", "", "", "", 0, 0, 0 }, [8] = { "", "", "", "", "", 0, 0 },
[B_PAWN] = { "", "", "p", "", "Pawn", P_VAL_OPN, P_VAL_MID, P_VAL_END }, [B_PAWN] = { "", "", "p", "", "Pawn", P_VAL_MID, P_VAL_END },
[B_KNIGHT] = { "N", "n", "n", "", "Knight", P_VAL_OPN, N_VAL_MID, N_VAL_END }, [B_KNIGHT] = { "N", "n", "n", "", "Knight", N_VAL_MID, N_VAL_END },
[B_BISHOP] = { "B", "b", "b", "", "Bishop", P_VAL_OPN, B_VAL_MID, B_VAL_END }, [B_BISHOP] = { "B", "b", "b", "", "Bishop", B_VAL_MID, B_VAL_END },
[B_ROOK] = { "R", "r", "r", "", "Rook", P_VAL_OPN, R_VAL_MID, R_VAL_END }, [B_ROOK] = { "R", "r", "r", "", "Rook", R_VAL_MID, R_VAL_END },
[B_QUEEN] = { "Q", "q", "q", "", "Queen", P_VAL_OPN, Q_VAL_MID, Q_VAL_END }, [B_QUEEN] = { "Q", "q", "q", "", "Queen", Q_VAL_MID, Q_VAL_END },
[B_KING] = { "K", "k", "k", "", "King", P_VAL_OPN, K_VAL_MID, K_VAL_END }, [B_KING] = { "K", "k", "k", "", "King", K_VAL_MID, K_VAL_END },
}; };
const char pieces_str[6+6+1] = "PNBRQKpnbrqk"; const char pieces_str[6+6+1] = "PNBRQKpnbrqk";

View File

@@ -24,43 +24,38 @@
* C: 0 for white, 1: black * C: 0 for white, 1: black
* PPP: pawn (1), knight, bishop, rook, queen, king (6) * PPP: pawn (1), knight, bishop, rook, queen, king (6)
*/ */
typedef enum { enum {
WHITE, BLACK, WHITE, BLACK,
COLOR_MAX COLOR_NB
} color_t; };
typedef u8 color_t;
typedef enum { enum {
ALL_PIECES = 0, /* 'all pieces' bitboard */ ALL_PIECES = 0, /* 'all pieces' bitboard */
NO_PIECE_TYPE = 0, NO_PIECE_TYPE = 0,
PAWN = 1, KNIGHT, BISHOP, ROOK, QUEEN, KING, PAWN = 1, KNIGHT, BISHOP, ROOK, QUEEN, KING,
PIECE_TYPE_MAX = 7 /* bit 4 */ PIECE_TYPE_NB,
} piece_type_t; PT_NB = PIECE_TYPE_NB
};
typedef u8 piece_type_t;
typedef enum __piece_e { enum __piece_e {
EMPTY = 0, EMPTY = 0,
NO_PIECE = 0, NO_PIECE = 0,
W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING, W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
B_PAWN = PAWN | 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING, B_PAWN = PAWN | 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
PIECE_MAX PIECE_NB
} piece_t; };
typedef u8 piece_t;
/* default values for opening, midgame, endgame /* default values for midgame, endgame
*/ */
#define E_VAL_OPN 0 /* empty */
#define P_VAL_OPN 100
#define N_VAL_OPN 300
#define B_VAL_OPN 300
#define R_VAL_OPN 500
#define Q_VAL_OPN 900
#define K_VAL_OPN 20000
#define E_VAL_MID 0 #define E_VAL_MID 0
#define P_VAL_MID 100 #define P_VAL_MID 100
#define N_VAL_MID 300 #define N_VAL_MID 300
#define B_VAL_MID 300 #define B_VAL_MID 300
#define R_VAL_MID 500 #define R_VAL_MID 500
#define Q_VAL_MID 900 #define Q_VAL_MID 900
#define K_VAL_MID 20000 #define K_VAL_MID 10000
#define E_VAL_END 0 #define E_VAL_END 0
#define P_VAL_END 100 #define P_VAL_END 100
@@ -68,7 +63,7 @@ typedef enum __piece_e {
#define B_VAL_END 300 #define B_VAL_END 300
#define R_VAL_END 500 #define R_VAL_END 500
#define Q_VAL_END 900 #define Q_VAL_END 900
#define K_VAL_END 20000 #define K_VAL_END 10000
/* some default values for pieces /* some default values for pieces
* @abbr: char, piece capital letter (used for game notation) * @abbr: char, piece capital letter (used for game notation)
@@ -86,10 +81,9 @@ extern const struct piece_details {
char *fen; /* cap=white, low=black */ char *fen; /* cap=white, low=black */
char *sym; /* UTF-8 symbol */ char *sym; /* UTF-8 symbol */
char *name; /* piece name */ char *name; /* piece name */
s64 opn_value; /* value opening */ s16 mid_value; /* value midgame */
s64 mid_value; /* value midgame */ s16 end_value; /* value endgame */
s64 end_value; /* value endgame */ } piece_details[PIECE_NB];
} piece_details[PIECE_MAX];
extern const char pieces_str[6+6+1]; /* to search from fen/user input */ extern const char pieces_str[6+6+1]; /* to search from fen/user input */
@@ -102,13 +96,18 @@ extern const char pieces_str[6+6+1]; /* to search from fen/user inp
#define PIECE(p) ((p) & MASK_PIECE) #define PIECE(p) ((p) & MASK_PIECE)
#define MAKE_PIECE(p, c) ((p) | (c) << 3) #define MAKE_PIECE(p, c) ((p) | (c) << 3)
#define IS_WHITE(p) (!COLOR(p)) #define IS_BLACK(p) ((p) & MASK_COLOR)
#define IS_BLACK(p) (COLOR(p)) #define IS_WHITE(p) (! IS_BLACK(p))
#define SET_WHITE(p) (piece_t)((p) &= ~MASK_COLOR) #define SET_WHITE(p) (piece_t)((p) &= ~MASK_COLOR)
#define SET_BLACK(p) (piece_t)((p) |= MASK_COLOR) #define SET_BLACK(p) (piece_t)((p) |= MASK_COLOR)
#define SET_COLOR(p, c) (piece_t)(!(c)? SET_WHITE(p): SET_BLACK(p)) #define SET_COLOR(p, c) (piece_t)(!(c)? SET_WHITE(p): SET_BLACK(p))
static __inline s16 piece_val(piece_type_t pt)
{
return piece_details[pt].mid_value;
}
bool piece_ok(piece_t p); bool piece_ok(piece_t p);
char *piece_to_cap(piece_t p); char *piece_to_cap(piece_t p);
@@ -118,18 +117,13 @@ char *piece_to_sym(piece_t p);
char *piece_to_name(piece_t p); char *piece_to_name(piece_t p);
#define piece_to_char(c) piece_to_fen(c) #define piece_to_char(c) piece_to_fen(c)
//#define piece_to_char_t(p) piece_to_uci(p) #define piece_to_uci(p) piece_to_low(p)
//piece_type_t char_to_piece(char c);
piece_type_t piece_t_from_char(char c); piece_type_t piece_t_from_char(char c);
piece_t piece_from_fen(char c); piece_t piece_from_fen(char c);
#define piece_from_char(c) piece_from_fen(c) #define piece_from_char(c) piece_from_fen(c)
/* use short name or symbol - no effect
*/
#define P_USE_UTF 1
//void piece_list_print(struct list_head *list); //void piece_list_print(struct list_head *list);
//pool_t *piece_pool_init(); //pool_t *piece_pool_init();
//void piece_pool_stats(); //void piece_pool_stats();

View File

@@ -20,16 +20,18 @@
#include <brlib.h> #include <brlib.h>
#include <bitops.h> #include <bitops.h>
#include <bug.h>
#include "chessdefs.h" #include "chessdefs.h"
#include "position.h" #include "position.h"
#include "bitboard.h" #include "bitboard.h"
#include "hyperbola-quintessence.h" #include "hq.h"
#include "fen.h" #include "fen.h"
#include "piece.h" #include "piece.h"
#include "util.h" #include "alloc.h"
#include "board.h" #include "board.h"
#include "attack.h" #include "attack.h"
#include "hist.h"
/** /**
* pos_new() - allocate a new position * pos_new() - allocate a new position
@@ -41,7 +43,7 @@
*/ */
pos_t *pos_new(void) pos_t *pos_new(void)
{ {
return safe_malloc(sizeof(pos_t)); return safe_alloc(sizeof(pos_t));
} }
/** /**
@@ -56,7 +58,7 @@ pos_t *pos_new(void)
*/ */
pos_t *pos_dup(const pos_t *pos) pos_t *pos_dup(const pos_t *pos)
{ {
pos_t *newpos = safe_malloc(sizeof(pos_t)); pos_t *newpos = safe_alloc(sizeof(pos_t));
*newpos = *pos; *newpos = *pos;
return newpos; return newpos;
@@ -107,6 +109,7 @@ pos_t *pos_clear(pos_t *pos)
pos->castle = 0; pos->castle = 0;
pos->clock_50 = 0; pos->clock_50 = 0;
pos->plycount = 0; pos->plycount = 0;
pos->move = MOVE_NONE;
pos->captured = NO_PIECE; pos->captured = NO_PIECE;
for (square_t sq = A1; sq <= H8; ++sq) for (square_t sq = A1; sq <= H8; ++sq)
@@ -123,8 +126,6 @@ pos_t *pos_clear(pos_t *pos)
pos->pinners = 0; pos->pinners = 0;
pos->blockers = 0; pos->blockers = 0;
pos->repeat.moves = 0;
return pos; return pos;
} }
@@ -167,10 +168,12 @@ bool pos_cmp(const pos_t *pos1, const pos_t *pos2)
if (_cmpf(checkers) ||_cmpf(pinners) || _cmpf(blockers)) if (_cmpf(checkers) ||_cmpf(pinners) || _cmpf(blockers))
goto end; goto end;
if (_cmpf(repeat.moves) || /*
memcmp(pos1->repeat.key, pos2->repeat.key, * if (_cmpf(repeat.moves) ||
pos1->repeat.moves * sizeof pos1->repeat.key)) * memcmp(pos1->repeat.key, pos2->repeat.key,
goto end; * pos1->repeat.moves * sizeof pos1->repeat.key))
* goto end;
*/
ret = true; ret = true;
end: end:
@@ -216,7 +219,7 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
attackers = pos->bb[them][BISHOP] | pos->bb[them][QUEEN]; attackers = pos->bb[them][BISHOP] | pos->bb[them][QUEEN];
/* targets is all "target" pieces if K was a bishop */ /* targets is all "target" pieces if K was a bishop */
targets = hyperbola_bishop_moves(occ, king) & occ; targets = hq_bishop_moves(occ, king) & occ;
/* checkers = only opponent B/Q */ /* checkers = only opponent B/Q */
tmpcheckers = targets & attackers; tmpcheckers = targets & attackers;
@@ -227,7 +230,7 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
/* we find second targets, by removing first ones (excl. checkers) */ /* we find second targets, by removing first ones (excl. checkers) */
if (maybeblockers) { if (maybeblockers) {
targets = hyperbola_bishop_moves(occ ^ maybeblockers, king) ^ tmpcheckers; targets = hq_bishop_moves(occ ^ maybeblockers, king) ^ tmpcheckers;
/* pinners = only B/Q */ /* pinners = only B/Q */
tmppinners = targets & attackers; tmppinners = targets & attackers;
@@ -242,14 +245,14 @@ void pos_set_checkers_pinners_blockers(pos_t *pos)
/* same for rook type */ /* same for rook type */
attackers = pos->bb[them][ROOK] | pos->bb[them][QUEEN]; attackers = pos->bb[them][ROOK] | pos->bb[them][QUEEN];
targets = hyperbola_rook_moves(occ, king) & occ; targets = hq_rook_moves(occ, king) & occ;
tmpcheckers = targets & attackers; tmpcheckers = targets & attackers;
checkers |= tmpcheckers; checkers |= tmpcheckers;
maybeblockers = targets & ~tmpcheckers; maybeblockers = targets & ~tmpcheckers;
if (maybeblockers) { if (maybeblockers) {
targets = hyperbola_rook_moves(occ ^ maybeblockers, king) ^ tmpcheckers; targets = hq_rook_moves(occ ^ maybeblockers, king) ^ tmpcheckers;
tmppinners = targets & attackers; tmppinners = targets & attackers;
while (tmppinners) { while (tmppinners) {
pinner = bb_next(&tmppinners); pinner = bb_next(&tmppinners);
@@ -360,64 +363,52 @@ bitboard_t pos_king_blockers(const pos_t *pos, const color_t color, const bitboa
bool pos_ok(pos_t *pos, const bool strict) bool pos_ok(pos_t *pos, const bool strict)
{ {
int n, count = 0, bbcount = 0, error = 0; int n, count = 0, bbcount = 0, error = 0;
color_t us = pos->turn, them = OPPONENT(us); color_t us = pos->turn, __unused them = OPPONENT(us);
/* force BUG_ON and WARN_ON */
# pragma push_macro("BUG_ON")
# pragma push_macro("WARN_ON")
# undef BUG_ON
# define BUG_ON
# undef WARN_ON
# define WARN_ON
# include <bug.h>
/* pawns on 1st ot 8th rank */ /* pawns on 1st ot 8th rank */
error += warn_on((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) & error += warn_on_or_eval((pos->bb[WHITE][PAWN] | pos->bb[BLACK][PAWN]) &
(RANK_1bb | RANK_8bb)); (RANK_1bb | RANK_8bb));
for (color_t color = WHITE; color <= BLACK; ++color) { for (color_t color = WHITE; color <= BLACK; ++color) {
/* pawn count */ /* pawn count */
n = popcount64(pos->bb[color][PAWN]); n = popcount64(pos->bb[color][PAWN]);
error += warn_on(n > 8); error += warn_on_or_eval(n > 8);
/* king count */ /* king count */
n = popcount64(pos->bb[color][KING]); n = popcount64(pos->bb[color][KING]);
error += warn_on(n != 1); error += warn_on_or_eval(n != 1);
/* king mismatch with board */ /* king mismatch with board */
error += warn_on(PIECE(pos->board[pos->king[color]]) != KING); error += warn_on_or_eval(PIECE(pos->board[pos->king[color]]) != KING);
/* pieces count */ /* pieces count */
n = popcount64(pos->bb[color][ALL_PIECES]); n = popcount64(pos->bb[color][ALL_PIECES]);
error += warn_on(n == 0 || n > 16); error += warn_on_or_eval(n == 0 || n > 16);
bbcount += n; bbcount += n;
} }
for (square_t sq = 0; sq < 64; ++sq) { for (square_t sq = 0; sq < 64; ++sq) {
piece_t piece = pos->board[sq]; piece_t piece = pos->board[sq];
bitboard_t match; __unused bitboard_t match;
if (piece == EMPTY) if (piece == EMPTY)
continue; continue;
color_t c = COLOR(piece); color_t c = COLOR(piece);
piece_type_t p = PIECE(piece); piece_type_t p = PIECE(piece);
match = pos->bb[c][p] & BIT(sq); match = pos->bb[c][p] & BIT(sq);
error += warn_on(!match); error += warn_on_or_eval(!match);
count++; count++;
} }
/* occupied board is different from bitboards */ /* occupied board is different from bitboards */
error += warn_on(count != bbcount); error += warn_on_or_eval(count != bbcount);
/* is opponent already in check ? */ /* is opponent already in check ? */
error += warn_on(pos_checkers(pos, them)); error += warn_on_or_eval(pos_checkers(pos, them));
/* is color to play in check more than twice ? */ /* is color to play in check more than twice ? */
error += warn_on(popcount64(pos_checkers(pos, us)) > 2); error += warn_on_or_eval(popcount64(pos_checkers(pos, us)) > 2);
/* kings distance is less than 2 */ /* kings distance is less than 2 */
error += warn_on(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2); error += warn_on_or_eval(sq_dist(pos->king[WHITE], pos->king[BLACK]) < 2);
/* e.p. and castling rights check */ /* e.p. and castling rights check */
error += fen_ok(pos, false); error += fen_ok(pos, false);
if (strict) { if (strict) {
bug_on(error); bug_on_always(error);
/* not reached */
} }
return error? false: true; return error? false: true;
# pragma pop_macro("WARN_ON")
# pragma pop_macro("BUG_ON")
} }
/** /**
@@ -429,8 +420,9 @@ void pos_print(const pos_t *pos)
char str[128]; char str[128];
board_print(pos->board); board_print(pos->board);
printf("key:%lx ", pos->key);
printf("fen: %s\n", pos2fen(pos, str)); printf("fen: %s\n", pos2fen(pos, str));
printf("last move:%s ", move_to_str(str, pos->move, 0));
printf("key:%lx\n", pos->key);
printf("checkers:%s ", pos_checkers2str(pos, str, sizeof(str))); printf("checkers:%s ", pos_checkers2str(pos, str, sizeof(str)));
printf("pinners: %s ", pos_pinners2str(pos, str, sizeof(str))); printf("pinners: %s ", pos_pinners2str(pos, str, sizeof(str)));
printf("blockers: %s\n", pos_blockers2str(pos, str, sizeof(str))); printf("blockers: %s\n", pos_blockers2str(pos, str, sizeof(str)));

View File

@@ -28,13 +28,6 @@
#include "move.h" #include "move.h"
#include "board.h" #include "board.h"
#define REPEAT_SIZE 1024
typedef struct {
hkey_t key[REPEAT_SIZE];
int moves;
} repeat_t;
typedef struct __pos_s { typedef struct __pos_s {
u64 node_count; /* evaluated nodes */ u64 node_count; /* evaluated nodes */
int turn; /* WHITE or BLACK */ int turn; /* WHITE or BLACK */
@@ -50,21 +43,29 @@ typedef struct __pos_s {
* This allows a memcpy on this data (to save/restore position state). * This allows a memcpy on this data (to save/restore position state).
*/ */
struct_group_tagged(state_s, state, struct_group_tagged(state_s, state,
/* 64 bits */
struct state_s *prev;
hkey_t key; hkey_t key;
/* 16 bits */
move_t move;
u16 plycount; /* plies so far, start from 1 */
s16 phase;
/* 8 bits */
square_t en_passant; square_t en_passant;
castle_rights_t castle; castle_rights_t castle;
int clock_50;
int plycount; /* plies so far, start from 1 */
piece_t captured; /* only used in move_undo */ piece_t captured; /* only used in move_undo */
u8 clock_50;
); );
eval_t eval;
bitboard_t checkers; /* opponent checkers */ bitboard_t checkers; /* opponent checkers */
bitboard_t pinners; /* opponent pinners */ bitboard_t pinners; /* opponent pinners */
bitboard_t blockers; /* pieces blocking pin */ bitboard_t blockers; /* pieces blocking pin */
piece_t board[BOARDSIZE]; piece_t board[BOARDSIZE];
bitboard_t bb[2][PIECE_TYPE_MAX]; /* bb[0][PAWN], bb[1][ALL_PIECES] */ bitboard_t bb[2][PT_NB]; /* bb[0][PAWN], bb[1][ALL_PIECES] */
square_t king[2]; /* dup with bb, faster retrieval */ square_t king[2]; /* dup with bb, faster retrieval */
repeat_t repeat; /* for repetition detection */
} pos_t; } pos_t;
typedef struct state_s state_t; typedef struct state_s state_t;

View File

@@ -26,7 +26,7 @@
* @pos: &position to search * @pos: &position to search
* @depth: Wanted depth. * @depth: Wanted depth.
* @ply: current perft depth level (root = 1) * @ply: current perft depth level (root = 1)
* @output: output total for 1st level moves. * @divide: output total for 1st level moves.
* *
* Run perft on a position. This function displays the available moves at @depth * Run perft on a position. This function displays the available moves at @depth
* level for each possible first move, and the total of moves. * level for each possible first move, and the total of moves.
@@ -42,17 +42,12 @@
* *
* @return: total moves found at @depth level. * @return: total moves found at @depth level.
*/ */
u64 perft(pos_t *pos, int depth, int ply, bool output) u64 perft(pos_t *pos, int depth, int ply, bool divide)
{ {
u64 subnodes, nodes = 0; u64 subnodes = 0, nodes = 0;
movelist_t movelist; movelist_t movelist;
move_t *move, *last; move_t *move, *last;
state_t state; state_t state;
# ifdef PERFT_MOVE_HISTORY
static movelist_t stack;
if (ply == 1)
stack.nmoves = 0;
# endif
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
@@ -60,41 +55,33 @@ u64 perft(pos_t *pos, int depth, int ply, bool output)
last = movelist.move + movelist.nmoves; last = movelist.move + movelist.nmoves;
for (move = movelist.move; move < last; ++move) { for (move = movelist.move; move < last; ++move) {
if (depth == 1) { if (depth == 1) {
nodes++; subnodes = 1;
} else { } else {
move_do(pos, *move, &state); move_do(pos, *move, &state);
# ifdef PERFT_MOVE_HISTORY
stack.move[stack.nmoves++] = *move;
# endif
if (depth == 2) { if (depth == 2) {
movelist_t movelist2; movelist_t movelist2;
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
} else if (ply >= 4) { } else if (ply >= 3) {
hentry_t *entry = tt_probe_perft(pos->key, depth); hentry_t *entry = tt_probe_perft(pos->key, depth);
if (entry != TT_MISS) { if (entry != TT_MISS) {
subnodes = HASH_PERFT_VAL(entry->data); subnodes = HASH_PERFT_VAL(entry->data);
} else { } else {
subnodes = perft(pos, depth - 1, ply + 1, output); subnodes = perft(pos, depth - 1, ply + 1, divide);
tt_store_perft(pos->key, depth, subnodes); tt_store_perft(pos->key, depth, subnodes);
} }
} else { } else {
subnodes = perft(pos, depth - 1, ply + 1, output); subnodes = perft(pos, depth - 1, ply + 1, divide);
} }
if (output && ply == 1) { move_undo(pos, *move, &state);
}
nodes += subnodes;
if (ply == 1 && divide) {
char movestr[8]; char movestr[8];
printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes);
} }
nodes += subnodes;
move_undo(pos, *move, &state);
# ifdef PERFT_MOVE_HISTORY
stack.nmoves--;
# endif
}
} }
if (output && ply == 1)
printf("Total: %lu\n", nodes);
return nodes; return nodes;
} }
@@ -103,16 +90,16 @@ u64 perft(pos_t *pos, int depth, int ply, bool output)
* @pos: &position to search * @pos: &position to search
* @depth: Wanted depth. * @depth: Wanted depth.
* @ply: current perft depth level (root = 1) * @ply: current perft depth level (root = 1)
* @output: output total for 1st level moves. * @divide: output total for 1st level moves.
* *
* Run perft on a position. This function displays the available moves at @depth * Run perft on a position. This function displays the available moves at @depth
* level for each possible first move, and the total of moves. * level for each possible first move, and the total of moves.
* *
* @return: total moves found at @depth level. * @return: total moves found at @depth level.
*/ */
u64 perft_alt(pos_t *pos, int depth, int ply, bool output) u64 perft_alt(pos_t *pos, int depth, int ply, bool divide)
{ {
u64 subnodes, nodes = 0; u64 subnodes = 0, nodes = 0;
movelist_t movelist; movelist_t movelist;
move_t *move, *last; move_t *move, *last;
state_t state; state_t state;
@@ -123,7 +110,7 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output)
last = movelist.move + movelist.nmoves; last = movelist.move + movelist.nmoves;
for (move = movelist.move; move < last; ++move) { for (move = movelist.move; move < last; ++move) {
if (depth == 1) { if (depth == 1) {
nodes++; subnodes = 1;
} else { } else {
move_do_alt(pos, *move, &state); move_do_alt(pos, *move, &state);
if (depth == 2) { if (depth == 2) {
@@ -131,19 +118,17 @@ u64 perft_alt(pos_t *pos, int depth, int ply, bool output)
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves; subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
} else { } else {
subnodes = perft_alt(pos, depth - 1, ply + 1, output); subnodes = perft_alt(pos, depth - 1, ply + 1, divide);
} }
if (output && ply == 1) { move_undo_alt(pos, *move, &state);
}
nodes += subnodes;
if (ply == 1 && divide) {
char movestr[8]; char movestr[8];
printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes); printf("%s: %lu\n", move_to_str(movestr, *move, 0), subnodes);
} }
nodes += subnodes;
move_undo_alt(pos, *move, &state);
}
} }
if (output && ply == 1)
printf("Total: %lu\n", nodes);
return nodes; return nodes;
} }

View File

@@ -1,48 +0,0 @@
/* util.h - 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>
*
*/
#ifndef _UTIL_H
#define _UTIL_H
#include <stdio.h>
#include <stdlib.h>
#include <bug.h>
#include "chessdefs.h"
#undef safe_malloc
#undef safe_free
/* force BUG_ON, to get a program abort for failed malloc/free
*/
#pragma push_macro("BUG_ON")
#undef BUG_ON
#define BUG_ON
#define safe_malloc(size) ({ \
void *_ret = malloc(size); \
bug_on(_ret == NULL); \
_ret; \
})
#define safe_free(ptr) do { \
bug_on(ptr == NULL); \
free(ptr); \
} while (0)
/* restore BUG_ON
*/
#pragma pop_macro("BUG_ON")
#endif /* UTIL_H */

View File

@@ -33,7 +33,7 @@ int main(int __unused ac, __unused char**av)
setlinebuf(stdout); /* line-buffered stdout */ setlinebuf(stdout); /* line-buffered stdout */
bitboard_init(); bitboard_init();
hyperbola_init(); hq_init();
while ((fen = next_fen(ATTACK))) { while ((fen = next_fen(ATTACK))) {
//printf(">>>>> %s\n", test[i]); //printf(">>>>> %s\n", test[i]);
@@ -53,7 +53,7 @@ int main(int __unused ac, __unused char**av)
pos_set_checkers_pinners_blockers(pos); pos_set_checkers_pinners_blockers(pos);
printf("******* %s\n", cur_comment()); printf("******* line %d: %s\n", cur_line(), cur_comment());
bb_print_multi("checkers", 2, checkers, pos->checkers); bb_print_multi("checkers", 2, checkers, pos->checkers);
bb_print_multi("pinners", 2, pinners, pos->pinners); bb_print_multi("pinners", 2, pinners, pos->pinners);
bb_print_multi("blockers", 2, blockers, pos->blockers); bb_print_multi("blockers", 2, blockers, pos->blockers);

View File

@@ -18,13 +18,13 @@
#include "chessdefs.h" #include "chessdefs.h"
#include "bitboard.h" #include "bitboard.h"
#include "hyperbola-quintessence.h" #include "hq.h"
int main(int __unused ac, __unused char**av) int main(int __unused ac, __unused char**av)
{ {
char str[256]; char str[256];
bitboard_init(); bitboard_init();
hyperbola_init(); hq_init();
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
sprintf(str, "\n%#x:\n %-22s%-22s%-22s%-22s%-22s%-22s%-22s", i, sprintf(str, "\n%#x:\n %-22s%-22s%-22s%-22s%-22s%-22s%-22s", i,
"sliding", "diagonal", "antidiagonal", "file", "rank", "knight", "sliding", "diagonal", "antidiagonal", "file", "rank", "knight",

View File

@@ -28,20 +28,9 @@ struct fentest {
char *comment; char *comment;
char *fen; char *fen;
} fentest[] = { } fentest[] = {
/************************************************************ /******************************************************************
* TEMP TESTS BELOW - only run them (till sentinel below) * * TEMP TESTS BELOW - only run them (till sentinel below) *
************************************************************/ ******************************************************************/
/*
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
* "startpos + 1.e4 e5 2.Nf3 Nc6 3.Bb5 a6 4.Ba4",
* "r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 1 4"
* },
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
* "",
* "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"
* },
*/
/****************************************************************** /******************************************************************
* DO NOT DELETE NEXT LINE - sentinel entry for temp tests above. * * DO NOT DELETE NEXT LINE - sentinel entry for temp tests above. *
@@ -87,20 +76,6 @@ struct fentest {
"illegal e.p. bug perft at depth 4", "illegal e.p. bug perft at depth 4",
"1nbqkbn1/ppp2ppp/4p3/r1rpP3/6K1/P7/1PPP1PPP/RNBQ1BNR b - - 1 2" "1nbqkbn1/ppp2ppp/4p3/r1rpP3/6K1/P7/1PPP1PPP/RNBQ1BNR b - - 1 2"
}, },
/*
* { __LINE__, MOVEGEN | MOVEDO | PERFT,
* "illegal e.p. bug perft depth 3",
* "1nbqkbn1/ppp2ppp/4p3/2rpP3/r5K1/P7/1PPP1PPP/RNBQ1BNR w - - 2 3"
* },
* { __LINE__, MOVEGEN | MOVEDO | PERFT,
* "illegal e.p. bug perft depth 2",
* "1nbqkbn1/ppp2ppp/4p3/2rpP3/r4PK1/P7/1PPP2PP/RNBQ1BNR b - - 0 3"
* },
* { __LINE__, MOVEGEN | MOVEDO | PERFT | PERFT,
* "illegal e.p. bug perft depth 1 - fixed",
* "1nb1kbn1/ppp2ppp/4p3/2rpP1q1/r4PK1/P7/1PPP2PP/RNBQ1BNR w - - 1 4"
* },
*/
{ __LINE__, ATTACK, { __LINE__, ATTACK,
"only 3 K moves (but impossible situation)", "only 3 K moves (but impossible situation)",
"1k6/8/8/8/8/8/8/r2K3r w - - 0 1" "1k6/8/8/8/8/8/8/r2K3r w - - 0 1"
@@ -151,24 +126,8 @@ struct fentest {
"4k3/8/8/8/7b/8/8/4K3 w - - 0 1" "4k3/8/8/8/7b/8/8/4K3 w - - 0 1"
}, },
/* /*
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, * First game moves
* "1.e3 - perft bug",
* "rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
* },
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT | PERFT,
* "1.e3 Nc6 - perft bug",
* "r1bqkbnr/pppppppp/2n5/8/8/4P3/PPPP1PPP/RNBQKBNR w KQkq - 1 2"
* },
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT | PERFT,
* "1.e3 Nc6 2.Ke2 - perft bug",
* "r1bqkbnr/pppppppp/2n5/8/8/4P3/PPPPKPPP/RNBQ1BNR b kq - 2 2"
* },
* { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
* "1.e3 Nc6 2.Ke2 Nd4+ - perft bug",
* "r1bqkbnr/pppppppp/8/8/3n4/4P3/PPPPKPPP/RNBQ1BNR w kq - 3 3"
* },
*/ */
// First game moves
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"startpos", "startpos",
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
@@ -189,10 +148,11 @@ struct fentest {
"startpos + 1.e4 e5 2.Nf3 Nc6 3.Bb5 a6 4.Ba4", "startpos + 1.e4 e5 2.Nf3 Nc6 3.Bb5 a6 4.Ba4",
"r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 1 4" "r1bqkbnr/1ppp1ppp/p1n5/4p3/B3P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 1 4"
}, },
// castling test /******************
// both can castle queen only * Castling tests *
******************/
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"no Q castling", "both can castle K-side",
"r3k2r/8/3B4/8/8/3b4/8/R3K2R w KQkq - 0 1" "r3k2r/8/3B4/8/8/3b4/8/R3K2R w KQkq - 0 1"
}, },
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
@@ -200,30 +160,27 @@ struct fentest {
"r3k2r/8/3BB3/8/8/3bb3/8/R3K2R w KQkq - 0 1" "r3k2r/8/3BB3/8/8/3bb3/8/R3K2R w KQkq - 0 1"
}, },
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"", "No castling for white",
"r2bkb1r/8/8/8/8/3bb3/8/R2BKB1R w KQkq - 0 1" "r2bkb1r/8/8/8/8/3bb3/8/R2BKB1R w KQkq - 0 1"
}, },
//
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"4 castle possible, only K+R", "4 castling possible, only K+R",
"r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1" "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1"
}, },
// /*
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, * { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"only kings on A1/A8, white to play", * "only kings on A1/A8, white to play",
"k7/8/8/8/8/8/8/K7 w - - 0 1" * "k7/8/8/8/8/8/8/K7 w - - 0 1"
}, * },
// */
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"only one move possible (Pf2xBg3)", "only one move possible (Pf2xBg3)",
"k7/8/8/1p1p4/pPpPp3/P1PpPpb1/NBNP1P2/KBB1B3 w - - 0 1" "k7/8/8/1p1p4/pPpPp3/P1PpPpb1/NBNP1P2/KBB1B3 w - - 0 1"
}, },
//
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"only 2 moves possible (Ph5xg6 e.p., Ph5-h6)", "only 2 moves possible (Ph5xg6 e.p., Ph5-h6)",
"k7/8/8/1p1p2pP/pPpPp3/P1PpPp2/NBNP1P2/KBB1B3 w - g6 0 1" "k7/8/8/1p1p2pP/pPpPp3/P1PpPp2/NBNP1P2/KBB1B3 w - g6 0 1"
}, },
//
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"2 Kings, W/B/ pawns on 7th for promotion", "2 Kings, W/B/ pawns on 7th for promotion",
"k4n2/4P3/8/8/8/8/4p3/K4N2 w - - 0 1" "k4n2/4P3/8/8/8/8/4p3/K4N2 w - - 0 1"
@@ -249,38 +206,46 @@ struct fentest {
"", "",
"6k1/6pp/R2p4/p1p5/8/1P1r3P/6P1/6K1 b - - 3 3" "6k1/6pp/R2p4/p1p5/8/1P1r3P/6P1/6K1 b - - 3 3"
}, },
/*************************************
* Some FEN found on talkchess forum *
*************************************/
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"https://www.talkchess.com/forum3/viewtopic.php?f=7&t=71379",
"8/6kR/8/8/8/bq6/1rqqqqqq/K1nqnbrq b - - 0 1"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"from https://www.talkchess.com/forum/viewtopic.php?t=42463",
"rnbqkb1r/pp1p1ppp/2p5/4P3/2B5/8/PPP1NnPP/RNBQK2R w KQkq - 0 6"
},
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
"from https://talkchess.com/viewtopic.php?t=74153",
"8/p7/8/1P6/K1k3p1/6P1/7P/8 w - - 0 1", // Perft(8) == 8,103,790
},
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
"from https://talkchess.com/viewtopic.php?t=74153",
"8/5p2/8/2k3P1/p3K3/8/1P6/8 b - - 0 1" // Perft(8) == 64,451,405
},
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
"from https://talkchess.com/viewtopic.php?t=74153",
"n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1" // Perft(6) == 71,179,139
},
{ __LINE__, MOVEGEN | MOVEDO | PERFT,
"from https://talkchess.com/viewtopic.php?t=74153",
"r3k2r/p6p/8/B7/1pp1p3/3b4/P6P/R3K2R w KQkq - 0 1" // Perft(6) == 77,054,993
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"from https://talkchess.com/viewtopic.php?t=74153",
"r3k2r/pb3p2/5npp/n2p4/1p1PPB2/6P1/P2N1PBP/R3K2R w KQkq - 0 1" // Perft(5) == 29,179,893
},
// some of tests below are from: /*****************************************************
// - Rodent IV * some of tests below are from: *
// - https://www.chessprogramming.net/perfect-perft/ * https://www.chessprogramming.net/perfect-perft/ *
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, *****************************************************/
"",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"", "",
"8/2p5/3p4/Kp5r/1R3p1k/8/4P1P1/8 w - - 0 1" "8/2p5/3p4/Kp5r/1R3p1k/8/4P1P1/8 w - - 0 1"
}, },
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"", "",
"1rbqk1nr/p3ppbp/2np2p1/2p5/1p2PP2/3PB1P1/PPPQ2BP/R2NK1NR b KQk - 0 1" "1rbqk1nr/p3ppbp/2np2p1/2p5/1p2PP2/3PB1P1/PPPQ2BP/R2NK1NR b KQk - 0 1"
@@ -301,26 +266,6 @@ struct fentest {
"", "",
"n1q1r1k1/3b3n/p2p1bp1/P1pPp2p/2P1P3/2NBB2P/3Q1PK1/1R4N1 b - - 0 1" "n1q1r1k1/3b3n/p2p1bp1/P1pPp2p/2P1P3/2NBB2P/3Q1PK1/1R4N1 b - - 0 1"
}, },
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"",
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26"
},
{ __LINE__, FEN | MOVEGEN | MOVEDO | PERFT, { __LINE__, FEN | MOVEGEN | MOVEDO | PERFT,
"", "",
"2r5/8/1n6/1P1p1pkp/p2P4/R1P1PKP1/8/1R6 w - - 0 1" "2r5/8/1n6/1P1p1pkp/p2P4/R1P1PKP1/8/1R6 w - - 0 1"
@@ -410,6 +355,80 @@ struct fentest {
"simple movedo/undo: only 2 W knights", "simple movedo/undo: only 2 W knights",
"5n2/1k6/8/8/5K2/8/P7/1N6 w - - 0 1" "5n2/1k6/8/8/5K2/8/P7/1N6 w - - 0 1"
}, },
/*****************************************************
* test from Rodent III *
* https://github.com/nescitus/sources/src/uci.c *
* "taken from DiscoCheck by Lucas Braeschcoming" *
*****************************************************/
{ __LINE__, MOVEDO | PERFT,
"1.e4 c5 2.Nf3 Nc6",
"r1bqkbnr/pp1ppppp/2n5/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq -",
},
{ __LINE__, MOVEDO | PERFT,
"multiple captures (kiwipete)",
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -",
},
{ __LINE__, MOVEDO | PERFT,
"rook endgame",
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -",
},
{ __LINE__, MOVEDO | PERFT,
"",
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19",
},
{ __LINE__, MOVEDO | PERFT,
"knight pseudo-sack",
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14",
},
{ __LINE__, MOVEDO | PERFT,
"pawn chain",
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14",
},
{ __LINE__, MOVEDO | PERFT,
"",
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15",
},
{ __LINE__, MOVEDO | PERFT,
"",
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13",
},
{ __LINE__, MOVEDO | PERFT,
"attack for pawn",
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16",
},
{ __LINE__, MOVEDO | PERFT,
"exchange sack",
"4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17",
},
{ __LINE__, MOVEDO | PERFT,
"",
"2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11",
},
{ __LINE__, MOVEDO | PERFT,
"white pawn center",
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16",
},
{ __LINE__, MOVEDO | PERFT,
"",
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22",
},
{ __LINE__, MOVEDO | PERFT,
"",
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18",
},
{ __LINE__, MOVEDO | PERFT,
"endgame",
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22",
},
{ __LINE__, MOVEDO | PERFT,
"both queens en-prise",
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26",
},
/*****************************************************
* broken FEN *
*****************************************************/
{ __LINE__, FEN, { __LINE__, FEN,
"legal EP", "legal EP",
"4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 1" "4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 1"

View File

@@ -1,31 +0,0 @@
#include <stdio.h>
#include "debug.h"
#include "../src/fen.h"
#include "../src/move.h"
int main(int ac, char**av)
{
pos_t *pos;
debug_init(5, stderr, true);
piece_pool_init();
moves_pool_init();
pos_pool_init();
pos = pos_get();
if (ac == 1) {
fen2pos(pos, "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2");
//pos_startpos(pos);
} else {
fen2pos(pos, av[1]);
}
//printf("turn = %d opponent = %d\n", pos->turn, OPPONENT(pos->turn));
moves_gen_all(pos);
pos_print(pos);
pos_pieces_print(pos);
moves_print(pos, M_PR_SEPARATE);
//bitboard_print2(castle_squares[0].controlled, castle_squares[1].controlled);
//bitboard_print2(castle_squares[0].occupied, castle_squares[1].occupied);
}

View File

@@ -224,7 +224,7 @@ int main(int __unused ac, __unused char**av)
setlinebuf(stdout); /* line-buffered stdout */ setlinebuf(stdout); /* line-buffered stdout */
bitboard_init(); bitboard_init();
hyperbola_init(); hq_init();
outfd = open_stockfish(); outfd = open_stockfish();
while ((fen = next_fen(MOVEGEN))) { while ((fen = next_fen(MOVEGEN))) {

View File

@@ -116,9 +116,9 @@ static void stockfish_fen(FILE *desc, char *fen)
} }
static u64 stockfish_perft(FILE *desc, pos_t *pos, movelist_t *movelist, static u64 stockfish_perft(FILE *desc, pos_t *pos, movelist_t *movelist,
int depth) int depth, int divide)
{ {
char *buf = NULL; char *buf = NULL, movestr[8];
u64 count, mycount = 0, fishcount; u64 count, mycount = 0, fishcount;
size_t alloc = 0; size_t alloc = 0;
ssize_t buflen; ssize_t buflen;
@@ -144,30 +144,15 @@ static u64 stockfish_perft(FILE *desc, pos_t *pos, movelist_t *movelist,
break; break;
} }
//printf("%d: %s\n", line++, buf); //printf("%d: %s\n", line++, buf);
if (sscanf(buf, "%*4s: %lu", &count) == 1) { if (sscanf(buf, "%6[a-z1-8]: %lu", movestr, &count) == 2) {
square_t from = sq_from_string(buf); //printf("read:%s movestr:%s count:%lu\n", buf, movestr, count);
square_t to = sq_from_string(buf + 2); moves[(*nmoves)++] = move_from_str(movestr);
mycount += count; mycount += count;
//printf("move found: %c%c->%c%c %s->%s count=%d\n", if (divide) {
// buf[0], buf[1], buf[2], buf[3], printf("%s: %lu\n", movestr, count);
// sq_to_string(from), sq_to_string(to), }
// count);
moves[(*nmoves)++] = move_make(from, to);
} else if (sscanf(buf, "%*5s: %lu", &count) == 1) {
square_t from = sq_from_string(buf);
square_t to = sq_from_string(buf + 2);
piece_type_t promoted = piece_t_from_char(*(buf + 4));
mycount += count;
//printf("move found: %c%c->%c%c %s->%s count=%d\n",
// buf[0], buf[1], buf[2], buf[3],
// sq_to_string(from), sq_to_string(to),
// count);
moves[(*nmoves)++] = move_make_promote(from, to, promoted);
} }
} }
//pos->moves.nmoves = nmoves;
// printf("fishcount=%d mycount=%d\n", fishcount, mycount);
free(buf); free(buf);
return mycount; return mycount;
} }
@@ -200,8 +185,6 @@ static __unused void compare_moves(movelist_t *fish, movelist_t *me)
#define t(c) move_to(c) #define t(c) move_to(c)
for (move_t *c1 = m1, *c2 = m2; (c1 - m1 < n1) || (c2 - m2 < n2);) { for (move_t *c1 = m1, *c2 = m2; (c1 - m1 < n1) || (c2 - m2 < n2);) {
// square_t f1 = move_from(*c1); square_t t1 = move_to(*c1);
// square_t f2 = move_from(*c2); square_t t2 = move_to(*c2);
/* no more move in c2 */ /* no more move in c2 */
if (c2 - m2 >= n2) { if (c2 - m2 >= n2) {
@@ -257,7 +240,7 @@ static int usage(char *prg)
{ {
fprintf(stderr, "Usage: %s [-cms][-d depth] [-p version] [-t size:\n", prg); fprintf(stderr, "Usage: %s [-cms][-d depth] [-p version] [-t size:\n", prg);
fprintf(stderr, "\t-c: do *not* print FEN comments\n"); fprintf(stderr, "\t-c: do *not* print FEN comments\n");
fprintf(stderr, "\t-d depth: perft depth (default: 6)"); fprintf(stderr, "\t-d depth: perft depth (default: 6)\n");
fprintf(stderr, "\t-m: print moves details\n"); fprintf(stderr, "\t-m: print moves details\n");
fprintf(stderr, "\t-s: use Stockfish to validate perft result\n"); fprintf(stderr, "\t-s: use Stockfish to validate perft result\n");
fprintf(stderr, "\t-t size: Transposition Table size (Mb). Default: 32\n"); fprintf(stderr, "\t-t size: Transposition Table size (Mb). Default: 32\n");
@@ -270,22 +253,23 @@ int main(int ac, char**av)
{ {
int curtest = 0; int curtest = 0;
u64 sf_count = 0, my_count; u64 sf_count = 0, my_count;
bool comment = true, sf_run = false, moves_output = false; bool comment = true, sf_run = false, divide = false;
char *fen; char *fen;
pos_t *pos = NULL, *fenpos; pos_t *pos = NULL, *fenpos;
pos_t *fishpos = pos_new(); pos_t *fishpos = pos_new();
movelist_t fishmoves; movelist_t fishmoves;
FILE *outfd = NULL; FILE *outfd = NULL;
s64 ms, lps; s64 ms, lps;
int opt, depth = 6, run = 3, tt = 32, newtt = 32; int opt, depth = 6, run = 3, tt, newtt = HASH_SIZE_DEFAULT;
struct { struct {
s64 count, ms; s64 count, countskipped, ms;
s64 minlps, maxlps; s64 minlps, maxlps;
int skipped; int skipped;
int err;
} res[3] = { } 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) { while ((opt = getopt(ac, av, "cd:mp:st:")) != -1) {
@@ -299,7 +283,7 @@ int main(int ac, char**av)
depth = 6; depth = 6;
break; break;
case 'm': case 'm':
moves_output = false; divide = true;
break; break;
case 'p': case 'p':
run = atoi(optarg); run = atoi(optarg);
@@ -321,9 +305,12 @@ int main(int ac, char**av)
} }
init_all(); init_all();
if (newtt != 32 && newtt > 1) { tt = hash_tt.mb;
printf("changing TT size from %d to %d\n", tt, newtt);
if (run & 1 && newtt != tt) {
tt_create(newtt); tt_create(newtt);
printf("changing TT size from %d to %d\n", tt, newtt);
tt = newtt; tt = newtt;
} }
printf("%s: depth:%d tt_size:%d run:%x SF:%s\n", printf("%s: depth:%d tt_size:%d run:%x SF:%s\n",
@@ -334,8 +321,6 @@ int main(int ac, char**av)
tt_info(); tt_info();
printf("\n"); printf("\n");
printf("move_t size:%lu\n", sizeof(move_t));
if (sf_run) if (sf_run)
outfd = open_stockfish(); outfd = open_stockfish();
@@ -346,11 +331,10 @@ int main(int ac, char**av)
continue; continue;
} }
curtest++; curtest++;
printf("test:%d line:%d", curtest, cur_line()); printf("test:%d line:%d fen:%s\n", curtest, cur_line(), fen);
if (comment) if (comment)
printf(" comment:%s\n", printf("\t\"%s\"\n",
*cur_comment()? cur_comment(): "no test desc"); *cur_comment()? cur_comment(): "no test desc");
printf("\t%s\n", fen);
tt_clear(); tt_clear();
@@ -358,10 +342,11 @@ int main(int ac, char**av)
if (sf_run) { if (sf_run) {
stockfish_fen(outfd, fen); stockfish_fen(outfd, fen);
clock_start(&clock); clock_start(&clock);
sf_count = stockfish_perft(outfd, fishpos, &fishmoves, depth); sf_count = stockfish_perft(outfd, fishpos, &fishmoves, depth, divide);
ms = clock_elapsed_ms(&clock); ms = clock_elapsed_ms(&clock);
if (!ms) { if (!ms) {
res[2].skipped++; res[2].skipped++;
res[2].countskipped += sf_count;
lps = 0; lps = 0;
} else { } else {
lps = sf_count * 1000l / ms; lps = sf_count * 1000l / ms;
@@ -378,10 +363,11 @@ int main(int ac, char**av)
if (run & 1) { if (run & 1) {
clock_start(&clock); clock_start(&clock);
my_count = perft(pos, depth, 1, moves_output); my_count = perft(pos, depth, 1, divide);
ms = clock_elapsed_ms(&clock); ms = clock_elapsed_ms(&clock);
if (!ms) { if (!ms) {
res[0].skipped++; res[0].skipped++;
res[0].countskipped += my_count;
lps = 0; lps = 0;
} else { } else {
lps = my_count * 1000l / ms; lps = my_count * 1000l / ms;
@@ -399,15 +385,17 @@ int main(int ac, char**av)
tt_stats(); tt_stats();
} else { } else {
printf("perft : perft:%'lu ***ERROR***\n", my_count); printf("perft : perft:%'lu ***ERROR***\n", my_count);
res[0].err++;
} }
} }
if (run & 2) { if (run & 2) {
clock_start(&clock); clock_start(&clock);
my_count = perft_alt(pos, depth, 1, moves_output); my_count = perft_alt(pos, depth, 1, divide);
ms = clock_elapsed_ms(&clock); ms = clock_elapsed_ms(&clock);
if (!ms) { if (!ms) {
res[1].skipped++; res[1].skipped++;
res[1].countskipped += my_count;
lps = 0; lps = 0;
} else { } else {
lps = my_count * 1000l / ms; lps = my_count * 1000l / ms;
@@ -424,6 +412,7 @@ int main(int ac, char**av)
my_count, ms, lps); my_count, ms, lps);
} else { } else {
printf("perft_alt : perft:%'lu ***ERROR***\n", my_count); printf("perft_alt : perft:%'lu ***ERROR***\n", my_count);
res[1].err++;
} }
} }
printf("\n"); printf("\n");
@@ -432,32 +421,32 @@ int main(int ac, char**av)
if (sf_run) { if (sf_run) {
if (!res[2].ms) if (!res[2].ms)
res[2].ms = 1; res[2].ms = 1;
printf("total Stockfish : perft:%'lums ms:%'lums lps:%'lu min:%'lu max:%'lu " printf("total Stockfish : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n", "(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].count * 1000l / res[2].ms,
res[2].minlps, res[2].maxlps, res[2].minlps, res[2].maxlps,
res[0].skipped, curtest); res[2].skipped, curtest);
} }
if (run & 1) { if (run & 1) {
if (!res[0].ms) if (!res[0].ms)
res[0].ms = 1; res[0].ms = 1;
printf("total perft : perft:%'lums ms:%'lums lps:%'lu min:%'lu max:%'lu " printf("total perft : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n", "(pos:%d skipped:%d err:%d)\n",
res[0].count, res[0].ms, res[0].count + res[0].countskipped, res[0].ms,
res[0].count * 1000l / res[0].ms, res[0].count * 1000l / res[0].ms,
res[0].minlps, res[0].maxlps, res[0].minlps, res[0].maxlps,
res[0].skipped, curtest); curtest, res[0].skipped, res[0].err);
} }
if (run & 2) { if (run & 2) {
if (!res[1].ms) if (!res[1].ms)
res[1].ms = 1; res[1].ms = 1;
printf("total perft_alt : perft:%'lums ms:%'lums lps:%'lu min:%'lu max:%'lu " printf("total perft_alt : perft:%'lu ms:%'lu lps:%'lu min:%'lu max:%'lu "
"(skipped %d/%d)\n", "(pos:%d skipped:%d err:%d)\n",
res[1].count, res[1].ms, res[1].count + res[1].countskipped, res[1].ms,
res[1].count * 1000l / res[1].ms, res[1].count * 1000l / res[1].ms,
res[1].minlps, res[1].maxlps, res[1].minlps, res[1].maxlps,
res[0].skipped, curtest); curtest, res[1].skipped, res[1].err);
} }
return 0; return 0;
} }

View File

@@ -29,50 +29,6 @@
#include "move-gen.h" #include "move-gen.h"
#include "search.h" #include "search.h"
// #include "common-test.h"
static move_t move_in_movelist(movelist_t *ml, square_t from, square_t to, piece_type_t pt)
{
const int nmoves = ml->nmoves;
const move_t *moves = ml->move;
int movenum = 0;
move_t move;
for (movenum = 0; movenum < nmoves; ++movenum) {
move = moves[movenum];
printf("compare %s%s to %s%s pt=%d ",
sq_to_string(from), sq_to_string(to),
sq_to_string(move_from(move)),
sq_to_string(move_to(move)),
pt
);
if (move_from(move) == from && move_to(move) == to) {
printf("HIT!\n");
if (pt != NO_PIECE_TYPE && move_promoted(move) != pt)
continue;
printf("move_in_movelist(%s%s) found from=%s to=%s\n",
sq_to_string(from), sq_to_string(to),
sq_to_string(move_from(move)),
sq_to_string(move_to(move)));
return move;
} else
puts("");
}
return MOVE_NONE;
}
static move_t move_from_str(pos_t *pos, const char *move)
{
movelist_t movelist;
square_t from = sq_from_string(move);
square_t to = sq_from_string(move + 2);
piece_type_t promoted = piece_t_from_char(*(move + 4));
printf("from=%o to=%o promoted=%d\n", from, to, promoted);
pos_set_checkers_pinners_blockers(pos);
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
return move_in_movelist(&movelist, from, to, promoted);
}
static void pr_entry(hentry_t *entry) static void pr_entry(hentry_t *entry)
{ {
if (!entry) if (!entry)
@@ -91,7 +47,7 @@ int main()
hentry_t *entry; hentry_t *entry;
move_t move; move_t move;
state_t state; state_t state;
//movelist_t movelist; movelist_t movelist;
const char *moves_array[] = { const char *moves_array[] = {
"e2e4 e7e5 g1f3 b8c6", "e2e4 e7e5 g1f3 b8c6",
@@ -113,10 +69,12 @@ int main()
depth++; depth++;
printf("%s ", token); printf("%s ", token);
//pos_set_checkers_pinners_blockers(pos); move = move_from_str(token);
//pos_legal(pos, pos_gen_pseudo(pos, &movelist)); pos_set_checkers_pinners_blockers(pos);
move = move_from_str(pos, token); pos_legal(pos, pos_gen_pseudo(pos, &movelist));
printf("move: %s\n", move_to_str(buf, move, 0)); printf("move: %s\n", move_to_str(buf, move, 0));
move = move_find_in_movelist(move, &movelist);
if (move != MOVE_NONE) {
move_do(pos, move, &state); move_do(pos, move, &state);
if ((entry = tt_probe_perft(pos->key, depth))) { if ((entry = tt_probe_perft(pos->key, depth))) {
printf("tt hit: depth=%d val=%lu", printf("tt hit: depth=%d val=%lu",
@@ -126,6 +84,7 @@ int main()
tt_store_perft(pos->key, i + 1, depth); tt_store_perft(pos->key, i + 1, depth);
printf("tt store: depth=%d val=%lu", depth, (u64)i * 123); printf("tt store: depth=%d val=%lu", depth, (u64)i * 123);
}; };
}
token = strtok(NULL, " \t"); token = strtok(NULL, " \t");
} }