Compare commits
76 Commits
e7d69d7ce4
...
brlib-swit
| Author | SHA1 | Date | |
|---|---|---|---|
| 345834159a | |||
| 09633a4287 | |||
| cb9c81e8f9 | |||
| 072f3ced9b | |||
| 77bde22d00 | |||
| e2d32a7300 | |||
| 01c5765888 | |||
| a0ccad58e5 | |||
| be790056f6 | |||
| e0da38e697 | |||
| 11d3501a35 | |||
| 48b5420830 | |||
| f27b649503 | |||
| 605ef7d201 | |||
| aa1e9fdeda | |||
| d3c78cb0af | |||
| 4ff9df9369 | |||
| b3fde55107 | |||
| f2d4f07069 | |||
| b855ba59aa | |||
| 20403a0795 | |||
| c7e2aec77c | |||
| 754b011d05 | |||
| e2a3563fce | |||
| d852e0bc1d | |||
| 3de87daa5a | |||
| b5ed42746e | |||
| 0ca495576d | |||
| ed9b9cc646 | |||
| 88d2d4061f | |||
| 9932a64c97 | |||
| af1f5db507 | |||
| d76c10797a | |||
| 36aa34a38b | |||
| d9f03acb02 | |||
| 683b6ad66b | |||
| b1e6461f6f | |||
| 65f1bef987 | |||
| 23e49f463e | |||
| 48319cf21a | |||
| 0b787c8a90 | |||
| 4bca805404 | |||
| 0df87ff41c | |||
| 892bdcd004 | |||
| 120a459206 | |||
| 7952a34c88 | |||
| 531bfa4fb0 | |||
| 12f972e152 | |||
| 183e9ef2be | |||
| 6f7a04cc89 | |||
| a08b006b98 | |||
| 8857dec6cd | |||
| aa7cb11056 | |||
| fe5b21aad9 | |||
| bab3ea95b9 | |||
| 09ceca44e5 | |||
| 1e4af66379 | |||
| 5bd8f9042a | |||
| 373a73cb52 | |||
| 9c6830bc56 | |||
| 9b25a6ba8c | |||
| 1154f141c9 | |||
| cb94ca52b9 | |||
| 6f3570ef40 | |||
| d9b42e2b43 | |||
| 8036b289a6 | |||
| e1570fa34a | |||
| aaa9cb8690 | |||
| 05a64ec742 | |||
| 6b2c1702f6 | |||
| b582798751 | |||
| 097dae84d6 | |||
| da0ee468e0 | |||
| bf520b6c71 | |||
| 96c342b3d4 | |||
| c90cc39383 |
3
.dir-locals.el
Normal file
3
.dir-locals.el
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
((nil . ((compile-command . (concat "make -C "
|
||||||
|
(vc-root-dir)
|
||||||
|
" -k -j2")))))
|
||||||
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,16 +1,17 @@
|
|||||||
core
|
core
|
||||||
vgcore.*
|
vgcore.*
|
||||||
GPATH
|
|
||||||
GRTAGS
|
|
||||||
GTAGS
|
|
||||||
fen
|
|
||||||
pool
|
|
||||||
piece
|
|
||||||
move
|
|
||||||
bits
|
|
||||||
eval
|
|
||||||
debug
|
|
||||||
bodichess
|
|
||||||
*.s
|
*.s
|
||||||
/test/
|
*.i
|
||||||
|
*.old
|
||||||
|
*.save
|
||||||
|
/.ccls-root
|
||||||
|
/.ccls-cache/
|
||||||
/obj/
|
/obj/
|
||||||
|
/lib/
|
||||||
|
/libobj/
|
||||||
|
/bin/
|
||||||
|
/dep/
|
||||||
|
/tmp/
|
||||||
|
/notused/
|
||||||
|
valgrind.out
|
||||||
|
compile_commands.json
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "brlib"]
|
||||||
|
path = brlib
|
||||||
|
url = ../brlib.git
|
||||||
12
FENTESTS.txt
12
FENTESTS.txt
@@ -1,12 +0,0 @@
|
|||||||
4k3/4p3/8/b7/1BR1p2p/1Q3P2/5N2/4K3 w - - 0 1
|
|
||||||
r1bq1rk1/pppp1ppp/2n2n2/4p3/2B1P3/3PPN2/PPP3PP/RN1QK2R b KQ - 1 7
|
|
||||||
6k1/6pp/R2p4/p1p5/8/1P1r3P/6P1/6K1 b - - 3 37
|
|
||||||
|
|
||||||
# both can castle queen only
|
|
||||||
r3k2r/8/3B4/8/8/3b4/8/R3K2R w KQkq - 0 1
|
|
||||||
r3k2r/8/3BB3/8/8/3bb3/8/R3K2R w KQkq - 0 1
|
|
||||||
r2bkb1r/8/8/8/8/3bb3/8/R2BKB1R w KQkq - 0 1
|
|
||||||
|
|
||||||
# illegal positions
|
|
||||||
4k3/8/8/8/7b/8/8/4K3 b - - 0 1
|
|
||||||
2r1k3/3P4/8/8/8/8/8/4K3 w - - 0 1
|
|
||||||
351
Makefile
351
Makefile
@@ -1,111 +1,300 @@
|
|||||||
# Makefile - GNU make only.
|
# Makefile - GNU make only.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 Bruno Raoult ("br")
|
# Copyright (C) 2021-2023 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.
|
||||||
# * 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.htmlL>.
|
# 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>
|
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
#
|
#
|
||||||
|
|
||||||
BINDIR := ./bin
|
SHELL := /bin/bash
|
||||||
SRCDIR := ./src
|
CC := gcc
|
||||||
OBJDIR := ./obj
|
LD := ld
|
||||||
DEPS := make.deps
|
BEAR := bear
|
||||||
|
TOUCH := touch
|
||||||
|
RM := rm
|
||||||
|
RMDIR := rmdir
|
||||||
|
|
||||||
SRC=$(wildcard $(SRCDIR)/*.c)
|
SRCDIR := ./src
|
||||||
INC=$(wildcard $(SRCDIR)/*.h)
|
INCDIR := ./include
|
||||||
SRC_S=$(notdir $(SRC))
|
OBJDIR := ./obj
|
||||||
|
|
||||||
CC=gcc
|
LIBSRCDIR := ./libsrc
|
||||||
|
LIBOBJDIR := ./libobj
|
||||||
|
|
||||||
.SECONDEXPANSION:
|
BINDIR := ./bin
|
||||||
OBJ=$(addprefix $(OBJDIR)/,$(SRC_S:.c=.o))
|
LIBDIR := ./lib
|
||||||
BIN=fen pool piece move debug eval bits bodichess
|
DEPDIR := ./dep
|
||||||
|
|
||||||
LIBS = -lreadline -lncurses
|
CCLSROOT := .ccls-root
|
||||||
CFLAGS += -std=gnu99
|
CCLSFILE := compile_commands.json
|
||||||
|
|
||||||
#CFLAGS += -O2
|
SRC := $(wildcard $(SRCDIR)/*.c) # project sources
|
||||||
CFLAGS += -g
|
SRC_FN := $(notdir $(SRC)) # source basename
|
||||||
CFLAGS += -Wall
|
OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
|
||||||
CFLAGS += -Wextra
|
|
||||||
CFLAGS += -march=native
|
|
||||||
#CFLAGS += -pedantic
|
|
||||||
#CFLAGS += -Wno-pointer-arith
|
|
||||||
#CFLAGS += -Werror
|
|
||||||
CFLAGS += -Wmissing-declarations
|
|
||||||
|
|
||||||
##################################### DEBUG flags
|
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c) # lib sources
|
||||||
CFLAGS += -DDEBUG # global
|
LIBSRC_FN := $(notdir $(LIBSRC)) # lib sources basename
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
LIBOBJ := $(addprefix $(LIBOBJDIR)/,$(LIBSRC_FN:.c=.o)) # and lib obj ones
|
||||||
CFLAGS += -DDEBUG_FEN # FEN decoding
|
|
||||||
CFLAGS += -DDEBUG_MOVE # move generation
|
|
||||||
CFLAGS += -DDEBUG_EVAL # eval functions
|
|
||||||
CFLAGS += -DDEBUG_PIECE # piece list management
|
|
||||||
#CFLAGS += -DDEBUG_BITS # bits functions (take care !)
|
|
||||||
|
|
||||||
#CFLAGS += -DDEBUG_EVAL # sleep 1 sec within main loop (SIGINTR test)
|
LIB := br_$(shell uname -m) # library name
|
||||||
#CFLAGS += -DDEBUG_EVAL2 # eval 2
|
SLIB := $(addsuffix .a, $(LIBDIR)/lib$(LIB)) # static lib
|
||||||
#CFLAGS += -DDEBUG_EVAL3 # eval 3
|
DLIB := $(addsuffix .so, $(LIBDIR)/lib$(LIB)) # dynamic lib
|
||||||
#CFLAGS += -DDEBUG_MEM # malloc
|
|
||||||
|
|
||||||
.PHONY: all cflags clean
|
DEP_FN := $(SRC_FN) $(LIBSRC_FN)
|
||||||
|
DEP := $(addprefix $(DEPDIR)/,$(DEP_FN:.c=.d))
|
||||||
|
|
||||||
compile: cflags $(OBJ) $(BIN)
|
TARGET_FN := brchess
|
||||||
|
TARGET := $(addprefix $(BINDIR)/,$(TARGET_FN))
|
||||||
|
|
||||||
cflags:
|
LDFLAGS := -L$(LIBDIR)
|
||||||
@echo CFLAGS used: $(CFLAGS)
|
LIBS := -l$(LIB) -lreadline -lncurses
|
||||||
|
|
||||||
all: clean compile
|
##################################### pre-processor flags
|
||||||
|
CPPFLAGS := -I$(INCDIR)
|
||||||
|
#CPPFLAGS += -DDEBUG # global
|
||||||
|
CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
||||||
|
#CPPFLAGS += -DDEBUG_DEBUG_C # enable verbose log() settings
|
||||||
|
CPPFLAGS += -DDEBUG_POOL # memory pools management
|
||||||
|
CPPFLAGS += -DDEBUG_FEN # FEN decoding
|
||||||
|
CPPFLAGS += -DDEBUG_MOVE # move generation
|
||||||
|
CPPFLAGS += -DDEBUG_EVAL # eval functions
|
||||||
|
CPPFLAGS += -DDEBUG_PIECE # piece list management
|
||||||
|
CPPFLAGS += -DDEBUG_SEARCH # move search
|
||||||
|
|
||||||
$(DEPS): $(SRC) $(INC)
|
# remove extraneous spaces (due to spaces before comments)
|
||||||
@echo generating dependancies.
|
CPPFLAGS := $(strip $(CPPFLAGS))
|
||||||
@$(CC) -MM $(SRC) > $@
|
|
||||||
@sed -i "s|\(.*\.o\):|${OBJDIR}/\0:|" $@
|
|
||||||
|
|
||||||
include $(DEPS)
|
##################################### compiler flags
|
||||||
|
CFLAGS := -std=gnu11
|
||||||
|
#CFLAGS += -O2
|
||||||
|
CFLAGS += -g
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wextra
|
||||||
|
CFLAGS += -march=native
|
||||||
|
CFLAGS += -Wmissing-declarations
|
||||||
|
# for gprof
|
||||||
|
# CFLAGS += -pg
|
||||||
|
# Next one may be useful for valgrind (when invalid instructions)
|
||||||
|
# CFLAGS += -mno-tbm
|
||||||
|
|
||||||
clean:
|
CFLAGS := $(strip $(CFLAGS))
|
||||||
rm -rf $(OBJ) core $(BIN)
|
|
||||||
|
|
||||||
#$(OBJ): $(OBJDIR)/%.o: $(SRCDIR)/%.c
|
##################################### archiver/linker/dependency flags
|
||||||
# @mkdir -p $(@D)
|
ARFLAGS := rcs
|
||||||
# $(CC) -c $(CFLAGS) -o $@ $<
|
LDFLAGS := -L$(LIBDIR)
|
||||||
$(OBJDIR)/%.o:
|
DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$*.d
|
||||||
@mkdir -p $(@D)
|
|
||||||
@echo compiling $@.
|
|
||||||
@$(CC) -c $(CFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
#fen: CFLAGS+=-DBIN_$$@
|
##################################### General targets
|
||||||
#$(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
.PHONY: all compile clean cleanall
|
||||||
# @echo compiling $@.
|
|
||||||
# @$(CC) -DBIN_$@ $(CFLAGS) $^ $(LIBS) -o $@
|
|
||||||
|
|
||||||
# TODO: find a better dependancy graph
|
all: $(TARGET)
|
||||||
$(BIN): $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
|
||||||
@echo compiling $@.
|
|
||||||
@echo NEED_TO_CHANGE_THIS=$^
|
|
||||||
@$(CC) -DBIN_$@ $(CFLAGS) $^ $(LIBS) -o $@
|
|
||||||
|
|
||||||
#pool: CFLAGS+=-DPOOLBIN
|
compile: libobjs objs
|
||||||
#pool: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
|
||||||
# $(CC) $(CFLAGS) $^ -o $@
|
|
||||||
|
|
||||||
# piece: CFLAGS+=-DPIECEBIN
|
clean: cleandep cleanobj cleanlib cleanlibobj cleanbin
|
||||||
# piece: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
|
||||||
# $(CC) $(CFLAGS) $^ -o $@
|
|
||||||
|
|
||||||
# move: CFLAGS+=-DMOVEBIN
|
cleanall: clean cleandepdir cleanobjdir cleanlibdir cleanlibobjdir cleanbindir
|
||||||
# move: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
|
||||||
# $(CC) $(CFLAGS) $^ -o $@
|
|
||||||
|
|
||||||
# debug: CFLAGS+=-DDEBUGBIN
|
##################################### cleaning functions
|
||||||
# debug: $$(subst $(OBJDIR)/$$@.o,,$(OBJ)) $(SRCDIR)/$$@.c
|
# rmfiles - deletes a list of files in a directory if they exist.
|
||||||
# $(CC) $(CFLAGS) $^ -o $@
|
# $(1): the directory
|
||||||
|
# $(2): the list of files to delete
|
||||||
|
# $(3): The string to include in action output - "cleaning X files."
|
||||||
|
# see: https://stackoverflow.com/questions/6783243/functions-in-makefiles
|
||||||
|
#
|
||||||
|
# Don't use wildcard like "$(DIR)/*.o", so we can control mismatches between
|
||||||
|
# list and actual files in directory.
|
||||||
|
# See rmdir below.
|
||||||
|
define rmfiles
|
||||||
|
@#echo "rmfiles=+$(1)+"
|
||||||
|
$(eval $@_EXIST = $(wildcard $(1)))
|
||||||
|
@#echo "existfile=+${$@_EXIST}+"
|
||||||
|
@if [[ -n "${$@_EXIST}" ]]; then \
|
||||||
|
echo "cleaning $(2) files." ; \
|
||||||
|
$(RM) ${$@_EXIST} ; \
|
||||||
|
fi
|
||||||
|
endef
|
||||||
|
|
||||||
#.PHONY: bits
|
# rmdir - deletes a directory if it exists.
|
||||||
#bits2: src/bits.c
|
# $(1): the directory
|
||||||
# $(CC) $(CFLAGS) -S $^ -o $@.s
|
# $(2): The string to include in action output - "removing X dir."
|
||||||
# $(CC) $(CFLAGS) $^ -o $@
|
#
|
||||||
|
# Don't use $(RM) -rf, to control unexpected dep files.
|
||||||
|
# See rmfile above.
|
||||||
|
define rmdir
|
||||||
|
@#echo "rmdir +$(1)+"
|
||||||
|
$(eval $@_EXIST = $(wildcard $(1)))
|
||||||
|
@#echo "existdir=+${$@_EXIST}+"
|
||||||
|
@if [[ -n "${$@_EXIST}" ]]; then \
|
||||||
|
echo "removing $(2) dir." ; \
|
||||||
|
$(RMDIR) ${$@_EXIST} ; \
|
||||||
|
fi
|
||||||
|
endef
|
||||||
|
|
||||||
|
##################################### dirs creation
|
||||||
|
.PHONY: alldirs
|
||||||
|
|
||||||
|
ALLDIRS := $(DEPDIR) $(OBJDIR) $(LIBDIR) $(LIBOBJDIR) $(BINDIR)
|
||||||
|
|
||||||
|
alldirs: $(ALLDIRS)
|
||||||
|
|
||||||
|
# Here, we have something like:
|
||||||
|
# a: a
|
||||||
|
# a will be built if (1) older than a, or (2) does not exist. Here only (2).
|
||||||
|
$(ALLDIRS): $@
|
||||||
|
@echo creating $@ directory.
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
##################################### Dependencies files
|
||||||
|
.PHONY: cleandep cleandepdir
|
||||||
|
|
||||||
|
-include $(wildcard $(DEP))
|
||||||
|
|
||||||
|
# Don't use $(DEPDIR)/*.d, to control mismatches between dep and src files.
|
||||||
|
# See second rule below.
|
||||||
|
cleandep:
|
||||||
|
$(call rmfiles,$(DEP),depend)
|
||||||
|
@#echo cleaning dependency files.
|
||||||
|
@#$(RM) -f $(DEP)
|
||||||
|
|
||||||
|
cleandepdir:
|
||||||
|
$(call rmdir,$(DEPDIR),depend)
|
||||||
|
@#[ -d $(DEPDIR) ] && echo cleaning depend files && $(RM) -f $(DEP) || true
|
||||||
|
|
||||||
|
##################################### brchess objects
|
||||||
|
.PHONY: objs cleanobj cleanobjdir
|
||||||
|
|
||||||
|
objs: $(OBJ)
|
||||||
|
|
||||||
|
cleanobj:
|
||||||
|
$(call rmfiles,$(OBJ),object)
|
||||||
|
|
||||||
|
cleanobjdir: cleanobj
|
||||||
|
$(call rmdir,$(OBJDIR),objects)
|
||||||
|
|
||||||
|
# The part right of '|' are "order-only prerequisites": They are build as
|
||||||
|
# "normal" ones, but do not imply to rebuild target.
|
||||||
|
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(DEPDIR)
|
||||||
|
@echo compiling brchess $< "->" $@.
|
||||||
|
@$(CC) -c $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
##################################### brlib objects
|
||||||
|
.PHONY: libobjs cleanlibobj cleanlibobjdir
|
||||||
|
|
||||||
|
libobjs: $(LIBOBJ)
|
||||||
|
|
||||||
|
cleanlibobj:
|
||||||
|
$(call rmfiles,$(LIBOBJ),brlib object)
|
||||||
|
|
||||||
|
cleanlibobjdir:
|
||||||
|
$(call rmdir,$(LIBOBJDIR),brlib objects)
|
||||||
|
|
||||||
|
$(LIBOBJDIR)/%.o: $(LIBSRCDIR)/%.c | $(LIBOBJDIR) $(DEPDIR)
|
||||||
|
@echo compiling library $< "->" $@.
|
||||||
|
$(CC) -c $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
##################################### brlib libraries
|
||||||
|
.PHONY: libs cleanlib cleanlibdir
|
||||||
|
|
||||||
|
cleanlib:
|
||||||
|
$(call rmfiles,$(DLIB) $(SLIB),library)
|
||||||
|
|
||||||
|
cleanlibdir:
|
||||||
|
$(call rmdir,$(LIBDIR),libraries)
|
||||||
|
|
||||||
|
libs: $(DLIB) $(SLIB)
|
||||||
|
|
||||||
|
$(DLIB): CFLAGS += -fPIC
|
||||||
|
$(DLIB): LDFLAGS += -shared
|
||||||
|
$(DLIB): $(LIBOBJ) | $(LIBDIR)
|
||||||
|
@echo building $@ shared library.
|
||||||
|
@$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
$(SLIB): $(LIBOBJ) | $(LIBDIR)
|
||||||
|
@echo building $@ static library.
|
||||||
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
|
|
||||||
|
##################################### brchess binaries
|
||||||
|
.PHONY: targets cleanbin cleanbindir
|
||||||
|
|
||||||
|
targets: $(TARGET)
|
||||||
|
|
||||||
|
cleanbin:
|
||||||
|
$(call rmfiles,$(TARGET),binary)
|
||||||
|
|
||||||
|
cleanbindir:
|
||||||
|
$(call rmdir,$(BINDIR),binaries)
|
||||||
|
|
||||||
|
# We don't use static lib, but we could build it here
|
||||||
|
$(TARGET): $(DLIB) $(OBJ) | $(BINDIR) $(SLIB)
|
||||||
|
@echo generating $@ executable.
|
||||||
|
@$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
##################################### pre-processed (.i) and assembler (.s) output
|
||||||
|
%.i: %.c
|
||||||
|
@echo generating $@
|
||||||
|
@$(CC) -E $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.s: %.c
|
||||||
|
@echo generating $@
|
||||||
|
@$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
##################################### LSP (ccls)
|
||||||
|
.PHONY: ccls
|
||||||
|
|
||||||
|
ccls: $(CCLSFILE)
|
||||||
|
|
||||||
|
$(CCLSROOT):
|
||||||
|
@echo creating project root file.
|
||||||
|
@$(TOUCH) $@
|
||||||
|
|
||||||
|
# generate compile_commands.json.
|
||||||
|
# Need to add includes and Makefile dependencies.
|
||||||
|
# also, if cclsfile is newer than sources, no need to clean objects file
|
||||||
|
# (and to run bear).
|
||||||
|
# maybe run cleanobj cleanlibobj in commands ?
|
||||||
|
$(CCLSFILE): cleanobj cleanlibobj $(SRC) $(LIBSRC) | $(CCLSROOT)
|
||||||
|
@echo "Generating ccls compile commands file ($@)."
|
||||||
|
@$(BEAR) -- make compile
|
||||||
|
|
||||||
|
#.PHONY: bear
|
||||||
|
#bear: cleanobj cleanlibobj Makefile | $(CCLSROOT)
|
||||||
|
# @$(BEAR) -- make compile
|
||||||
|
|
||||||
|
##################################### valgrind (mem check)
|
||||||
|
.PHONY: memcheck
|
||||||
|
|
||||||
|
VALGRIND = valgrind
|
||||||
|
VALGRINDFLAGS = --leak-check=full --show-leak-kinds=all
|
||||||
|
VALGRINDFLAGS += --track-origins=yes --sigill-diagnostics=yes
|
||||||
|
VALGRINDFLAGS += --quiet --show-error-list=yes
|
||||||
|
VALGRINDFLAGS += --log-file=valgrind.out
|
||||||
|
# We need to suppress libreadline leaks here. See :
|
||||||
|
# https://stackoverflow.com/questions/72840015
|
||||||
|
VALGRINDFLAGS += --suppressions=etc/libreadline.supp
|
||||||
|
|
||||||
|
memcheck: targets
|
||||||
|
@$(VALGRIND) $(VALGRINDFLAGS) $(BINDIR)/brchess
|
||||||
|
|
||||||
|
##################################### Makefile debug
|
||||||
|
.PHONY: showflags wft
|
||||||
|
|
||||||
|
showflags:
|
||||||
|
@echo CFLAGS: "$(CFLAGS)"
|
||||||
|
@echo CPPFLAGS: $(CPPFLAGS)
|
||||||
|
@echo DEPFLAGS: $(DEPFLAGS)
|
||||||
|
@echo LDFLAGS: $(LDFLAGS)
|
||||||
|
@echo DEPFLAGS: $(DEPFLAGS)
|
||||||
|
|
||||||
|
wtf:
|
||||||
|
@printf "LIBOBJDIR=%s\n\n" "$(LIBOBJDIR)"
|
||||||
|
@printf "LIBOBJ=%s\n\n" "$(LIBOBJ)"
|
||||||
|
@printf "OBJDIR=%s\n\n" "$(OBJDIR)"
|
||||||
|
@printf "OBJ=%s\n\n" "$(OBJ)"
|
||||||
|
@#echo LIBOBJ=$(LIBOBJ)
|
||||||
|
@#echo DEP=$(DEP)
|
||||||
|
@#echo LIBSRC=$(LIBSRC)
|
||||||
|
|||||||
1
README.org
Normal file
1
README.org
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A basic chess program. The goal is not to make it good, but at least to be able to play a full game - Far to be the case !
|
||||||
57
STATUS.org
Normal file
57
STATUS.org
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#+OPTIONS: toc:nil
|
||||||
|
|
||||||
|
* Misc
|
||||||
|
- License: [[https://www.gnu.org/licenses/gpl-3.0-standalone.html][GNU General Public License v3.0 or later]].
|
||||||
|
- Code is in C (gnu11 = C11 + some GNU extensions), tested only on Linux x86-64.
|
||||||
|
- [[https://git.raoult.com/bruno/brchess][Source Code]].
|
||||||
|
|
||||||
|
* Done or partially done
|
||||||
|
*** Text interface
|
||||||
|
- basic commands like "init", "fen xxxx", "depth n", "search", "pvs", etc...
|
||||||
|
*** Dual [[https://en.wikipedia.org/wiki/0x88][0x88]] / [[https://en.wikipedia.org/wiki/Bitboard#Chess_bitboards][bitboard]] representations
|
||||||
|
- I started with a [[https://en.wikipedia.org/wiki/0x88][0x88 board representation]]
|
||||||
|
- But... wanted to switch to [[https://en.wikipedia.org/wiki/Bitboard#Chess_bitboards][bitboard]] lately
|
||||||
|
- Today there is a messy mix of the two representations.
|
||||||
|
*** A [[https://www.chessprogramming.org/Pseudo-Legal_Move][pseudo-legal move]] generator
|
||||||
|
- Does not check for some invalid moves (especially king-pinned pieces moves, which could be very expensive).
|
||||||
|
I believe some programs do not do it too, and prefer to see invalid positions at next ply (TODO).
|
||||||
|
- Still with 0x88 board (needs to be rewritten with bitboards).
|
||||||
|
*** *Very expensive* pieces and moves list
|
||||||
|
- They should be converted into arrays, to allow fast duplication for move_do(), the function which actually makes a move.
|
||||||
|
*** A basic eval function
|
||||||
|
- preferred squares for pieces
|
||||||
|
- mobility
|
||||||
|
*** "Move Search" functions
|
||||||
|
**** Basic [[https://en.wikipedia.org/wiki/Negamax][negamax]] search function
|
||||||
|
- No [[https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning][alpha-beta pruning]]
|
||||||
|
**** [[https://en.wikipedia.org/wiki/Principal_variation_search][Principal Variation Search]] (PVS) function
|
||||||
|
- Alpha-beta pruning
|
||||||
|
- Basic moves [[https://www.chessprogramming.org/Move_Ordering][pre-ordering]]
|
||||||
|
It makes the PVS/alpha-beta pruning quite decent. For example, a 6 ply depth search gives:
|
||||||
|
- negamax: 1,196 secs for 125,799 Knodes
|
||||||
|
- PVS: 14 secs for 1,575 Knodes
|
||||||
|
- Both make search at a fixed depth (still no [[https://www.chessprogramming.org/Quiescence_Search][quiescence search]] at terminal nodes).
|
||||||
|
|
||||||
|
* Missing
|
||||||
|
*** All Chess rules
|
||||||
|
- Mate/Pat detection (!)
|
||||||
|
Not trivial, as using pseudo-valid moves implies mate/pat detection is late
|
||||||
|
- Special rules like 50 moves/position repetition
|
||||||
|
*** Actual game management
|
||||||
|
- Play a move, ask engine to play a move
|
||||||
|
- A standard interface for usual software (like SCID)
|
||||||
|
Probably [[https://www.gnu.org/software/xboard/engine-intf.html][xboard]] first, as it looks simpler than [[https://en.wikipedia.org/wiki/Universal_Chess_Interface][UCI]].
|
||||||
|
*** Search improvement
|
||||||
|
- Book-keeping of moves during search (did not decide the method).
|
||||||
|
- [[https://en.wikipedia.org/wiki/Zobrist_hashing][Positions hashing]] / transposition detection
|
||||||
|
|
||||||
|
* Next steps planned (no specific order)
|
||||||
|
*** Memory cleanup
|
||||||
|
- proper recusive position/moves cleanup in search() and pvs()
|
||||||
|
- use valgrind to find possible other unfreed memory
|
||||||
|
*** Replace the current interface with a basic xboard one
|
||||||
|
1. Check which commands are necessary/mandatory.
|
||||||
|
1. This will allow easy testing with common software
|
||||||
|
*** Mate/Pat detection
|
||||||
|
*** In Search, detect King capture
|
||||||
|
*** In Search, do something when no move available
|
||||||
1
brlib
Submodule
1
brlib
Submodule
Submodule brlib added at 97d6570be7
@@ -1 +0,0 @@
|
|||||||
((c-mode . ((compile-command . "make -C ../build -j2 whatever"))))
|
|
||||||
6
etc/libreadline.supp
Normal file
6
etc/libreadline.supp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
ignore_libreadline_leaks
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
obj:*/libreadline.so.*
|
||||||
|
}
|
||||||
17
make.deps
17
make.deps
@@ -1,17 +0,0 @@
|
|||||||
./obj/bits.o:: src/bits.c src/bits.h src/debug.h
|
|
||||||
./obj/bodichess.o:: src/bodichess.c src/chessdefs.h src/bits.h src/debug.h \
|
|
||||||
src/board.h src/piece.h src/list.h src/pool.h src/move.h src/position.h \
|
|
||||||
src/fen.h src/eval.h src/bodichess.h
|
|
||||||
./obj/debug.o:: src/debug.c src/debug.h
|
|
||||||
./obj/eval.o:: src/eval.c src/eval.h src/position.h src/chessdefs.h src/bits.h \
|
|
||||||
src/debug.h src/board.h src/piece.h src/list.h src/pool.h
|
|
||||||
./obj/fen.o:: src/fen.c src/debug.h src/chessdefs.h src/bits.h src/position.h \
|
|
||||||
src/board.h src/piece.h src/list.h src/pool.h src/fen.h
|
|
||||||
./obj/move.o:: src/move.c src/chessdefs.h src/bits.h src/debug.h src/board.h \
|
|
||||||
src/piece.h src/list.h src/pool.h src/move.h src/position.h
|
|
||||||
./obj/piece.o:: src/piece.c src/chessdefs.h src/bits.h src/debug.h src/piece.h \
|
|
||||||
src/list.h src/pool.h src/board.h src/position.h
|
|
||||||
./obj/pool.o:: src/pool.c src/list.h src/pool.h src/debug.h
|
|
||||||
./obj/position.o:: src/position.c src/chessdefs.h src/bits.h src/debug.h \
|
|
||||||
src/position.h src/board.h src/piece.h src/list.h src/pool.h src/move.h \
|
|
||||||
src/fen.h
|
|
||||||
26
scripts/env.sh
Executable file
26
scripts/env.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# env.sh - set environment for brchess developer.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 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>
|
||||||
|
#
|
||||||
|
# USAGE: source env.sh [arg]
|
||||||
|
#
|
||||||
|
# This file will actually be sourced if it was never sourced in current bash
|
||||||
|
# environment.
|
||||||
|
|
||||||
|
if [[ ! -v _BRCHESS_ENV_ ]]; then
|
||||||
|
export _BRCHESS_ENV_=1 BRCHESS_ROOT BRLIB_DIR LD_LIBRARY_PATH
|
||||||
|
BRCHESS_ROOT=$(realpath -L "$(dirname "${BASH_SOURCE[0]}")/..")
|
||||||
|
BRLIB_DIR="$BRCHESS_ROOT/brlib/lib"
|
||||||
|
LD_LIBRARY_PATH=/mypath${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
|
||||||
|
#printf "R=%s L=%s LD=%s\n" "$BRCHESS_ROOT" "$BRLIB_DIR" "$LD_LIBRARY_PATH"
|
||||||
|
printf "Chess environment complete.\n"
|
||||||
|
fi
|
||||||
70
src/bitboard.h
Normal file
70
src/bitboard.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* bitboard.h - bitboard definitions.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 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 BITBOARD_H
|
||||||
|
#define BITBOARD_H
|
||||||
|
|
||||||
|
#include <bits.h>
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
|
#include "piece.h"
|
||||||
|
|
||||||
|
enum bb_square {
|
||||||
|
A1 = 1UL << 0, B1 = 1UL << 1, C1 = 1UL << 2, D1 = 1UL << 3,
|
||||||
|
E1 = 1UL << 4, F1 = 1UL << 5, G1 = 1UL << 6, H1 = 1UL << 7,
|
||||||
|
|
||||||
|
A2 = 1UL << 8, B2 = 1UL << 9, C2 = 1UL << 10, D2 = 1UL << 11,
|
||||||
|
E2 = 1UL << 12, F2 = 1UL << 13, G2 = 1UL << 14, H2 = 1UL << 15,
|
||||||
|
|
||||||
|
A3 = 1UL << 16, B3 = 1UL << 17, C3 = 1UL << 18, D3 = 1UL << 19,
|
||||||
|
E3 = 1UL << 20, F3 = 1UL << 21, G3 = 1UL << 22, H3 = 1UL << 23,
|
||||||
|
|
||||||
|
A4 = 1UL << 24, B4 = 1UL << 25, C4 = 1UL << 26, D4 = 1UL << 27,
|
||||||
|
E4 = 1UL << 28, F4 = 1UL << 29, G4 = 1UL << 30, H4 = 1UL << 31,
|
||||||
|
|
||||||
|
A5 = 1UL << 32, B5 = 1UL << 33, C5 = 1UL << 34, D5 = 1UL << 35,
|
||||||
|
E5 = 1UL << 36, F5 = 1UL << 37, G5 = 1UL << 38, H5 = 1UL << 39,
|
||||||
|
|
||||||
|
A6 = 1UL << 40, B6 = 1UL << 41, C6 = 1UL << 42, D6 = 1UL << 43,
|
||||||
|
E6 = 1UL << 44, F6 = 1UL << 45, G6 = 1UL << 46, H6 = 1UL << 47,
|
||||||
|
|
||||||
|
A7 = 1UL << 48, B7 = 1UL << 49, C7 = 1UL << 50, D7 = 1UL << 51,
|
||||||
|
E7 = 1UL << 52, F7 = 1UL << 53, G7 = 1UL << 54, H7 = 1UL << 55,
|
||||||
|
|
||||||
|
A8 = 1UL << 56, B8 = 1UL << 57, C8 = 1UL << 58, D8 = 1UL << 59,
|
||||||
|
E8 = 1UL << 60, F8 = 1UL << 61, G8 = 1UL << 62, H8 = 1UL << 63,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum bb_files {
|
||||||
|
F_1 = A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8,
|
||||||
|
F_2 = B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8,
|
||||||
|
F_3 = C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8,
|
||||||
|
F_4 = D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8,
|
||||||
|
F_5 = E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8,
|
||||||
|
F_6 = F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8,
|
||||||
|
F_7 = G1 | G2 | G3 | G4 | G5 | G6 | G7 | G8,
|
||||||
|
F_8 = H1 | H2 | H3 | H4 | H5 | H6 | H7 | H8,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum bb_ranges {
|
||||||
|
R_1 = A1 | B1 | C1 | D1 | E1 | F1 | G1 | H1,
|
||||||
|
R_2 = A2 | B2 | C2 | D2 | E2 | F2 | G2 | H2,
|
||||||
|
R_3 = A3 | B3 | C3 | D3 | E3 | F3 | G3 | H3,
|
||||||
|
R_4 = A4 | B4 | C4 | D4 | E4 | F4 | G4 | H4,
|
||||||
|
R_5 = A5 | B5 | C5 | D5 | E5 | F5 | G5 | H5,
|
||||||
|
R_6 = A6 | B6 | C6 | D6 | E6 | F6 | G6 | H6,
|
||||||
|
R_7 = A7 | B7 | C7 | D7 | E7 | F7 | G7 | H7,
|
||||||
|
R_8 = A8 | B8 | C8 | D8 | E8 | F8 | G8 | H8,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* BOARD_H */
|
||||||
85
src/bits.c
85
src/bits.c
@@ -1,85 +0,0 @@
|
|||||||
/* bits.c - bits.h tests
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bits.h"
|
|
||||||
|
|
||||||
#ifdef BIN_bits
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static inline int _popcount64(u64 n)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
while (n) {
|
|
||||||
count++;
|
|
||||||
n &= (n - 1);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int _ctz64(u64 n)
|
|
||||||
{
|
|
||||||
return _popcount64((n & -n) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int _clz64(u64 n)
|
|
||||||
{
|
|
||||||
u64 r, q;
|
|
||||||
|
|
||||||
r = (n > 0xFFFFFFFF) << 5; n >>= r;
|
|
||||||
q = (n > 0xFFFF) << 4; n >>= q; r |= q;
|
|
||||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
|
||||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
|
||||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
|
||||||
r |= (n >> 1);
|
|
||||||
return __WORDSIZE - r - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int _ffs64(u64 n)
|
|
||||||
{
|
|
||||||
if (n == 0)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
return _popcount64(n ^ ~-n);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int ac, char **av)
|
|
||||||
{
|
|
||||||
u64 u = 123, _tmp;
|
|
||||||
int curbit;
|
|
||||||
int base = 10;
|
|
||||||
debug_init(0);
|
|
||||||
if (ac > 2)
|
|
||||||
base = atoi(*(av+2));
|
|
||||||
if (ac > 1) {
|
|
||||||
u = strtoul(*(av+1), NULL, base);
|
|
||||||
printf("base=%d input=%#lx\n", base, u);
|
|
||||||
printf("popcount64(%lu) = %d/%d\n", u, popcount64(u), _popcount64(u));
|
|
||||||
printf("ctz64(%lu) = %d/%d\n", u, ctz64(u), _ctz64(u));
|
|
||||||
printf("clz64(%lu) = %d/%d\n", u, clz64(u), _clz64(u));
|
|
||||||
printf("ffs64(%lu) = %d/%d\n", u, ffs64(u), _ffs64(u));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
bit_for_each64(curbit, _tmp, u) {
|
|
||||||
printf("loop: curbit=%d tmp=%ld\n", curbit, _tmp);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
bit_for_each64_2(curbit, _tmp, u) {
|
|
||||||
printf("loop2: curbit=%d tmp=%ld\n", curbit, _tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* BIN_bits */
|
|
||||||
163
src/bits.h
163
src/bits.h
@@ -1,163 +0,0 @@
|
|||||||
/* bits.h - bits functions.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef BITS_H
|
|
||||||
#define BITS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* next include will define __WORDSIZE: 32 or 64
|
|
||||||
*/
|
|
||||||
#include <bits/wordsize.h>
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#ifndef __has_builtin
|
|
||||||
#define __has_builtin(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* no plan to support 32bits for now...
|
|
||||||
*/
|
|
||||||
#if __WORDSIZE != 64
|
|
||||||
ERROR_64_BYTES_WORDSIZE_ONLY
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
|
|
||||||
/* count trailing zeroes : 00101000 -> 3
|
|
||||||
* ^^^
|
|
||||||
*/
|
|
||||||
static inline int ctz64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ctzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctzl.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ctzl(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_clzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin clzl.\n");
|
|
||||||
# endif
|
|
||||||
return __WORDSIZE - (__builtin_clzl(n & -n) + 1);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount64((n & −n) − 1);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count leading zeroes : 00101000 -> 2
|
|
||||||
* ^^
|
|
||||||
*/
|
|
||||||
static inline int clz64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_clzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_clzl(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
u64 r, q;
|
|
||||||
|
|
||||||
r = (n > 0xFFFFFFFF) << 5; n >>= r;
|
|
||||||
q = (n > 0xFFFF) << 4; n >>= q; r |= q;
|
|
||||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
|
||||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
|
||||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
|
||||||
r |= (n >> 1);
|
|
||||||
return __WORDSIZE - r - 1;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find first set : 00101000 -> 4
|
|
||||||
* ^
|
|
||||||
*/
|
|
||||||
static inline uint ffs64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_ffsl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ffsl.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_ffsll(n);
|
|
||||||
|
|
||||||
# elif __has_builtin(__builtin_ctzl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin ctzl.\n");
|
|
||||||
# endif
|
|
||||||
if (n == 0)
|
|
||||||
return (0);
|
|
||||||
return __builtin_ctzl(n) + 1;
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
return popcount64(n ^ ~-n);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int popcount64(u64 n)
|
|
||||||
{
|
|
||||||
# if __has_builtin(__builtin_popcountl)
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "builtin.\n");
|
|
||||||
# endif
|
|
||||||
return __builtin_popcountl(n);
|
|
||||||
|
|
||||||
# else
|
|
||||||
# ifdef DEBUG_BITS
|
|
||||||
log_f(1, "emulated.\n");
|
|
||||||
# endif
|
|
||||||
int count = 0;
|
|
||||||
while (n) {
|
|
||||||
count++;
|
|
||||||
n &= (n - 1);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** bit_for_each64 - iterate over an u64 bits
|
|
||||||
* @pos: an int used as current bit
|
|
||||||
* @tmp: a temp u64 used as temporary storage
|
|
||||||
* @ul: the u64 to loop over
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* u64 u=139, _t; // u=b10001011
|
|
||||||
* int cur;
|
|
||||||
* bit_for_each64(cur, _t, u) {
|
|
||||||
* printf("%d\n", cur);
|
|
||||||
* }
|
|
||||||
* This will display the position of each bit in u: 1, 2, 4, 8
|
|
||||||
*
|
|
||||||
* I should probably re-think the implementation...
|
|
||||||
*/
|
|
||||||
#define bit_for_each64(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ffs64(tmp); tmp; tmp &= (tmp - 1), pos = ffs64(tmp))
|
|
||||||
|
|
||||||
/** or would it be more useful (counting bits from zero instead of 1) ?
|
|
||||||
*/
|
|
||||||
#define bit_for_each64_2(pos, tmp, ul) \
|
|
||||||
for (tmp = ul, pos = ctz64(tmp); tmp; tmp ^= 1<<pos, pos = ctz64(tmp))
|
|
||||||
|
|
||||||
#endif /* BITS_H */
|
|
||||||
41
src/board.h
41
src/board.h
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -27,9 +27,12 @@ typedef struct board_s {
|
|||||||
|
|
||||||
/* definitions for 0x88 representation
|
/* definitions for 0x88 representation
|
||||||
*/
|
*/
|
||||||
#define SQ88(f, r) (16 * (r) + (f)) /* from rank,file to sq88 */
|
#define SQ88(f, r) (((r) << 4) | (f)) /* from rank,file to sq88 */
|
||||||
#define FILE88(s) ((s) & 7) /* from sq88 to file */
|
#define F88(s) ((s) & 0x0f) /* from sq88 to file */
|
||||||
#define RANK88(s) ((s) >> 4) /* from sq88 to rank */
|
#define R88(s) ((s) >> 4) /* from sq88 to rank */
|
||||||
|
|
||||||
|
#define SETF88(s, r) ((s) &= 0xf0, (s) |= (r))
|
||||||
|
#define SETR88(s, f) ((s) &= 0x0f, (s) |= (f)<<4)
|
||||||
|
|
||||||
#define SQ88_NOK(s) ((s) & 0x88) /* invalid square */
|
#define SQ88_NOK(s) ((s) & 0x88) /* invalid square */
|
||||||
#define SQ88_OK(s) (!SQ88_NOK(s))
|
#define SQ88_OK(s) (!SQ88_NOK(s))
|
||||||
@@ -37,7 +40,7 @@ typedef struct board_s {
|
|||||||
/* definitions for bitboard representation
|
/* definitions for bitboard representation
|
||||||
*/
|
*/
|
||||||
#define BB(f, r) (1ULL << (8 * (r) + (f))) /* from rank,file to bitboard */
|
#define BB(f, r) (1ULL << (8 * (r) + (f))) /* from rank,file to bitboard */
|
||||||
#define SQ88_2_BB(s) (BB(FILE88(s), RANK88(s))) /* from sq88 to bitboard */
|
#define SQ88_2_BB(s) (BB(F88(s), R88(s))) /* from sq88 to bitboard */
|
||||||
#define FILEBB(b) ((b) % 8) /* from sq88 to file */
|
#define FILEBB(b) ((b) % 8) /* from sq88 to file */
|
||||||
#define RANKBB(b) ((b) / 8) /* from sq88 to rank */
|
#define RANKBB(b) ((b) / 8) /* from sq88 to rank */
|
||||||
|
|
||||||
@@ -74,32 +77,4 @@ enum x88_square {
|
|||||||
x88_A8=0x70, x88_B8, x88_C8, x88_D8, x88_E8, x88_F8, x88_G8, x88_H8,
|
x88_A8=0x70, x88_B8, x88_C8, x88_D8, x88_E8, x88_F8, x88_G8, x88_H8,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* necessary not to become mad to set bitboards
|
|
||||||
*/
|
|
||||||
enum bb_square{
|
|
||||||
A1=(u64)1, B1=(u64)A1<<1, C1=(u64)B1<<1, D1=(u64)C1<<1,
|
|
||||||
E1=(u64)D1<<1, F1=(u64)E1<<1, G1=(u64)F1<<1, H1=(u64)G1<<1,
|
|
||||||
|
|
||||||
A2=(u64)A1<<8, B2=(u64)B1<<8, C2=(u64)C1<<8, D2=(u64)D1<<8,
|
|
||||||
E2=(u64)E1<<8, F2=(u64)F1<<8, G2=(u64)G1<<8, H2=(u64)H1<<8,
|
|
||||||
|
|
||||||
A3=(u64)A2<<8, B3=(u64)B2<<8, C3=(u64)C2<<8, D3=(u64)D2<<8,
|
|
||||||
E3=(u64)E2<<8, F3=(u64)F2<<8, G3=(u64)G2<<8, H3=(u64)H2<<8,
|
|
||||||
|
|
||||||
A4=(u64)A3<<8, B4=(u64)B3<<8, C4=(u64)C3<<8, D4=(u64)D3<<8,
|
|
||||||
E4=(u64)E3<<8, F4=(u64)F3<<8, G4=(u64)G3<<8, H4=(u64)H3<<8,
|
|
||||||
|
|
||||||
A5=(u64)A4<<8, B5=(u64)B4<<8, C5=(u64)C4<<8, D5=(u64)D4<<8,
|
|
||||||
E5=(u64)E4<<8, F5=(u64)F4<<8, G5=(u64)G4<<8, H5=(u64)H4<<8,
|
|
||||||
|
|
||||||
A6=(u64)A5<<8, B6=(u64)B5<<8, C6=(u64)C5<<8, D6=(u64)D5<<8,
|
|
||||||
E6=(u64)E5<<8, F6=(u64)F5<<8, G6=(u64)G5<<8, H6=(u64)H5<<8,
|
|
||||||
|
|
||||||
A7=(u64)A6<<8, B7=(u64)B6<<8, C7=(u64)C6<<8, D7=(u64)D6<<8,
|
|
||||||
E7=(u64)E6<<8, F7=(u64)F6<<8, G7=(u64)G6<<8, H7=(u64)H6<<8,
|
|
||||||
|
|
||||||
A8=(u64)A7<<8, B8=(u64)B7<<8, C8=(u64)C7<<8, D8=(u64)D7<<8,
|
|
||||||
E8=(u64)E7<<8, F8=(u64)F7<<8, G8=(u64)G7<<8, H8=(u64)H7<<8,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* BOARD_H */
|
#endif /* BOARD_H */
|
||||||
|
|||||||
@@ -1,39 +1,42 @@
|
|||||||
/* bodichess.c - main loop.
|
/* brchess.c - main loop.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
* Copyright (C) 2021-2023 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.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
#include <br.h>
|
||||||
|
#include <list.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "brchess.h"
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "list.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "fen.h"
|
#include "fen.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "bodichess.h"
|
#include "eval-simple.h"
|
||||||
|
#include "search.h"
|
||||||
|
|
||||||
typedef struct {
|
struct command {
|
||||||
char *name; /* User printable name */
|
char *name; /* User printable name */
|
||||||
int (*func)(pos_t *, char *); /* function doing the job */
|
int (*func)(pos_t *, char *); /* function doing the job */
|
||||||
char *doc; /* function doc */
|
char *doc; /* function doc */
|
||||||
} COMMAND;
|
};
|
||||||
|
|
||||||
/* readline example inspired by :
|
/* readline example inspired by :
|
||||||
* - https://thoughtbot.com/blog/tab-completion-in-gnu-readline
|
* - https://thoughtbot.com/blog/tab-completion-in-gnu-readline
|
||||||
@@ -44,37 +47,54 @@ char *commands_generator(const char *, int);
|
|||||||
char *escape(const char *);
|
char *escape(const char *);
|
||||||
int quote_detector(char *, int);
|
int quote_detector(char *, int);
|
||||||
int execute_line (pos_t *, char *line);
|
int execute_line (pos_t *, char *line);
|
||||||
COMMAND *find_command (char *);
|
struct command *find_command (char *);
|
||||||
char *stripwhite (char *string);
|
char *stripwhite (char *string);
|
||||||
|
|
||||||
/* 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_help(pos_t *, char*);
|
||||||
int do_fen(pos_t *, char*);
|
int do_fen(pos_t *, char*);
|
||||||
|
int do_init(pos_t *, char*);
|
||||||
int do_pos(pos_t *, char*);
|
int do_pos(pos_t *, char*);
|
||||||
int do_genmoves(pos_t *, char*);
|
int do_genmoves(pos_t *, char*);
|
||||||
int do_prmoves(pos_t *, char*);
|
int do_prmoves(pos_t *, char*);
|
||||||
|
//int do_prmovepos(pos_t *pos, char *arg);
|
||||||
|
int do_prpieces(pos_t *pos, char *arg);
|
||||||
int do_memstats(pos_t *, char*);
|
int do_memstats(pos_t *, char*);
|
||||||
int do_eval(pos_t *, char*);
|
int do_eval(pos_t *, char*);
|
||||||
|
int do_simple_eval(pos_t *, char*);
|
||||||
|
int do_move(pos_t *, char*);
|
||||||
int do_quit(pos_t *, char*);
|
int do_quit(pos_t *, char*);
|
||||||
int do_debug(pos_t *, char*);
|
int do_debug(pos_t *, char*);
|
||||||
|
int do_depth(pos_t *, char*);
|
||||||
|
int do_search(pos_t *, char*);
|
||||||
|
int do_pvs(pos_t *, char*);
|
||||||
|
|
||||||
COMMAND commands[] = {
|
struct command commands[] = {
|
||||||
{ "help", do_help, "Display this text" },
|
{ "help", do_help, "Display this text" },
|
||||||
{ "?", do_help, "Synonym for 'help'" },
|
{ "?", do_help, "Synonym for 'help'" },
|
||||||
{ "fen", do_fen, "Set position to FEN" },
|
{ "fen", do_fen, "Set position to FEN" },
|
||||||
|
{ "init", do_init, "Set position to normal start position" },
|
||||||
{ "pos", do_pos, "Print current position" },
|
{ "pos", do_pos, "Print current position" },
|
||||||
{ "quit", do_quit, "Quit" },
|
{ "quit", do_quit, "Quit" },
|
||||||
{ "genmove", do_genmoves, "Generate next move list" },
|
{ "genmove", do_genmoves, "Generate move list for " },
|
||||||
{ "prmoves", do_prmoves, "Generate next move list" },
|
{ "prmoves", do_prmoves, "Print position move list" },
|
||||||
|
// { "prmovepos", do_prmovepos, "Print Nth move resulting position" },
|
||||||
|
{ "prpieces", do_prpieces, "Print Pieces (from pieces lists)" },
|
||||||
{ "memstats", do_memstats, "Generate next move list" },
|
{ "memstats", do_memstats, "Generate next move list" },
|
||||||
{ "eval", do_eval, "Eval current position" },
|
{ "eval", do_eval, "Eval current position" },
|
||||||
|
{ "simple-eval", do_simple_eval, "Simple eval current position" },
|
||||||
|
{ "do_move", do_move, "execute nth move on current position" },
|
||||||
{ "debug", do_debug, "Set log level to LEVEL" },
|
{ "debug", do_debug, "Set log level to LEVEL" },
|
||||||
|
{ "depth", do_depth, "Set search depth to N" },
|
||||||
|
{ "search", do_search, "Search best move (negamax)" },
|
||||||
|
{ "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 bodichess(pos_t *pos)
|
int brchess(pos_t *pos)
|
||||||
{
|
{
|
||||||
char *buffer, *s;
|
char *buffer, *s;
|
||||||
|
|
||||||
@@ -104,9 +124,7 @@ int bodichess(pos_t *pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//char **commands_completion(const char *text, int start, int end)
|
//char **commands_completion(const char *text, int start, int end)
|
||||||
char **commands_completion(const char *text,
|
char **commands_completion(const char *text, __unused int start, __unused int end)
|
||||||
__attribute__((unused)) int start,
|
|
||||||
__attribute__((unused)) int end)
|
|
||||||
{
|
{
|
||||||
rl_attempted_completion_over = 1;
|
rl_attempted_completion_over = 1;
|
||||||
return rl_completion_matches(text, commands_generator);
|
return rl_completion_matches(text, commands_generator);
|
||||||
@@ -183,7 +201,7 @@ int quote_detector(char *line, int index)
|
|||||||
int execute_line(pos_t *pos, char *line)
|
int execute_line(pos_t *pos, char *line)
|
||||||
{
|
{
|
||||||
register int i;
|
register int i;
|
||||||
COMMAND *command;
|
struct command *command;
|
||||||
char *word;
|
char *word;
|
||||||
|
|
||||||
/* Isolate the command word. */
|
/* Isolate the command word. */
|
||||||
@@ -217,7 +235,7 @@ int execute_line(pos_t *pos, char *line)
|
|||||||
|
|
||||||
/* Look up NAME as the name of a command, and return a pointer to that
|
/* 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. */
|
command. Return a NULL pointer if NAME isn't a command name. */
|
||||||
COMMAND *find_command(char *name)
|
struct command *find_command(char *name)
|
||||||
{
|
{
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
@@ -225,7 +243,7 @@ COMMAND *find_command(char *name)
|
|||||||
if (strcmp(name, commands[i].name) == 0)
|
if (strcmp(name, commands[i].name) == 0)
|
||||||
return &commands[i];
|
return &commands[i];
|
||||||
|
|
||||||
return (COMMAND *)NULL;
|
return (struct command *)NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Strip whitespace from the start and end of STRING. Return a pointer
|
/* Strip whitespace from the start and end of STRING. Return a pointer
|
||||||
@@ -248,48 +266,90 @@ char *stripwhite(char *string)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_eval(__attribute__((unused)) pos_t *pos,
|
int do_eval(__unused pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
|
||||||
{
|
{
|
||||||
|
eval_t material[2], control[2], mobility[2];
|
||||||
|
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);
|
eval_t res = eval(pos);
|
||||||
printf("eval=%ld (%.3f pawns)\n", res, (float)res/100);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_fen(pos_t *pos, char *arg)
|
int do_fen(pos_t *pos, char *arg)
|
||||||
{
|
{
|
||||||
log_f(1, "%s\n", arg);
|
|
||||||
fen2pos(pos, arg);
|
fen2pos(pos, arg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_pos(pos_t *pos,
|
int do_init(pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
{
|
||||||
|
pos_startpos(pos);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_pos(pos_t *pos, __unused char *arg)
|
||||||
{
|
{
|
||||||
log_f(1, "%s\n", arg);
|
|
||||||
pos_print(pos);
|
pos_print(pos);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_genmoves(pos_t *pos,
|
int do_genmoves(pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
|
||||||
{
|
{
|
||||||
log_f(1, "%s\n", arg);
|
moves_gen_all(pos);
|
||||||
moves_gen(pos, OPPONENT(pos->turn), false);
|
|
||||||
moves_gen(pos, pos->turn, true);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_prmoves(pos_t *pos,
|
int do_prmoves(pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
|
||||||
{
|
{
|
||||||
log_f(1, "%s\n", arg);
|
uint debug_level = debug_level_get();
|
||||||
moves_print(pos, M_PR_SEPARATE);
|
debug_level_set(1);
|
||||||
|
moves_print(pos, M_PR_SEPARATE | M_PR_NUM | M_PR_LONG);
|
||||||
|
debug_level_set(debug_level);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_memstats(__attribute__((unused)) pos_t *pos,
|
/*
|
||||||
__attribute__((unused)) char *arg)
|
* int do_prmovepos(pos_t *pos, char *arg)
|
||||||
|
* {
|
||||||
|
* struct list_head *p_cur, *tmp;
|
||||||
|
* int movenum = atoi(arg), cur = 0; /\* starts with 0 *\/
|
||||||
|
* move_t *move;
|
||||||
|
*
|
||||||
|
* log_f(1, "%s\n", arg);
|
||||||
|
* list_for_each_safe(p_cur, tmp, &pos->moves[pos->turn]) {
|
||||||
|
* move = list_entry(p_cur, move_t, list);
|
||||||
|
* if (cur++ == movenum) {
|
||||||
|
* pos_print(move->newpos);
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* return 1;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
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();
|
moves_pool_stats();
|
||||||
piece_pool_stats();
|
piece_pool_stats();
|
||||||
@@ -297,14 +357,36 @@ int do_memstats(__attribute__((unused)) pos_t *pos,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_quit(__attribute__((unused)) pos_t *pos,
|
int do_move(__unused pos_t *pos, __unused char *arg)
|
||||||
__attribute__((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_quit(__unused pos_t *pos, __unused char *arg)
|
||||||
{
|
{
|
||||||
return done = 1;
|
return done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_debug(__attribute__((unused)) pos_t *pos,
|
int do_debug(__unused pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
|
||||||
{
|
{
|
||||||
debug_level_set(atoi(arg));
|
debug_level_set(atoi(arg));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -312,15 +394,14 @@ int do_debug(__attribute__((unused)) pos_t *pos,
|
|||||||
|
|
||||||
/* Print out help for ARG, or for all of the commands if ARG is
|
/* Print out help for ARG, or for all of the commands if ARG is
|
||||||
not present. */
|
not present. */
|
||||||
int do_help(__attribute__((unused)) pos_t *pos,
|
int do_help(__unused pos_t *pos, __unused char *arg)
|
||||||
__attribute__((unused)) char *arg)
|
|
||||||
{
|
{
|
||||||
register int i;
|
int i;
|
||||||
int printed = 0;
|
int printed = 0;
|
||||||
|
|
||||||
for (i = 0; commands[i].name; i++) {
|
for (i = 0; commands[i].name; i++) {
|
||||||
if (!*arg || (strcmp(arg, commands[i].name) == 0)) {
|
if (!*arg || (strcmp(arg, commands[i].name) == 0)) {
|
||||||
printf("%s\t\t%s.\n", commands[i].name, commands[i].doc);
|
printf("%-11.11s%s.\n", commands[i].name, commands[i].doc);
|
||||||
printed++;
|
printed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,10 +426,61 @@ int do_help(__attribute__((unused)) pos_t *pos,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BIN_bodichess
|
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()
|
/** main()
|
||||||
* options:
|
* options:
|
||||||
int bodichess(pos_t *pos)
|
int brchess(pos_t *pos)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int usage(char *prg)
|
static int usage(char *prg)
|
||||||
@@ -364,11 +496,12 @@ int main(int ac, char **av)
|
|||||||
pos_t *pos;
|
pos_t *pos;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
debug_init(1);
|
|
||||||
piece_pool_init();
|
piece_pool_init();
|
||||||
moves_pool_init();
|
moves_pool_init();
|
||||||
pos_pool_init();
|
pos_pool_init();
|
||||||
pos = pos_get();
|
pos = pos_get();
|
||||||
|
debug_init(1, stderr, true);
|
||||||
|
eval_simple_init();
|
||||||
|
|
||||||
while ((opt = getopt(ac, av, "d:f:")) != -1) {
|
while ((opt = getopt(ac, av, "d:f:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -382,10 +515,8 @@ int main(int ac, char **av)
|
|||||||
return usage(*av);
|
return usage(*av);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("optind = %d ac = %d\n", optind, ac);
|
|
||||||
if (optind < ac)
|
if (optind < ac)
|
||||||
return usage(*av);
|
return usage(*av);
|
||||||
|
|
||||||
return bodichess(pos);
|
return brchess(pos);
|
||||||
}
|
}
|
||||||
#endif /* BIN_bodichess */
|
|
||||||
@@ -5,17 +5,17 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BODICHESS_H
|
#ifndef BRCHESS_H
|
||||||
#define BODICHESS_H
|
#define BRCHESS_H
|
||||||
|
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
int bodichess(pos_t *pos);
|
int brchess(pos_t *pos);
|
||||||
|
|
||||||
#endif /* BODICHESS_H */
|
#endif /* BRCHESS_H */
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -14,45 +14,62 @@
|
|||||||
#ifndef CHESSDEFS_H
|
#ifndef CHESSDEFS_H
|
||||||
#define CHESSDEFS_H
|
#define CHESSDEFS_H
|
||||||
|
|
||||||
#include "bits.h"
|
#include <bits.h>
|
||||||
|
|
||||||
/* piece_t bits structure
|
/* piece_t bits structure
|
||||||
|
* MSB 8 7 6 5 4 3 2 1 LSB
|
||||||
|
* 1: color (0 for white)
|
||||||
|
* 2-7: bit set for pawn (2), knight, bishop, rook, queen, king (7)
|
||||||
*/
|
*/
|
||||||
typedef u8 piece_t;
|
typedef u8 piece_t;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
E_EMPTY = 0,
|
E_EMPTY = 0,
|
||||||
|
E_COLOR, /* LSB */
|
||||||
E_PAWN,
|
E_PAWN,
|
||||||
E_KNIGHT,
|
E_KNIGHT,
|
||||||
E_BISHOP,
|
E_BISHOP,
|
||||||
E_ROOK,
|
E_ROOK,
|
||||||
E_QUEEN,
|
E_QUEEN,
|
||||||
E_KING,
|
E_KING,
|
||||||
E_COLOR = 8
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* pos_t bitboards tables
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
BB_ALL = 0, /* OR of all bitboards */
|
||||||
|
BB_UNUSED, /* future use ? */
|
||||||
|
BB_PAWN = E_PAWN,
|
||||||
|
BB_KNIGHT,
|
||||||
|
BB_BISHOP,
|
||||||
|
BB_ROOK,
|
||||||
|
BB_QUEEN,
|
||||||
|
BB_KING,
|
||||||
|
BB_END
|
||||||
|
};
|
||||||
|
|
||||||
/* piece bitmask in piece_t
|
/* piece bitmask in piece_t
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
EMPTY = 0,
|
EMPTY = 0,
|
||||||
PAWN = 1 << (E_PAWN - 1), /* 0x01 00000001 */
|
PAWN = 1 << (E_PAWN - 1), /* 1<<(2-1) = 0x02 00000010 */
|
||||||
KNIGHT = 1 << (E_KNIGHT - 1), /* 0x02 00000010 */
|
KNIGHT = 1 << (E_KNIGHT - 1), /* 0x04 00000100 */
|
||||||
BISHOP = 1 << (E_BISHOP - 1), /* 0x04 00000100 */
|
BISHOP = 1 << (E_BISHOP - 1), /* 0x08 00001000 */
|
||||||
ROOK = 1 << (E_ROOK - 1), /* 0x08 00001000 */
|
ROOK = 1 << (E_ROOK - 1), /* 0x10 00010000 */
|
||||||
QUEEN = 1 << (E_QUEEN - 1), /* 0x10 00010000 */
|
QUEEN = 1 << (E_QUEEN - 1), /* 0x20 00100000 */
|
||||||
KING = 1 << (E_KING - 1), /* 0x20 00100000 */
|
KING = 1 << (E_KING - 1), /* 0x40 01000000 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PIECETOBB(p) (ffs64(PIECE(p))) /* from piece_t to bb piece array */
|
||||||
|
|
||||||
#define WHITE 0 /* 0x00 00000000 */
|
#define WHITE 0 /* 0x00 00000000 */
|
||||||
#define BLACK 1 /* 0x01 00000001 */
|
#define BLACK 1 /* 0x01 00000001 */
|
||||||
#define OPPONENT(p) !(p)
|
#define OPPONENT(p) !(p)
|
||||||
|
|
||||||
#define MASK_PIECE 0x3F /* 00111111 */
|
#define MASK_COLOR 0x01 /* 00000001 */
|
||||||
#define MASK_COLOR 0x80 /* 10000000 */
|
#define MASK_PIECE 0x7E /* 01111110 */
|
||||||
|
|
||||||
#define COLOR(p) ((p) & MASK_COLOR) /* bitmask */
|
#define COLOR(p) ((p) & MASK_COLOR) /* bitmask */
|
||||||
#define VCOLOR(p) (!!COLOR(p)) /* WHITE/BLACK */
|
|
||||||
#define PIECE(p) ((p) & MASK_PIECE)
|
#define PIECE(p) ((p) & MASK_PIECE)
|
||||||
#define E_PIECE(p) (ffs64(PIECE(p))) /* convert mask to E_XX */
|
#define E_PIECE(p) (ffs64(PIECE(p))) /* convert mask to E_XX */
|
||||||
|
|
||||||
@@ -63,43 +80,50 @@ enum {
|
|||||||
#define SET_BLACK(p) ((p) |= MASK_COLOR)
|
#define SET_BLACK(p) ((p) |= MASK_COLOR)
|
||||||
#define SET_COLOR(p, c) (!(c)? SET_WHITE(p): SET_BLACK(p))
|
#define SET_COLOR(p, c) (!(c)? SET_WHITE(p): SET_BLACK(p))
|
||||||
|
|
||||||
/* square_t bits structure : ffffrrrr
|
/* flip a 0-63 square:
|
||||||
|
* Vertical: G8 (62) becomes G1 (6)
|
||||||
|
* Horizontal: G8 (62) becomes B8 (57)
|
||||||
|
*/
|
||||||
|
#define FLIP_V(sq) ((sq) ^ 56)
|
||||||
|
#define FLIP_H(sq) ((sq) ^ 7)
|
||||||
|
/* square_t bits structure : rrrrffff
|
||||||
* ffff: file
|
* ffff: file
|
||||||
* rrrr: rank
|
* rrrr: rank
|
||||||
*/
|
*/
|
||||||
typedef unsigned char square_t;
|
typedef unsigned char square_t;
|
||||||
|
|
||||||
#define GET_R(s) ((s) >> 4)
|
|
||||||
#define GET_F(s) ((s) & 0x0f)
|
|
||||||
#define SET_R(s, f) ((s) &= 0x0f, (s) |= (f)<<4)
|
|
||||||
#define SET_F(s, r) ((s) &= 0xf0, (s) |= (r))
|
|
||||||
#define SQUARE(f, r) ((r) << 4 | (f))
|
|
||||||
|
|
||||||
/* castle_t bits structure
|
/* castle_t bits structure
|
||||||
*/
|
*/
|
||||||
typedef unsigned char castle_t;
|
typedef unsigned char castle_t;
|
||||||
|
|
||||||
#define CASTLE_WK 1 /* 0x01 00000001 */
|
#define CASTLE_WK (1 << 0) /* 0x01 00000001 */
|
||||||
#define CASTLE_WQ (1 << 1) /* 0x02 00000010 */
|
#define CASTLE_WQ (1 << 1) /* 0x02 00000010 */
|
||||||
#define CASTLE_BK (1 << 2) /* 0x04 00000100 */
|
#define CASTLE_BK (1 << 2) /* 0x04 00000100 */
|
||||||
#define CASTLE_BQ (1 << 3) /* 0x08 00001000 */
|
#define CASTLE_BQ (1 << 3) /* 0x08 00001000 */
|
||||||
|
|
||||||
#define CASTLE_W 0x03 /* 00000011 W castle mask */
|
#define CASTLE_W (CASTLE_WK | CASTLE_WQ) /* 00000011 W castle mask */
|
||||||
#define CASTLE_B 0x0C /* 00001100 B castle mask */
|
#define CASTLE_B (CASTLE_BK | CASTLE_BQ) /* 00001100 B castle mask */
|
||||||
|
|
||||||
|
/* game phases
|
||||||
|
*/
|
||||||
|
#define OPENING 0
|
||||||
|
#define MIDDLEGAME 1
|
||||||
|
#define ENDGAME 2
|
||||||
|
|
||||||
/* bitboard
|
/* bitboard
|
||||||
*/
|
*/
|
||||||
typedef uint64_t bitboard_t;
|
typedef u64 bitboard_t;
|
||||||
|
|
||||||
|
|
||||||
/* eval type
|
/* eval type
|
||||||
*/
|
*/
|
||||||
typedef int64_t eval_t;
|
typedef s32 eval_t;
|
||||||
|
|
||||||
/* forward typedefs
|
/* forward typedefs
|
||||||
*/
|
*/
|
||||||
typedef struct piece_list_s piece_list_t;
|
typedef struct piece_list_s piece_list_t;
|
||||||
typedef struct board_s board_t;
|
typedef struct board_s board_t;
|
||||||
typedef struct pos_s pos_t;
|
typedef struct pos_s pos_t;
|
||||||
|
typedef struct move_s move_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
106
src/debug.c
106
src/debug.c
@@ -1,106 +0,0 @@
|
|||||||
/* debug.c - debug/log management
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#define NANOSEC 1000000000 /* nano sec in sec */
|
|
||||||
#define MILLISEC 1000000 /* milli sec in sec */
|
|
||||||
|
|
||||||
static int64_t timer_start; /* in nanosecond */
|
|
||||||
static uint32_t debug_level=0;
|
|
||||||
|
|
||||||
void debug_level_set(uint32_t level)
|
|
||||||
{
|
|
||||||
debug_level = level;;
|
|
||||||
|
|
||||||
log(0, "debug level set to %u\n", level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void debug_init(uint32_t level)
|
|
||||||
{
|
|
||||||
struct timespec timer;
|
|
||||||
|
|
||||||
debug_level_set(level);
|
|
||||||
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
|
|
||||||
timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
timer_start = 0;
|
|
||||||
}
|
|
||||||
log(0, "timer started.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int64_t timer_elapsed()
|
|
||||||
{
|
|
||||||
struct timespec timer;
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &timer);
|
|
||||||
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* void debug - log function
|
|
||||||
* @timestamp : boolean
|
|
||||||
* @indent : indent level (2 spaces each)
|
|
||||||
* @src : source file/func name (or NULL)
|
|
||||||
* @line : line number
|
|
||||||
*/
|
|
||||||
void debug(uint32_t level, bool timestamp, uint32_t indent, const char *src,
|
|
||||||
uint32_t line, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
if (level > debug_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (indent)
|
|
||||||
printf("%*s", 2*(indent-1), "");
|
|
||||||
|
|
||||||
if (timestamp) {
|
|
||||||
int64_t diff = timer_elapsed();
|
|
||||||
printf("%ld.%03ld ", diff/NANOSEC, (diff/1000000)%1000);
|
|
||||||
printf("%010ld ", diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src) {
|
|
||||||
if (line)
|
|
||||||
printf("[%s:%u] ", src, line);
|
|
||||||
else
|
|
||||||
printf("[%s] ", src);
|
|
||||||
}
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vprintf(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BIN_debug
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
int foo=1;
|
|
||||||
debug_init(5);
|
|
||||||
|
|
||||||
log(0, "log0=%d\n", foo++);
|
|
||||||
log(1, "log1=%d\n", foo++);
|
|
||||||
log(2, "log2=%d\n", foo++);
|
|
||||||
log_i(2, "log_i 2=%d\n", foo++);
|
|
||||||
log_i(5, "log_i 5=%d\n", foo++);
|
|
||||||
log_i(6, "log_i 6=%d\n", foo++);
|
|
||||||
log_it(4, "log_it 4=%d\n", foo++);
|
|
||||||
log_f(1, "log_f 5=%d\n", foo++);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
66
src/debug.h
66
src/debug.h
@@ -1,66 +0,0 @@
|
|||||||
/* move.h - debug/log management.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEBUG_H
|
|
||||||
#define DEBUG_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void debug_init(uint32_t level);
|
|
||||||
void debug_level_set(uint32_t level);
|
|
||||||
void debug_devel_set(uint32_t level);
|
|
||||||
void debug(uint32_t level, bool timestamp, uint32_t indent,
|
|
||||||
const char *src, uint32_t line, const char *, ...);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
|
|
||||||
/* format: only printf
|
|
||||||
*/
|
|
||||||
#define log(level, fmt, args...) \
|
|
||||||
debug((level), false, 0, NULL, 0, fmt, ##args)
|
|
||||||
|
|
||||||
/* format: func name, no line number, no indent, no timestamp
|
|
||||||
* foo:15 val=2
|
|
||||||
*/
|
|
||||||
#define log_f(level, fmt, args...) \
|
|
||||||
debug((level), false, 0, __func__, 0, fmt, ##args)
|
|
||||||
|
|
||||||
/* format : func name, indent, no timestamp
|
|
||||||
* foo:15 val=2
|
|
||||||
*/
|
|
||||||
#define log_i(level, fmt, args...) \
|
|
||||||
debug((level), false, (level), __func__, __LINE__, fmt, ##args)
|
|
||||||
|
|
||||||
/* format : func name, indent, timestamp
|
|
||||||
* []foo:15 val=2
|
|
||||||
*/
|
|
||||||
#define log_it(level, fmt, args...) \
|
|
||||||
debug((level), true, (level), __func__, __LINE__, fmt, ##args)
|
|
||||||
|
|
||||||
/* format: file name, no indent, no timestamp
|
|
||||||
* foo:15 val=2
|
|
||||||
*
|
|
||||||
* #define log_f(level, fmt, args...) \
|
|
||||||
* debug((level), false, 0, __FILE__, __LINE__, fmt, args)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define log(level, fmt, args...)
|
|
||||||
#define log_i(...)
|
|
||||||
#define log_it(...)
|
|
||||||
#define log_f(...)
|
|
||||||
|
|
||||||
#endif /* DEBUG */
|
|
||||||
|
|
||||||
#endif /* DEBUG_H */
|
|
||||||
199
src/eval-simple.c
Normal file
199
src/eval-simple.c
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/* eval-simple.c - simple position evaluation.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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 <bits.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "piece.h"
|
||||||
|
#include "eval-simple.h"
|
||||||
|
#include "position.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tables are from https://www.chessprogramming.org/Simplified_Evaluation_Function
|
||||||
|
*
|
||||||
|
* Attention! Tables are black point of view (to be visually easier to read).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mg_pawn[] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mg_knight[] = {
|
||||||
|
-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
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mg_bishop[] = {
|
||||||
|
-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
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mg_rook[] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mg_queen[] = {
|
||||||
|
-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
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mg_king[] = {
|
||||||
|
-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,
|
||||||
|
-20, -30, -30, -40, -40, -30, -30, -20,
|
||||||
|
-10, -20, -20, -20, -20, -20, -20, -10,
|
||||||
|
20, 20, 0, 0, 0, 0, 20, 20,
|
||||||
|
20, 30, 10, 0, 0, 10, 30, 20
|
||||||
|
};
|
||||||
|
|
||||||
|
static int eg_king[] = {
|
||||||
|
-50, -40, -30, -20, -20, -30, -40, -50,
|
||||||
|
-30, -20, -10, 0, 0, -10, -20, -30,
|
||||||
|
-30, -10, 20, 30, 30, 20, -10, -30,
|
||||||
|
-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, -30, 0, 0, 0, 0, -30, -30,
|
||||||
|
-50, -30, -30, -30, -30, -30, -30, -50
|
||||||
|
};
|
||||||
|
|
||||||
|
/* as pieces bitboard tables start at position 2; we make these tables
|
||||||
|
* bigger.
|
||||||
|
*/
|
||||||
|
static int *mg_tables[] = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
mg_pawn,
|
||||||
|
mg_knight,
|
||||||
|
mg_bishop,
|
||||||
|
mg_rook,
|
||||||
|
mg_queen,
|
||||||
|
mg_king
|
||||||
|
};
|
||||||
|
|
||||||
|
static int *eg_tables[] = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
mg_pawn,
|
||||||
|
mg_knight,
|
||||||
|
mg_bishop,
|
||||||
|
mg_rook,
|
||||||
|
mg_queen,
|
||||||
|
eg_king
|
||||||
|
};
|
||||||
|
|
||||||
|
/* to flip vertically a square, we need to XOR it with 56
|
||||||
|
*/
|
||||||
|
static int mg_table[2][6 + 2][64];
|
||||||
|
static int eg_table[2][6 + 2][64];
|
||||||
|
|
||||||
|
void eval_simple_init(void)
|
||||||
|
{
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(1, "initializing piece tables\n");
|
||||||
|
# endif
|
||||||
|
for (int piece = BB_PAWN; piece <= BB_KING; ++piece) {
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eval_simple() - simple and fast position evaluation
|
||||||
|
* @pos: &position to evaluate
|
||||||
|
*
|
||||||
|
* This function is normally used only during initialization,
|
||||||
|
* or when changing phase (middlegame <--> endgame), as the eval
|
||||||
|
* will be done increntally when doing moves.
|
||||||
|
*
|
||||||
|
* @return: the @pos evaluation in centipawns
|
||||||
|
*/
|
||||||
|
eval_t eval_simple(pos_t *pos)
|
||||||
|
{
|
||||||
|
eval_t eval[2] = { 0, 0 };
|
||||||
|
int eg = simple_is_endgame(pos);
|
||||||
|
int (*gg)[6 + 2][64]= eg? eg_table: mg_table;
|
||||||
|
|
||||||
|
pos->eval_simple_phase = ENDGAME;
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(5, "phase = %s.\n", eg? "endgame": "midgame");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
for (int color = WHITE; color <= BLACK; ++color) {
|
||||||
|
for (uint piece = PAWN; piece <= KING; piece <<= 1) {
|
||||||
|
int bb = PIECETOBB(piece), cur;
|
||||||
|
u64 _t;
|
||||||
|
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(5, "p=%u bb=%d %s %s: count=%d val=%ld ", piece, bb, color? "black": "white",
|
||||||
|
P_SYM(piece), popcount64(pos->bb[color][bb]),
|
||||||
|
popcount64(pos->bb[color][bb]) * P_VALUE(piece));
|
||||||
|
# endif
|
||||||
|
|
||||||
|
eval[color] += popcount64(pos->bb[color][bb]) * P_LETTER(piece);
|
||||||
|
bit_for_each64_2(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
|
||||||
|
log(5, "\n");
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(2, "eval:%d white:%d black:%d\n", eval[WHITE] - eval[BLACK],
|
||||||
|
eval[WHITE], eval[BLACK]);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return eval[WHITE] - eval[BLACK];
|
||||||
|
}
|
||||||
47
src/eval-simple.h
Normal file
47
src/eval-simple.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* eval-simple.h - simple position evaluation.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 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 EVAL_SIMPLE_H
|
||||||
|
#define EVAL_SIMPLE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
|
|
||||||
|
/* no queen on board */
|
||||||
|
#define simple_no_queen(p, c) \
|
||||||
|
( !(p)->bb[c][BB_QUEEN] )
|
||||||
|
|
||||||
|
#define simple_one_queen(p, c) \
|
||||||
|
( popcount64((p)->bb[c][BB_QUEEN]) == 1 )
|
||||||
|
|
||||||
|
#define simple_no_rook(p, c) \
|
||||||
|
(!(p)->bb[c][BB_ROOK])
|
||||||
|
|
||||||
|
#define simple_one_minor_piece(p, c) \
|
||||||
|
(popcount64((p)->bb[c][BB_KNIGHT] | (p)->bb[c][BB_BISHOP]) == 1)
|
||||||
|
|
||||||
|
#define simple_is_endgame(p) \
|
||||||
|
( (simple_no_queen(p, WHITE) || \
|
||||||
|
(simple_one_queen(p, WHITE) && \
|
||||||
|
simple_no_rook(p, WHITE) && \
|
||||||
|
simple_one_minor_piece(p, WHITE))) \
|
||||||
|
&& \
|
||||||
|
(simple_no_queen(p, BLACK) || \
|
||||||
|
(simple_one_queen(p, BLACK) && \
|
||||||
|
simple_no_rook(p, BLACK) && \
|
||||||
|
simple_one_minor_piece(p, BLACK))) )
|
||||||
|
|
||||||
|
void eval_simple_init(void);
|
||||||
|
eval_t eval_simple(pos_t *pos);
|
||||||
|
|
||||||
|
#endif /* EVAL_SIMPLE_H */
|
||||||
150
src/eval.c
150
src/eval.c
@@ -1,11 +1,11 @@
|
|||||||
/* eval.c - static position evaluation.
|
/* eval.c - static position evaluation.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 Bruno Raoult ("br")
|
* Copyright (C) 2021-2023 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.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -13,93 +13,83 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <list.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "position.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "list.h"
|
#include "eval-simple.h"
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
eval_t eval(pos_t *pos)
|
inline eval_t eval_material(pos_t *pos, bool color)
|
||||||
{
|
{
|
||||||
eval_t material[2] = {0};
|
|
||||||
eval_t control[2] = {0};
|
|
||||||
eval_t res = 0;
|
eval_t res = 0;
|
||||||
struct list_head *p_cur, *p_tmp, *list;
|
|
||||||
piece_list_t *piece;
|
|
||||||
|
|
||||||
/* 1) pieces value
|
/* I need to do something about the king, if it can be potentially taken
|
||||||
|
* if pseudo-moves include a pinned piece on King.
|
||||||
*/
|
*/
|
||||||
for (int color=0; color <2; ++color) {
|
for (uint piece = PAWN; piece < KING; piece <<= 1) {
|
||||||
list = &pos->pieces[color];
|
uint bb = PIECETOBB(piece);
|
||||||
list_for_each_safe(p_cur, p_tmp, list) {
|
# ifdef DEBUG_EVAL
|
||||||
piece = list_entry(p_cur, piece_list_t, list);
|
log_f(2, "color=%u piece=%u bb=%u=%c count=%ul val=%ld\n",
|
||||||
if (PIECE(piece->piece) != KING)
|
color, piece, bb, P_LETTER(piece), popcount64(pos->bb[color][bb]),
|
||||||
material[color] += piece->value;
|
P_VALUE(piece));
|
||||||
}
|
# endif
|
||||||
|
/* attention here */
|
||||||
|
res += popcount64(pos->bb[color][bb]) * P_VALUE(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = material[WHITE] - material[BLACK];
|
|
||||||
# ifdef DEBUG_EVAL
|
|
||||||
log_f(2, "material: W:%ld B:%ld eval=%ld (%.3f pawns)\n",
|
|
||||||
material[WHITE], material[BLACK],
|
|
||||||
material[WHITE] - material[BLACK], (float)res/100);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/* 2) square control: 10 square controls diff = 1 pawn
|
|
||||||
*/
|
|
||||||
control[WHITE] = popcount64(pos->controlled[WHITE]);
|
|
||||||
control[BLACK] = popcount64(pos->controlled[BLACK]);
|
|
||||||
res = control[WHITE] - control[BLACK];
|
|
||||||
# ifdef DEBUG_EVAL
|
|
||||||
log_f(2, "square control: W:%ld B:%ld eval=%ld (%.3f pawns)\n",
|
|
||||||
control[WHITE], control[BLACK],
|
|
||||||
res, (float)res/10);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/* 3) mobility: 5 mobility diff = 1 pawn
|
|
||||||
*/
|
|
||||||
res = pos->mobility[WHITE] - pos->mobility[BLACK];
|
|
||||||
# ifdef DEBUG_EVAL
|
|
||||||
log_f(2, "mobility: W:%ld B:%ld eval=%ld (%.3f pawns)\n",
|
|
||||||
pos->mobility[WHITE], pos->mobility[BLACK],
|
|
||||||
res, (float)res/5);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
res = material[WHITE] - material[BLACK] +
|
|
||||||
(control[WHITE] - control[BLACK]) * 10 +
|
|
||||||
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 20;
|
|
||||||
# ifdef DEBUG_EVAL
|
|
||||||
log_f(2, "eval: %ld (%.3f pawns)\n",
|
|
||||||
res, (float)res/100);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BIN_eval
|
inline eval_t eval_mobility(pos_t *pos, bool color)
|
||||||
#include "fen.h"
|
|
||||||
#include "move.h"
|
|
||||||
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
{
|
||||||
pos_t *pos;
|
return pos->mobility[color];
|
||||||
eval_t res;
|
}
|
||||||
|
|
||||||
debug_init(2);
|
inline eval_t eval_square_control(pos_t *pos, bool color)
|
||||||
piece_pool_init();
|
{
|
||||||
moves_pool_init();
|
return popcount64(pos->controlled[color]);
|
||||||
pos_pool_init();
|
}
|
||||||
pos = pos_get();
|
|
||||||
|
eval_t eval(pos_t *pos)
|
||||||
if (ac == 1) {
|
{
|
||||||
pos_startpos(pos);
|
eval_t simple = 0, control[2] = {0};
|
||||||
} else {
|
|
||||||
fen2pos(pos, av[1]);
|
if (pos->eval != EVAL_INVALID)
|
||||||
}
|
return pos->eval;
|
||||||
|
|
||||||
moves_gen(pos, OPPONENT(pos->turn), false);
|
/* 1) pieces value */
|
||||||
moves_gen(pos, pos->turn, true);
|
//material[WHITE] = eval_material(pos, WHITE);
|
||||||
pos_print(pos);
|
//material[BLACK] = eval_material(pos, BLACK);
|
||||||
pos_pieces_print(pos);
|
simple = eval_simple(pos);
|
||||||
res = eval(pos);
|
|
||||||
printf("eval=%ld (%.3f pawns)\n", res, (float)res/100);
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(2, "eval_simple=%d\n", simple);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* 2) square control: 10 square controls diff = 1 pawn */
|
||||||
|
control[WHITE] = eval_square_control(pos, WHITE);
|
||||||
|
control[BLACK] = eval_square_control(pos, BLACK);
|
||||||
|
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(2, "square control: W:%d B:%d diff=%d\n",
|
||||||
|
control[WHITE], control[BLACK],
|
||||||
|
(control[WHITE] - control[BLACK]) * 10);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* 3) mobility: 10 mobility diff = 1 pawn
|
||||||
|
*/
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(2, "mobility: W:%u B:%u diff=%d\n",
|
||||||
|
pos->mobility[WHITE], pos->mobility[BLACK],
|
||||||
|
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
eval_t res = simple +
|
||||||
|
(control[WHITE] - control[BLACK]) * 10 +
|
||||||
|
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10;
|
||||||
|
# ifdef DEBUG_EVAL
|
||||||
|
log_f(2, "eval: %d\n", res);
|
||||||
|
# endif
|
||||||
|
pos->eval = res;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
20
src/eval.h
20
src/eval.h
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -14,7 +14,23 @@
|
|||||||
#ifndef EVAL_H
|
#ifndef EVAL_H
|
||||||
#define EVAL_H
|
#define EVAL_H
|
||||||
|
|
||||||
#include "position.h"
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "chessdefs.h"
|
||||||
|
#include "piece.h"
|
||||||
|
|
||||||
|
/* max pieces eval is KING_VALUE + 9*QUEEN_VALUE + 2*ROOK_VALUE + 2*BISHOP_VALUE
|
||||||
|
* + 2*KNIGHT_VALUE which around 30000.
|
||||||
|
* We are on secure side with -50000/+50000
|
||||||
|
*/
|
||||||
|
#define EVAL_MAX (50000)
|
||||||
|
#define EVAL_MIN (-EVAL_MAX)
|
||||||
|
#define EVAL_INVALID INT_MIN
|
||||||
|
#define EVAL_MATE EVAL_MAX
|
||||||
|
|
||||||
|
eval_t eval_material(pos_t *pos, bool color);
|
||||||
|
eval_t eval_mobility(pos_t *pos, bool color);
|
||||||
|
eval_t eval_square_control(pos_t *pos, bool color);
|
||||||
|
|
||||||
eval_t eval(pos_t *pos);
|
eval_t eval(pos_t *pos);
|
||||||
|
|
||||||
|
|||||||
49
src/fen.c
49
src/fen.c
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include <debug.h>
|
||||||
|
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
pos_t *fen2pos(pos_t *pos, char *fen)
|
pos_t *fen2pos(pos_t *pos, char *fen)
|
||||||
{
|
{
|
||||||
char *p = fen;
|
char *p = fen;
|
||||||
short rank, file, skip, color;
|
short rank, file, skip, color, bbpiece;
|
||||||
piece_t piece;
|
piece_t piece;
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
# define SKIP_BLANK(p) for(;*(p) == ' '; (p)++)
|
# define SKIP_BLANK(p) for(;*(p) == ' '; (p)++)
|
||||||
@@ -61,34 +62,41 @@ pos_t *fen2pos(pos_t *pos, char *fen)
|
|||||||
char cp = toupper(*p);
|
char cp = toupper(*p);
|
||||||
switch (cp) {
|
switch (cp) {
|
||||||
case CHAR_PAWN:
|
case CHAR_PAWN:
|
||||||
|
bbpiece = BB_PAWN;
|
||||||
piece = PAWN;
|
piece = PAWN;
|
||||||
goto set_square;
|
goto set_square;
|
||||||
case CHAR_KNIGHT:
|
case CHAR_KNIGHT:
|
||||||
|
bbpiece = BB_KNIGHT;
|
||||||
piece = KNIGHT;
|
piece = KNIGHT;
|
||||||
goto set_square;
|
goto set_square;
|
||||||
case CHAR_BISHOP:
|
case CHAR_BISHOP:
|
||||||
|
bbpiece = BB_BISHOP;
|
||||||
piece = BISHOP;
|
piece = BISHOP;
|
||||||
goto set_square;
|
goto set_square;
|
||||||
case CHAR_ROOK:
|
case CHAR_ROOK:
|
||||||
|
bbpiece = BB_ROOK;
|
||||||
piece = ROOK;
|
piece = ROOK;
|
||||||
goto set_square;
|
goto set_square;
|
||||||
case CHAR_QUEEN:
|
case CHAR_QUEEN:
|
||||||
|
bbpiece = BB_QUEEN;
|
||||||
piece = QUEEN;
|
piece = QUEEN;
|
||||||
goto set_square;
|
goto set_square;
|
||||||
case CHAR_KING:
|
case CHAR_KING:
|
||||||
|
bbpiece = BB_KING;
|
||||||
piece = KING;
|
piece = KING;
|
||||||
pos->king[color]=SQ88(file, rank);
|
//pos->bb[color][BB_KING] = BB(file, rank);
|
||||||
//goto set_square;
|
//goto set_square;
|
||||||
set_square:
|
set_square:
|
||||||
# ifdef DEBUG_FEN
|
# ifdef DEBUG_FEN
|
||||||
log_i(5, "f=%d r=%d *p=%c piece=%c color=%d\n",
|
log_i(5, "f=%d r=%d *p=%c piece=%c color=%d\n",
|
||||||
file, rank, *p, cp, color);
|
file, rank, *p, cp, color);
|
||||||
# endif
|
# endif
|
||||||
|
pos->bb[color][bbpiece] |= BB(file, rank);
|
||||||
pos->occupied[color] |= BB(file, rank);
|
pos->occupied[color] |= BB(file, rank);
|
||||||
SET_COLOR(piece, color);
|
SET_COLOR(piece, color);
|
||||||
board[SQ88(file, rank)].piece = piece;
|
board[SQ88(file, rank)].piece = piece;
|
||||||
board[SQ88(file, rank)].s_piece =
|
board[SQ88(file, rank)].s_piece =
|
||||||
piece_add(pos, piece, SQUARE(file, rank));
|
piece_add(pos, piece, SQ88(file, rank));
|
||||||
file++;
|
file++;
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
@@ -146,8 +154,10 @@ pos_t *fen2pos(pos_t *pos, char *fen)
|
|||||||
SKIP_BLANK(p);
|
SKIP_BLANK(p);
|
||||||
pos->en_passant = 0;
|
pos->en_passant = 0;
|
||||||
if (*p != '-') {
|
if (*p != '-') {
|
||||||
SET_F(pos->en_passant, C2FILE(*p++));
|
//SET_F(pos->en_passant, C2FILE(*p++));
|
||||||
SET_R(pos->en_passant, C2RANK(*p++));
|
//SET_R(pos->en_passant, C2RANK(*p++));
|
||||||
|
pos->en_passant = SQ88(C2FILE(*p), C2RANK(*(p+1)));
|
||||||
|
pos += 2;
|
||||||
} else {
|
} else {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
@@ -156,25 +166,10 @@ pos_t *fen2pos(pos_t *pos, char *fen)
|
|||||||
* 6) current move number
|
* 6) current move number
|
||||||
*/
|
*/
|
||||||
SKIP_BLANK(p);
|
SKIP_BLANK(p);
|
||||||
log_i(5, "pos=%d\n", (int)(p-fen));
|
//log_i(5, "pos=%d\n", (int)(p-fen));
|
||||||
sscanf(p, "%hd %hd", &pos->clock_50, &pos->curmove);
|
sscanf(p, "%hd %hd", &pos->clock_50, &pos->curmove);
|
||||||
|
# ifdef DEBUG_FEN
|
||||||
|
log_i(5, "50 rule=%d current move=%d\n", pos->clock_50, pos->curmove);
|
||||||
|
# endif
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BIN_fen
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
|
||||||
pos_t *pos;
|
|
||||||
|
|
||||||
debug_init(5);
|
|
||||||
piece_pool_init();
|
|
||||||
pos_pool_init();
|
|
||||||
pos = pos_get();
|
|
||||||
if (ac == 1) {
|
|
||||||
pos_startpos(pos);
|
|
||||||
} else {
|
|
||||||
fen2pos(pos, av[1]);
|
|
||||||
}
|
|
||||||
pos_print(pos);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
|
|||||||
995
src/list.h
995
src/list.h
@@ -1,995 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
/* adaptation of kernel's <linux/list.h>
|
|
||||||
* Main change is that I don't use READ_ONCE and WRITE_ONCE
|
|
||||||
* See https://www.kernel.org/doc/Documentation/memory-barriers.txt
|
|
||||||
*/
|
|
||||||
#ifndef __BR_LIST_H
|
|
||||||
#define __BR_LIST_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/************ originally in <include/linux/types.h> */
|
|
||||||
struct list_head {
|
|
||||||
struct list_head *next, *prev;
|
|
||||||
};
|
|
||||||
struct hlist_head {
|
|
||||||
struct hlist_node *first;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hlist_node {
|
|
||||||
struct hlist_node *next, **pprev;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************ originally in <include/linux/poison.h> */
|
|
||||||
# define POISON_POINTER_DELTA 0
|
|
||||||
/* These are non-NULL pointers that will result in page faults
|
|
||||||
* under normal circumstances, used to verify that nobody uses
|
|
||||||
* non-initialized list entries.
|
|
||||||
*/
|
|
||||||
#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA)
|
|
||||||
#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA)
|
|
||||||
|
|
||||||
/************ originally in <include/linux/kernel.h> */
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
|
||||||
void *__mptr = (void *)(ptr); \
|
|
||||||
((type *)(__mptr - offsetof(type, member))); })
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Circular doubly linked list implementation.
|
|
||||||
*
|
|
||||||
* Some of the internal functions ("__xxx") are useful when
|
|
||||||
* manipulating whole lists rather than single entries, as
|
|
||||||
* sometimes we already know the next/prev entries and we can
|
|
||||||
* generate better code by using them directly rather than
|
|
||||||
* using the generic single-entry routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
|
||||||
|
|
||||||
#define LIST_HEAD(name) \
|
|
||||||
struct list_head name = LIST_HEAD_INIT(name)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* INIT_LIST_HEAD - Initialize a list_head structure
|
|
||||||
* @list: list_head structure to be initialized.
|
|
||||||
*
|
|
||||||
* Initializes the list_head to point to itself. If it is a list header,
|
|
||||||
* the result is an empty list.
|
|
||||||
*/
|
|
||||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
|
||||||
{
|
|
||||||
list->next = list;
|
|
||||||
list->prev = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert a new entry between two known consecutive entries.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_add(struct list_head *new,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
next->prev = new;
|
|
||||||
new->next = next;
|
|
||||||
new->prev = prev;
|
|
||||||
prev->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it after
|
|
||||||
*
|
|
||||||
* Insert a new entry after the specified head.
|
|
||||||
* This is good for implementing stacks.
|
|
||||||
*/
|
|
||||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add_tail - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it before
|
|
||||||
*
|
|
||||||
* Insert a new entry before the specified head.
|
|
||||||
* This is useful for implementing queues.
|
|
||||||
*/
|
|
||||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a list entry by making the prev/next entries
|
|
||||||
* point to each other.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
|
||||||
{
|
|
||||||
next->prev = prev;
|
|
||||||
prev->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a list entry and clear the 'prev' pointer.
|
|
||||||
*
|
|
||||||
* This is a special-purpose list clearing method used in the networking code
|
|
||||||
* for lists allocated as per-cpu, where we don't want to incur the extra
|
|
||||||
* WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this
|
|
||||||
* needs to check the node 'prev' pointer instead of calling list_empty().
|
|
||||||
*/
|
|
||||||
static inline void __list_del_clearprev(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
entry->prev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_del_entry(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del - deletes entry from list.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
* Note: list_empty() on entry does not return true after this, the entry is
|
|
||||||
* in an undefined state.
|
|
||||||
*/
|
|
||||||
static inline void list_del(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del_entry(entry);
|
|
||||||
entry->next = LIST_POISON1;
|
|
||||||
entry->prev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_replace - replace old entry by new one
|
|
||||||
* @old : the element to be replaced
|
|
||||||
* @new : the new element to insert
|
|
||||||
*
|
|
||||||
* If @old was empty, it will be overwritten.
|
|
||||||
*/
|
|
||||||
static inline void list_replace(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
new->next = old->next;
|
|
||||||
new->next->prev = new;
|
|
||||||
new->prev = old->prev;
|
|
||||||
new->prev->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_replace_init - replace old entry by new one and initialize the old one
|
|
||||||
* @old : the element to be replaced
|
|
||||||
* @new : the new element to insert
|
|
||||||
*
|
|
||||||
* If @old was empty, it will be overwritten.
|
|
||||||
*/
|
|
||||||
static inline void list_replace_init(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
list_replace(old, new);
|
|
||||||
INIT_LIST_HEAD(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
|
|
||||||
* @entry1: the location to place entry2
|
|
||||||
* @entry2: the location to place entry1
|
|
||||||
*/
|
|
||||||
static inline void list_swap(struct list_head *entry1,
|
|
||||||
struct list_head *entry2)
|
|
||||||
{
|
|
||||||
struct list_head *pos = entry2->prev;
|
|
||||||
|
|
||||||
list_del(entry2);
|
|
||||||
list_replace(entry1, entry2);
|
|
||||||
if (pos == entry1)
|
|
||||||
pos = entry2;
|
|
||||||
list_add(entry1, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del_init - deletes entry from list and reinitialize it.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
*/
|
|
||||||
static inline void list_del_init(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del_entry(entry);
|
|
||||||
INIT_LIST_HEAD(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move - delete from one list and add as another's head
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will precede our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del_entry(list);
|
|
||||||
list_add(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move_tail - delete from one list and add as another's tail
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will follow our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del_entry(list);
|
|
||||||
list_add_tail(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_bulk_move_tail - move a subsection of a list to its tail
|
|
||||||
* @head: the head that will follow our entry
|
|
||||||
* @first: first entry to move
|
|
||||||
* @last: last entry to move, can be the same as first
|
|
||||||
*
|
|
||||||
* Move all entries between @first and including @last before @head.
|
|
||||||
* All three entries must belong to the same linked list.
|
|
||||||
*/
|
|
||||||
static inline void list_bulk_move_tail(struct list_head *head,
|
|
||||||
struct list_head *first,
|
|
||||||
struct list_head *last)
|
|
||||||
{
|
|
||||||
first->prev->next = last->next;
|
|
||||||
last->next->prev = first->prev;
|
|
||||||
|
|
||||||
head->prev->next = first;
|
|
||||||
first->prev = head->prev;
|
|
||||||
|
|
||||||
last->next = head;
|
|
||||||
head->prev = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_first -- tests whether @list is the first entry in list @head
|
|
||||||
* @list: the entry to test
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline int list_is_first(const struct list_head *list,
|
|
||||||
const struct list_head *head)
|
|
||||||
{
|
|
||||||
return list->prev == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_last - tests whether @list is the last entry in list @head
|
|
||||||
* @list: the entry to test
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline int list_is_last(const struct list_head *list,
|
|
||||||
const struct list_head *head)
|
|
||||||
{
|
|
||||||
return list->next == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_empty - tests whether a list is empty
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_empty(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return head->next == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_rotate_left - rotate the list to the left
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline void list_rotate_left(struct list_head *head)
|
|
||||||
{
|
|
||||||
struct list_head *first;
|
|
||||||
|
|
||||||
if (!list_empty(head)) {
|
|
||||||
first = head->next;
|
|
||||||
list_move_tail(first, head);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_rotate_to_front() - Rotate list to specific item.
|
|
||||||
* @list: The desired new front of the list.
|
|
||||||
* @head: The head of the list.
|
|
||||||
*
|
|
||||||
* Rotates list so that @list becomes the new front of the list.
|
|
||||||
*/
|
|
||||||
static inline void list_rotate_to_front(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Deletes the list head from the list denoted by @head and
|
|
||||||
* places it as the tail of @list, this effectively rotates the
|
|
||||||
* list so that @list is at the front.
|
|
||||||
*/
|
|
||||||
list_move_tail(head, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_singular - tests whether a list has just one entry.
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_is_singular(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return !list_empty(head) && (head->next == head->prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
struct list_head *new_first = entry->next;
|
|
||||||
list->next = head->next;
|
|
||||||
list->next->prev = list;
|
|
||||||
list->prev = entry;
|
|
||||||
entry->next = list;
|
|
||||||
head->next = new_first;
|
|
||||||
new_first->prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_cut_position - cut a list into two
|
|
||||||
* @list: a new list to add all removed entries
|
|
||||||
* @head: a list with entries
|
|
||||||
* @entry: an entry within head, could be the head itself
|
|
||||||
* and if so we won't cut the list
|
|
||||||
*
|
|
||||||
* This helper moves the initial part of @head, up to and
|
|
||||||
* including @entry, from @head to @list. You should
|
|
||||||
* pass on @entry an element you know is on @head. @list
|
|
||||||
* should be an empty list or a list you do not care about
|
|
||||||
* losing its data.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static inline void list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
if (list_empty(head))
|
|
||||||
return;
|
|
||||||
if (list_is_singular(head) &&
|
|
||||||
(head->next != entry && head != entry))
|
|
||||||
return;
|
|
||||||
if (entry == head)
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
else
|
|
||||||
__list_cut_position(list, head, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_cut_before - cut a list into two, before given entry
|
|
||||||
* @list: a new list to add all removed entries
|
|
||||||
* @head: a list with entries
|
|
||||||
* @entry: an entry within head, could be the head itself
|
|
||||||
*
|
|
||||||
* This helper moves the initial part of @head, up to but
|
|
||||||
* excluding @entry, from @head to @list. You should pass
|
|
||||||
* in @entry an element you know is on @head. @list should
|
|
||||||
* be an empty list or a list you do not care about losing
|
|
||||||
* its data.
|
|
||||||
* If @entry == @head, all entries on @head are moved to
|
|
||||||
* @list.
|
|
||||||
*/
|
|
||||||
static inline void list_cut_before(struct list_head *list,
|
|
||||||
struct list_head *head,
|
|
||||||
struct list_head *entry)
|
|
||||||
{
|
|
||||||
if (head->next == entry) {
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
list->next = head->next;
|
|
||||||
list->next->prev = list;
|
|
||||||
list->prev = entry->prev;
|
|
||||||
list->prev->next = list;
|
|
||||||
head->next = entry;
|
|
||||||
entry->prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_splice(const struct list_head *list,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
struct list_head *first = list->next;
|
|
||||||
struct list_head *last = list->prev;
|
|
||||||
|
|
||||||
first->prev = prev;
|
|
||||||
prev->next = first;
|
|
||||||
|
|
||||||
last->next = next;
|
|
||||||
next->prev = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice - join two lists, this is designed for stacks
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice(const struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail - join two lists, each list being a queue
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* Each of the lists is a queue.
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_entry - get the struct for this entry
|
|
||||||
* @ptr: the &struct list_head pointer.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_entry(ptr, type, member) \
|
|
||||||
container_of(ptr, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_first_entry - get the first element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note, that list is expected to be not empty.
|
|
||||||
*/
|
|
||||||
#define list_first_entry(ptr, type, member) \
|
|
||||||
list_entry((ptr)->next, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_last_entry - get the last element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note, that list is expected to be not empty.
|
|
||||||
*/
|
|
||||||
#define list_last_entry(ptr, type, member) \
|
|
||||||
list_entry((ptr)->prev, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_first_entry_or_null - get the first element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Note that if the list is empty, it returns NULL.
|
|
||||||
*/
|
|
||||||
#define list_first_entry_or_null(ptr, type, member) ({ \
|
|
||||||
struct list_head *head__ = (ptr); \
|
|
||||||
struct list_head *pos__ = head__->next; \
|
|
||||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_next_entry - get the next element in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_next_entry(pos, member) \
|
|
||||||
list_entry((pos)->member.next, __typeof__(*(pos)), member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_prev_entry - get the prev element in list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_prev_entry(pos, member) \
|
|
||||||
list_entry((pos)->member.prev, __typeof__(*(pos)), member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each - iterate over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each(pos, head) \
|
|
||||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_continue - continue iteration over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*
|
|
||||||
* Continue to iterate over a list, continuing after the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_continue(pos, head) \
|
|
||||||
for (pos = pos->next; pos != (head); pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev - iterate over a list backwards
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev(pos, head) \
|
|
||||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
|
||||||
pos = n, n = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->prev, n = pos->prev; \
|
|
||||||
pos != (head); \
|
|
||||||
pos = n, n = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_entry_is_head - test if the entry points to the head of the list
|
|
||||||
* @pos: the type * to cursor
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_entry_is_head(pos, head, member) \
|
|
||||||
(&pos->member == (head))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry(pos, head, member) \
|
|
||||||
for (pos = list_first_entry(head, __typeof__(*pos), member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_reverse(pos, head, member) \
|
|
||||||
for (pos = list_last_entry(head, __typeof__(*pos), member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
|
||||||
* @pos: the type * to use as a start point
|
|
||||||
* @head: the head of the list
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
|
||||||
*/
|
|
||||||
#define list_prepare_entry(pos, head, member) \
|
|
||||||
((pos) ? : list_entry(head, __typeof__(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue - continue iteration over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Continue to iterate over list of given type, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue(pos, head, member) \
|
|
||||||
for (pos = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Start to iterate over list of given type backwards, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
|
||||||
for (pos = list_prev_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing from current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_from(pos, head, member) \
|
|
||||||
for (; !list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_next_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_from_reverse - iterate backwards over list of given type
|
|
||||||
* from the current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate backwards over list of given type, continuing from current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_from_reverse(pos, head, member) \
|
|
||||||
for (; !list_entry_is_head(pos, head, member); \
|
|
||||||
pos = list_prev_entry(pos, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
|
||||||
for (pos = list_first_entry(head, __typeof__(*pos), member), \
|
|
||||||
n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing after current point,
|
|
||||||
* safe against removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
|
||||||
for (pos = list_next_entry(pos, member), \
|
|
||||||
n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type from current point, safe against
|
|
||||||
* removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
|
||||||
for (n = list_next_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_next_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* Iterate backwards over list of given type, safe against removal
|
|
||||||
* of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
|
||||||
for (pos = list_last_entry(head, __typeof__(*pos), member), \
|
|
||||||
n = list_prev_entry(pos, member); \
|
|
||||||
!list_entry_is_head(pos, head, member); \
|
|
||||||
pos = n, n = list_prev_entry(n, member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
|
||||||
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
|
||||||
* @n: temporary storage used in list_for_each_entry_safe
|
|
||||||
* @member: the name of the list_head within the struct.
|
|
||||||
*
|
|
||||||
* list_safe_reset_next is not safe to use in general if the list may be
|
|
||||||
* modified concurrently (eg. the lock is dropped in the loop body). An
|
|
||||||
* exception to this is if the cursor element (pos) is pinned in the list,
|
|
||||||
* and list_safe_reset_next is called after re-taking the lock and before
|
|
||||||
* completing the current iteration of the loop body.
|
|
||||||
*/
|
|
||||||
#define list_safe_reset_next(pos, n, member) \
|
|
||||||
n = list_next_entry(pos, member)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Double linked lists with a single pointer list head.
|
|
||||||
* Mostly useful for hash tables where the two pointer list head is
|
|
||||||
* too wasteful.
|
|
||||||
* You lose the ability to access the tail in O(1).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HLIST_HEAD_INIT { .first = NULL }
|
|
||||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
|
||||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
|
||||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
|
||||||
{
|
|
||||||
h->next = NULL;
|
|
||||||
h->pprev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_unhashed - Has node been removed from list and reinitialized?
|
|
||||||
* @h: Node to be checked
|
|
||||||
*
|
|
||||||
* Not that not all removal functions will leave a node in unhashed
|
|
||||||
* state. For example, hlist_nulls_del_init_rcu() does leave the
|
|
||||||
* node in unhashed state, but hlist_nulls_del() does not.
|
|
||||||
*/
|
|
||||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return !h->pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_unhashed_lockless - Version of hlist_unhashed for lockless use
|
|
||||||
* @h: Node to be checked
|
|
||||||
*
|
|
||||||
* This variant of hlist_unhashed() must be used in lockless contexts
|
|
||||||
* to avoid potential load-tearing. The READ_ONCE() is paired with the
|
|
||||||
* various WRITE_ONCE() in hlist helpers that are defined below.
|
|
||||||
*/
|
|
||||||
static inline int hlist_unhashed_lockless(const struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return !h->pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_empty - Is the specified hlist_head structure an empty hlist?
|
|
||||||
* @h: Structure to check.
|
|
||||||
*/
|
|
||||||
static inline int hlist_empty(const struct hlist_head *h)
|
|
||||||
{
|
|
||||||
return !h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
struct hlist_node *next = n->next;
|
|
||||||
struct hlist_node **pprev = n->pprev;
|
|
||||||
|
|
||||||
*pprev = next;
|
|
||||||
if (next)
|
|
||||||
next->pprev = pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_del - Delete the specified hlist_node from its list
|
|
||||||
* @n: Node to delete.
|
|
||||||
*
|
|
||||||
* Note that this function leaves the node in hashed state. Use
|
|
||||||
* hlist_del_init() or similar instead to unhash @n.
|
|
||||||
*/
|
|
||||||
static inline void hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
__hlist_del(n);
|
|
||||||
n->next = LIST_POISON1;
|
|
||||||
n->pprev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_del_init - Delete the specified hlist_node from its list and initialize
|
|
||||||
* @n: Node to delete.
|
|
||||||
*
|
|
||||||
* Note that this function leaves the node in unhashed state.
|
|
||||||
*/
|
|
||||||
static inline void hlist_del_init(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
if (!hlist_unhashed(n)) {
|
|
||||||
__hlist_del(n);
|
|
||||||
INIT_HLIST_NODE(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_head - add a new entry at the beginning of the hlist
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @h: hlist head to add it after
|
|
||||||
*
|
|
||||||
* Insert a new entry after the specified head.
|
|
||||||
* This is good for implementing stacks.
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
|
||||||
{
|
|
||||||
struct hlist_node *first = h->first;
|
|
||||||
n->next = first;
|
|
||||||
if (first)
|
|
||||||
first->pprev = &n->next;
|
|
||||||
h->first = n;
|
|
||||||
n->pprev = &h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_before - add a new entry before the one specified
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @next: hlist node to add it before, which must be non-NULL
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_before(struct hlist_node *n,
|
|
||||||
struct hlist_node *next)
|
|
||||||
{
|
|
||||||
n->pprev = next->pprev;
|
|
||||||
n->next = next;
|
|
||||||
next->pprev = &n->next;
|
|
||||||
*(n->pprev) = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_behind - add a new entry after the one specified
|
|
||||||
* @n: new entry to be added
|
|
||||||
* @prev: hlist node to add it after, which must be non-NULL
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_behind(struct hlist_node *n,
|
|
||||||
struct hlist_node *prev)
|
|
||||||
{
|
|
||||||
n->next = prev->next;
|
|
||||||
prev->next = n;
|
|
||||||
n->pprev = &prev->next;
|
|
||||||
|
|
||||||
if (n->next)
|
|
||||||
n->next->pprev = &n->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_add_fake - create a fake hlist consisting of a single headless node
|
|
||||||
* @n: Node to make a fake list out of
|
|
||||||
*
|
|
||||||
* This makes @n appear to be its own predecessor on a headless hlist.
|
|
||||||
* The point of this is to allow things like hlist_del() to work correctly
|
|
||||||
* in cases where there is no list.
|
|
||||||
*/
|
|
||||||
static inline void hlist_add_fake(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
n->pprev = &n->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_fake: Is this node a fake hlist?
|
|
||||||
* @h: Node to check for being a self-referential fake hlist.
|
|
||||||
*/
|
|
||||||
static inline bool hlist_fake(struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return h->pprev == &h->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_is_singular_node - is node the only element of the specified hlist?
|
|
||||||
* @n: Node to check for singularity.
|
|
||||||
* @h: Header for potentially singular list.
|
|
||||||
*
|
|
||||||
* Check whether the node is the only node of the head without
|
|
||||||
* accessing head, thus avoiding unnecessary cache misses.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
|
|
||||||
{
|
|
||||||
return !n->next && n->pprev == &h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_move_list - Move an hlist
|
|
||||||
* @old: hlist_head for old list.
|
|
||||||
* @new: hlist_head for new list.
|
|
||||||
*
|
|
||||||
* Move a list from one list head to another. Fixup the pprev
|
|
||||||
* reference of the first entry if it exists.
|
|
||||||
*/
|
|
||||||
static inline void hlist_move_list(struct hlist_head *old,
|
|
||||||
struct hlist_head *new)
|
|
||||||
{
|
|
||||||
new->first = old->first;
|
|
||||||
if (new->first)
|
|
||||||
new->first->pprev = &new->first;
|
|
||||||
old->first = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
|
||||||
|
|
||||||
#define hlist_for_each(pos, head) \
|
|
||||||
for (pos = (head)->first; pos ; pos = pos->next)
|
|
||||||
|
|
||||||
#define hlist_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
|
||||||
pos = n)
|
|
||||||
|
|
||||||
#define hlist_entry_safe(ptr, type, member) \
|
|
||||||
({ __typeof__(ptr) ____ptr = (ptr); \
|
|
||||||
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry(pos, head, member) \
|
|
||||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*(pos)), member); \
|
|
||||||
pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_continue(pos, member) \
|
|
||||||
for (pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member); \
|
|
||||||
pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_from(pos, member) \
|
|
||||||
for (; pos; \
|
|
||||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: a &struct hlist_node to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_safe(pos, n, head, member) \
|
|
||||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*pos), member); \
|
|
||||||
pos && ({ n = pos->member.next; 1; }); \
|
|
||||||
pos = hlist_entry_safe(n, __typeof__(*pos), member))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
666
src/move.c
666
src/move.c
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -14,12 +14,18 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <br.h>
|
||||||
|
#include <list.h>
|
||||||
|
#include <list_sort.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
#include "bitboard.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "list.h"
|
#include "eval.h"
|
||||||
#include "debug.h"
|
#include "eval-simple.h"
|
||||||
|
|
||||||
static pool_t *moves_pool;
|
static pool_t *moves_pool;
|
||||||
|
|
||||||
@@ -35,6 +41,7 @@ static struct vector {
|
|||||||
[KING] = { 8, 0, { -1, -16, 1, 16, -15, -17, 15, 17 }}
|
[KING] = { 8, 0, { -1, -16, 1, 16, -15, -17, 15, 17 }}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* squares needed to be empty & not controlled by opponent for castle.
|
/* squares needed to be empty & not controlled by opponent for castle.
|
||||||
* For black castle, same values 7 rows higher (>> 7*8)
|
* For black castle, same values 7 rows higher (>> 7*8)
|
||||||
*/
|
*/
|
||||||
@@ -50,7 +57,7 @@ static struct can_castle {
|
|||||||
pool_t *moves_pool_init()
|
pool_t *moves_pool_init()
|
||||||
{
|
{
|
||||||
if (!moves_pool)
|
if (!moves_pool)
|
||||||
moves_pool = pool_init("moves", 128, sizeof(move_t));
|
moves_pool = pool_create("moves", 128, sizeof(move_t));
|
||||||
return moves_pool;
|
return moves_pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,47 +67,69 @@ void moves_pool_stats()
|
|||||||
pool_stats(moves_pool);
|
pool_stats(moves_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
int move_print(move_t *move, move_flags_t flags)
|
/**
|
||||||
|
* move_print() - print a move
|
||||||
|
* @movenum: move number
|
||||||
|
* @move: &move to display
|
||||||
|
* @flags: options to display
|
||||||
|
*
|
||||||
|
* Possible flags are:
|
||||||
|
* M_PR_CAPT: print move if capture
|
||||||
|
* M_PR_NCAPT: print move if non capture
|
||||||
|
* M_PR_NUM: print also move number
|
||||||
|
* M_PR_LONG: print long notation
|
||||||
|
* M_PR_NL: print a newline after move
|
||||||
|
* M_PR_EVAL: print move eval
|
||||||
|
*
|
||||||
|
* @return: 0 if nothing printed, 1 otherwise
|
||||||
|
*/
|
||||||
|
int move_print(int movenum, move_t *move, move_flags_t flags)
|
||||||
{
|
{
|
||||||
if (flags & M_PR_CAPT && !(move->flags & M_CAPTURE)) {
|
if ((flags & M_PR_CAPT) && !(move->flags & M_CAPTURE)) {
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(5, "capture & %#04x\n", move->flags);
|
log_i(9, "skipping capture & %#04x\n", move->flags);
|
||||||
# endif
|
# endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (flags & M_PR_NCAPT && move->flags & M_CAPTURE) {
|
if ((flags & M_PR_NCAPT) && (move->flags & M_CAPTURE)) {
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(5, "!capture & %#04x\n", move->flags);
|
log_i(9, "skipping !capture & %#04x\n", move->flags);
|
||||||
# endif
|
# endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (flags & M_PR_NUM)
|
||||||
|
log(1, "%d:", movenum);
|
||||||
if (move->flags & M_CASTLE_K) {
|
if (move->flags & M_CASTLE_K) {
|
||||||
printf("O-O");
|
log(1, "O-O");
|
||||||
goto end;
|
goto end;
|
||||||
} else if (move->flags & M_CASTLE_Q) {
|
} else if (move->flags & M_CASTLE_Q) {
|
||||||
printf("O-O-O");
|
log(1, "O-O-O");
|
||||||
goto end;
|
goto end;
|
||||||
} else {
|
} else {
|
||||||
printf("%s%c%c", P_SYM(move->piece),
|
log(1, "%s%c%c", P_SYM(move->piece),
|
||||||
FILE2C(GET_F(move->from)),
|
FILE2C(F88(move->from)),
|
||||||
RANK2C(GET_R(move->from)));
|
RANK2C(R88(move->from)));
|
||||||
if (move->taken) {
|
if (move->flags & M_CAPTURE) {
|
||||||
printf("x");
|
log(1, "x");
|
||||||
if (flags & M_PR_LONG)
|
if (flags & M_PR_LONG)
|
||||||
printf("%s", P_SYM(move->taken));
|
log(1, "%s", P_SYM(move->capture));
|
||||||
} else {
|
} else {
|
||||||
printf("-");
|
log(1, "-");
|
||||||
}
|
}
|
||||||
printf("%c%c",
|
log(1, "%c%c",
|
||||||
FILE2C(GET_F(move->to)),
|
FILE2C(F88(move->to)),
|
||||||
RANK2C(GET_R(move->to)));
|
RANK2C(R88(move->to)));
|
||||||
if (flags & M_PR_LONG && move->flags & M_EN_PASSANT)
|
if (flags & M_PR_LONG && move->flags & M_EN_PASSANT)
|
||||||
printf("e.p.");
|
log(1, "e.p.");
|
||||||
if (move->promotion)
|
if (move->promotion)
|
||||||
printf("=%s", P_SYM(move->promotion));
|
log(1, "=%s", P_SYM(move->promotion));
|
||||||
|
if (flags & M_PR_EVAL)
|
||||||
|
log(1, "[ev:%d] ", move->eval);
|
||||||
end:
|
end:
|
||||||
printf(" ");
|
log(1, " ");
|
||||||
}
|
}
|
||||||
|
if (flags & M_PR_NL)
|
||||||
|
log(1, "\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,28 +137,32 @@ void moves_print(pos_t *pos, move_flags_t flags)
|
|||||||
{
|
{
|
||||||
struct list_head *p_cur, *tmp;
|
struct list_head *p_cur, *tmp;
|
||||||
move_t *move;
|
move_t *move;
|
||||||
int i = 0;
|
int movenum;
|
||||||
move_flags_t details = flags & M_PR_LONG;
|
|
||||||
|
|
||||||
printf("%s pseudo-moves:\n\t", pos->turn == WHITE? "White": "Black");
|
for (int color=WHITE; color <= BLACK; ++color) {
|
||||||
if (! (flags & M_PR_SEPARATE)) {
|
int verif = 0;
|
||||||
list_for_each_safe(p_cur, tmp, &pos->moves) {
|
log(1, "%s pseudo-moves:\n\t", color == WHITE? "White": "Black");
|
||||||
move = list_entry(p_cur, move_t, list);
|
if (! (flags & M_PR_SEPARATE)) {
|
||||||
i += move_print(move, details);
|
movenum = 1;
|
||||||
|
list_for_each_safe(p_cur, tmp, &pos->moves[color]) {
|
||||||
|
move = list_entry(p_cur, move_t, list);
|
||||||
|
verif += move_print(movenum++, move, flags);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log(1, "captures: ");
|
||||||
|
movenum = 1;
|
||||||
|
list_for_each_safe(p_cur, tmp, &pos->moves[color]) {
|
||||||
|
move = list_entry(p_cur, move_t, list);
|
||||||
|
verif += move_print(movenum++, move, flags | M_PR_CAPT);
|
||||||
|
}
|
||||||
|
movenum = 1;
|
||||||
|
log(1, "\n\tothers : ");
|
||||||
|
list_for_each_safe(p_cur, tmp, &pos->moves[color]) {
|
||||||
|
move = list_entry(p_cur, move_t, list);
|
||||||
|
verif += move_print(movenum++, move, flags | M_PR_NCAPT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("\n\tTotal moves = %d\n", i);
|
log(1, "\n\tTotal moves = %d mobility=%u\n", verif, pos->mobility[color]);
|
||||||
} else {
|
|
||||||
printf("captures: ");
|
|
||||||
list_for_each_safe(p_cur, tmp, &pos->moves) {
|
|
||||||
move = list_entry(p_cur, move_t, list);
|
|
||||||
i += move_print(move, details | M_PR_CAPT);
|
|
||||||
}
|
|
||||||
printf("\n\tothers : ");
|
|
||||||
list_for_each_safe(p_cur, tmp, &pos->moves) {
|
|
||||||
move = list_entry(p_cur, move_t, list);
|
|
||||||
i += move_print(move, details | M_PR_NCAPT);
|
|
||||||
}
|
|
||||||
printf("\n\tTotal moves = %d\n", i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,78 +171,94 @@ static move_t *move_add(pos_t *pos, piece_t piece, square_t from,
|
|||||||
{
|
{
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
move_t *move;
|
move_t *move;
|
||||||
|
int color = COLOR(pos->board[from].piece);
|
||||||
|
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(3, "piece_color=%d turn=%d from=%c%c to=%c%c\n",
|
log_i(3, "piece_color=%d turn=%d from=%c%c to=%c%c\n",
|
||||||
COLOR(piece), pos->turn,
|
color, pos->turn,
|
||||||
FILE2C(GET_F(from)),
|
FILE2C(F88(from)),
|
||||||
RANK2C(GET_R(from)),
|
RANK2C(R88(from)),
|
||||||
FILE2C(GET_F(to)),
|
FILE2C(F88(to)),
|
||||||
RANK2C(GET_R(to)));
|
RANK2C(R88(to)));
|
||||||
# endif
|
# endif
|
||||||
if (COLOR(piece) != pos->turn)
|
|
||||||
return NULL;
|
|
||||||
/* invalid position if opponent king is attacked
|
/* invalid position if opponent king is attacked
|
||||||
*/
|
*/
|
||||||
if (board[to].piece & KING) {
|
if (board[to].piece & KING) {
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(2, "invalid position: opponent king [%c%c] is in check.\n",
|
log_i(2, "invalid position: opponent king [%c%c] is in check.\n",
|
||||||
FILE2C(GET_F(to)), RANK2C(GET_R(to)));
|
FILE2C(F88(to)), RANK2C(R88(to)));
|
||||||
# endif
|
# endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(move = pool_get(moves_pool)))
|
if (!(move = pool_get(moves_pool)))
|
||||||
return NULL;
|
return NULL;
|
||||||
list_add(&move->list, &pos->moves);
|
list_add(&move->list, &pos->moves[color]);
|
||||||
|
|
||||||
move->piece = piece;
|
move->piece = piece | color;
|
||||||
move->from = from;
|
move->from = from;
|
||||||
move->to = to;
|
move->to = to;
|
||||||
move->taken = board[to].piece;
|
move->capture = board[to].piece;
|
||||||
|
if (PIECE(move->capture) == KING)
|
||||||
|
pos->check[color]++;
|
||||||
|
|
||||||
move->flags = M_NORMAL;
|
move->flags = M_NORMAL;
|
||||||
if (move->taken)
|
if (move->capture)
|
||||||
move->flags |= M_CAPTURE;
|
move->flags |= M_CAPTURE;
|
||||||
move->newpos = pos_dup(pos);
|
move->pos = NULL;
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(3, "added move from %c%c to %c%c\n",
|
log_i(3, "added %s %s move from %c%c to %c%c\n",
|
||||||
FILE2C(GET_F(move->from)), RANK2C(GET_R(move->from)),
|
COLOR(move->piece)? "black": "white",
|
||||||
FILE2C(GET_F(move->to)), RANK2C(GET_R(move->to)));
|
P_NAME(PIECE(move->piece)),
|
||||||
|
FILE2C(F88(move->from)), RANK2C(R88(move->from)),
|
||||||
|
FILE2C(F88(move->to)), RANK2C(R88(move->to)));
|
||||||
# endif
|
# endif
|
||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move_del() - delete a move from list.
|
||||||
|
* @ptr: move &list_head
|
||||||
|
*
|
||||||
|
* Remove the move whose 'list' element address is @ptr.
|
||||||
|
*/
|
||||||
void move_del(struct list_head *ptr)
|
void move_del(struct list_head *ptr)
|
||||||
{
|
{
|
||||||
move_t *move = list_entry(ptr, move_t, list);
|
move_t *move = list_entry(ptr, move_t, list);
|
||||||
|
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(3, "delete move from %c%c to %c%c\n",
|
log_i(3, "delete move from %c%c to %c%c\n",
|
||||||
FILE2C(GET_F(move->from)), RANK2C(GET_R(move->from)),
|
FILE2C(F88(move->from)), RANK2C(R88(move->from)),
|
||||||
FILE2C(GET_F(move->to)), RANK2C(GET_R(move->to)));
|
FILE2C(F88(move->to)), RANK2C(R88(move->to)));
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* TODO: remove move->pos if non null */
|
if (move->pos)
|
||||||
if (move->newpos) {
|
pos_del(move->pos);
|
||||||
pos_clear(move->newpos);
|
|
||||||
}
|
|
||||||
list_del(ptr);
|
list_del(ptr);
|
||||||
pool_add(moves_pool, move);
|
pool_add(moves_pool, move);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move_del() - delete all position moves.
|
||||||
|
* @ppos: &position.
|
||||||
|
*
|
||||||
|
* Remove all generated moves from @pos structure.
|
||||||
|
*/
|
||||||
int moves_del(pos_t *pos)
|
int moves_del(pos_t *pos)
|
||||||
{
|
{
|
||||||
struct list_head *p_cur, *tmp, *head;
|
struct list_head *p_cur, *tmp, *head;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
head = &pos->moves;
|
for (int color = WHITE; color <= BLACK; ++color) {
|
||||||
|
head = &pos->moves[color];
|
||||||
|
|
||||||
list_for_each_safe(p_cur, tmp, head) {
|
list_for_each_safe(p_cur, tmp, head) {
|
||||||
move_del(p_cur);
|
move_del(p_cur);
|
||||||
count++;
|
count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# ifdef DEBUG_PIECE
|
# ifdef DEBUG_PIECE
|
||||||
log_f(3, "removed=%d\n", count);
|
log_f(3, "%d moves removed\n", count);
|
||||||
# endif
|
# endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -221,17 +270,12 @@ static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from,
|
|||||||
move_t *move;
|
move_t *move;
|
||||||
piece_t promote;
|
piece_t promote;
|
||||||
unsigned char color = COLOR(piece);
|
unsigned char color = COLOR(piece);
|
||||||
pos_t *newpos;
|
|
||||||
|
|
||||||
if (color != pos->turn)
|
if (R88(from) == rank7) { /* promotion */
|
||||||
return NULL;
|
|
||||||
if (RANK88(from) == rank7) { /* promotion */
|
|
||||||
for (promote = QUEEN; promote > PAWN; promote >>= 1) {
|
for (promote = QUEEN; promote > PAWN; promote >>= 1) {
|
||||||
if ((move = move_add(pos, piece, from, to))) {
|
if ((move = move_add(pos, piece, from, to))) {
|
||||||
move->flags |= M_PROMOTION;
|
move->flags |= M_PROMOTION;
|
||||||
move->promotion = promote | color;
|
move->promotion = promote | color;
|
||||||
newpos = move->newpos;
|
|
||||||
//piece_del(&newpos->board[from].s_piece);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -240,14 +284,19 @@ static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from,
|
|||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pawn moves. We do not test for valid destination square here,
|
/**
|
||||||
* assuming position is valid. Is that correct ?
|
* pseudo_moves_pawn() - generate moves for pawn.
|
||||||
|
* @pos: &position
|
||||||
|
* @ppiece: &piece_list pawn structure pointer
|
||||||
|
* @doit: add move to moves list
|
||||||
|
*
|
||||||
|
* Calculate all possible moves for @ppiece pawn.
|
||||||
|
* If @doit is true, add moves to @pos' moves list.
|
||||||
*/
|
*/
|
||||||
int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit)
|
int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit)
|
||||||
{
|
{
|
||||||
piece_t piece = PIECE(ppiece->piece);
|
piece_t piece = PIECE(ppiece->piece);
|
||||||
unsigned char color = COLOR(ppiece->piece);
|
unsigned char color = COLOR(ppiece->piece);
|
||||||
unsigned char vcolor = VCOLOR(ppiece->piece);
|
|
||||||
square_t square = ppiece->square, new;
|
square_t square = ppiece->square, new;
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
unsigned char rank2, rank7, rank5;
|
unsigned char rank2, rank7, rank5;
|
||||||
@@ -277,7 +326,7 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
P_NAME(piece),
|
P_NAME(piece),
|
||||||
dir,
|
dir,
|
||||||
square,
|
square,
|
||||||
FILE2C(GET_F(square)), RANK2C(GET_R(square)));
|
FILE2C(F88(square)), RANK2C(R88(square)));
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* normal push. We do not test for valid destination square here,
|
/* normal push. We do not test for valid destination square here,
|
||||||
@@ -288,42 +337,43 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(4, "pushing pawn %#04x\n", square);
|
log_i(4, "pushing pawn %#04x\n", square);
|
||||||
# endif
|
# endif
|
||||||
//log_f(4, "pawn move mobility\n");
|
pos->mobility[color]++;
|
||||||
pos->mobility[vcolor]++;
|
count++;
|
||||||
if (doit && (move = move_pawn_add(pos, piece | color, square, new, rank7)))
|
if (doit)
|
||||||
count++;
|
move_pawn_add(pos, piece | color, square, new, rank7);
|
||||||
/* push 2 squares */
|
/* push 2 squares */
|
||||||
if (move && RANK88(square) == rank2) {
|
log(4, "R88(%#x)=%d R2=%d \n", square, R88(square), rank2);
|
||||||
|
if (R88(square) == rank2) {
|
||||||
new += dir * 16;
|
new += dir * 16;
|
||||||
if (SQ88_OK(new) && !board[new].piece) {
|
if (SQ88_OK(new) && !board[new].piece) {
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(4, "pushing pawn %#04x 2 squares\n", square);
|
log_i(4, "pushing pawn %#04x 2 squares\n", square);
|
||||||
# endif
|
# endif
|
||||||
//log_f(2, "pawn move2 mobility\n");
|
//log_f(2, "pawn move2 mobility\n");
|
||||||
pos->mobility[vcolor]++;
|
pos->mobility[color]++;
|
||||||
if (doit &&
|
count++;
|
||||||
(move = move_pawn_add(pos, piece | color, square, new, rank7))) {
|
if (doit)
|
||||||
count++;
|
move_pawn_add(pos, piece | color, square, new, rank7);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* en passant - not accounted for mobility. Correct ? */
|
/* en passant - not accounted for mobility. Correct ? */
|
||||||
if (doit && pos->en_passant && RANK88(square) == rank5) {
|
if (pos->en_passant && R88(square) == rank5) {
|
||||||
unsigned char ep_file = FILE88(pos->en_passant);
|
unsigned char ep_file = F88(pos->en_passant);
|
||||||
unsigned char sq_file = FILE88(square);
|
unsigned char sq_file = F88(square);
|
||||||
|
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(4, "possible en passant on rank %#x (current = %#0x)\n", ep_file,
|
log_i(4, "possible en passant on rank %#x (current = %#0x)\n", ep_file,
|
||||||
sq_file);
|
sq_file);
|
||||||
# endif
|
# endif
|
||||||
if (sq_file == ep_file - 1 || sq_file == ep_file + 1) {
|
if (sq_file == ep_file - 1 || sq_file == ep_file + 1) {
|
||||||
square_t taken = board[SQUARE(ep_file, rank5)].piece;
|
square_t t_square = SQ88(ep_file, rank5); /* taken pawn square */
|
||||||
|
piece_t captured = board[t_square].piece;
|
||||||
move = move_pawn_add(pos, piece | color , square, pos->en_passant, rank7);
|
move = move_pawn_add(pos, piece | color , square, pos->en_passant, rank7);
|
||||||
count++;
|
|
||||||
move->flags |= M_EN_PASSANT | M_CAPTURE;
|
move->flags |= M_EN_PASSANT | M_CAPTURE;
|
||||||
move->taken = taken;
|
move->capture = captured;
|
||||||
|
pos->mobility[color]++;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,21 +387,46 @@ int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
# endif
|
# endif
|
||||||
if (SQ88_NOK(new))
|
if (SQ88_NOK(new))
|
||||||
continue;
|
continue;
|
||||||
pos->controlled[vcolor] |= SQ88_2_BB(new);
|
pos->controlled[color] |= SQ88_2_BB(new);
|
||||||
if (board[new].piece && COLOR(board[new].piece) != color) {
|
if (board[new].piece && COLOR(board[new].piece) != color) {
|
||||||
|
if (PIECE(board[new].piece) == KING)
|
||||||
|
pos->check[color]++;
|
||||||
//log_f(2, "pawn capture mobility\n");
|
//log_f(2, "pawn capture mobility\n");
|
||||||
pos->mobility[vcolor]++;
|
pos->mobility[color]++;
|
||||||
if (doit &&
|
count++;
|
||||||
((move = move_pawn_add(pos, piece | color, square, new, rank7))))
|
if (doit)
|
||||||
count++;
|
move_pawn_add(pos, piece | color, square, new, rank7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# ifdef DEBUG_MOVE
|
||||||
|
log_f(2, "pos:%p turn:%s piece:%d [%s %s] dir:%d at %#04x[%c%c] count=%d\n",
|
||||||
|
pos,
|
||||||
|
IS_WHITE(pos->turn)? "white": "black",
|
||||||
|
piece,
|
||||||
|
IS_WHITE(color)? "white": "black",
|
||||||
|
P_NAME(piece),
|
||||||
|
dir,
|
||||||
|
square,
|
||||||
|
FILE2C(F88(square)), RANK2C(R88(square)), count);
|
||||||
|
# endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pseudo_moves_castle(pos_t *pos)
|
/**
|
||||||
|
* pseudo_moves_castle() - generate castle moves.
|
||||||
|
* @pos: &position
|
||||||
|
* @color: side for which to generate moves
|
||||||
|
* @doit: add move to moves list
|
||||||
|
* @do_king: count king moves in mobility
|
||||||
|
*
|
||||||
|
* Calculate the possible castle moves for @color side.
|
||||||
|
* If @doit is true, add moves to @pos' moves list.
|
||||||
|
* If @do_king is true, account king moves (incl. castle) to mobility.
|
||||||
|
*
|
||||||
|
* @return: The number of possible king moves.
|
||||||
|
*/
|
||||||
|
int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool do_king)
|
||||||
{
|
{
|
||||||
unsigned char color = pos->turn;
|
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
unsigned char rank1, castle_K, castle_Q;
|
unsigned char rank1, castle_K, castle_Q;
|
||||||
move_t *move = NULL;
|
move_t *move = NULL;
|
||||||
@@ -359,11 +434,13 @@ int pseudo_moves_castle(pos_t *pos)
|
|||||||
struct can_castle *can_castle;
|
struct can_castle *can_castle;
|
||||||
bitboard_t controlled;
|
bitboard_t controlled;
|
||||||
bitboard_t occupied = pos->occupied[WHITE] | pos->occupied[BLACK];
|
bitboard_t occupied = pos->occupied[WHITE] | pos->occupied[BLACK];
|
||||||
|
//pos_t *newpos;
|
||||||
|
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_f(2, "pos:%p turn:%s\n",
|
log_f(2, "pos:%p turn:%s color:%s\n",
|
||||||
pos,
|
pos,
|
||||||
IS_WHITE(pos->turn)? "white": "black");
|
IS_WHITE(pos->turn)? "white": "black",
|
||||||
|
IS_WHITE(color)? "white": "black");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
if (IS_WHITE(color)) {
|
if (IS_WHITE(color)) {
|
||||||
@@ -381,55 +458,79 @@ int pseudo_moves_castle(pos_t *pos)
|
|||||||
}
|
}
|
||||||
if (castle_K) {
|
if (castle_K) {
|
||||||
if (occupied & can_castle->occupied[1]) {
|
if (occupied & can_castle->occupied[1]) {
|
||||||
printf("Cannot castle K side: occupied\n");
|
# ifdef DEBUG_MOVE
|
||||||
|
log(5, "Cannot castle K side: occupied\n");
|
||||||
|
# endif
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
if (controlled & can_castle->controlled[1]) {
|
if (controlled & can_castle->controlled[1]) {
|
||||||
printf("Cannot castle K side: controlled\n");
|
# ifdef DEBUG_MOVE
|
||||||
|
log(5, "Cannot castle K side: controlled\n");
|
||||||
|
# endif
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
move = move_add(pos, board[SQUARE(4, rank1)].piece,
|
if (do_king) {
|
||||||
SQUARE(4, rank1), SQUARE(6, rank1));
|
pos->mobility[color]++;
|
||||||
if (move) {
|
|
||||||
move->flags |= M_CASTLE_K;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
if (doit) {
|
||||||
|
move = move_add(pos, board[SQ88(4, rank1)].piece,
|
||||||
|
SQ88(4, rank1), SQ88(6, rank1));
|
||||||
|
if (move)
|
||||||
|
move->flags |= M_CASTLE_K;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next:
|
next:
|
||||||
if (castle_Q) {
|
if (castle_Q) {
|
||||||
if (occupied & can_castle->occupied[0]) {
|
if (occupied & can_castle->occupied[0]) {
|
||||||
printf("Cannot castle Q side: occupied\n");
|
# ifdef DEBUG_MOVE
|
||||||
|
log(5, "Cannot castle Q side: occupied\n");
|
||||||
|
# endif
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (controlled & can_castle->controlled[0]) {
|
if (controlled & can_castle->controlled[0]) {
|
||||||
printf("Cannot castle Q side: controlled\n");
|
# ifdef DEBUG_MOVE
|
||||||
|
log(5, "Cannot castle Q side: controlled\n");
|
||||||
|
# endif
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
move = move_add(pos, board[SQUARE(4, rank1)].piece,
|
if (do_king) {
|
||||||
SQUARE(4, rank1), SQUARE(2, rank1));
|
pos->mobility[color]++;
|
||||||
if (move) {
|
|
||||||
move->flags |= M_CASTLE_Q;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
if (doit) {
|
||||||
|
move = move_add(pos, board[SQ88(4, rank1)].piece,
|
||||||
|
SQ88(4, rank1), SQ88(2, rank1));
|
||||||
|
if (move)
|
||||||
|
move->flags |= M_CASTLE_Q;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* general rule moves for non pawn pieces
|
/**
|
||||||
|
* pseudo_moves_gen() - general move generation for non pawn pieces
|
||||||
|
* @pos: &position
|
||||||
|
* @ppiece: &piece_list structure pointer
|
||||||
|
* @doit: add move to moves list
|
||||||
|
* @do_king: count king moves
|
||||||
|
*
|
||||||
|
* Calculate all possible moves for @ppiece.
|
||||||
|
* If @doit is true, add moves to @pos' moves list.
|
||||||
|
* If @do_king is true, account king moves (incl. castle) to mobility.
|
||||||
*/
|
*/
|
||||||
int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
|
int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit, bool do_king)
|
||||||
{
|
{
|
||||||
piece_t piece = PIECE(ppiece->piece);
|
piece_t piece = PIECE(ppiece->piece);
|
||||||
unsigned char color = COLOR(ppiece->piece);
|
unsigned char color = COLOR(ppiece->piece);
|
||||||
unsigned char vcolor = VCOLOR(ppiece->piece);
|
|
||||||
struct vector *vector = vectors+piece;
|
struct vector *vector = vectors+piece;
|
||||||
square_t square = ppiece->square;
|
square_t square = ppiece->square;
|
||||||
unsigned char ndirs = vector->ndirs;
|
unsigned char ndirs = vector->ndirs;
|
||||||
char slide = vector->slide;
|
char slide = vector->slide;
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
move_t *move;
|
//move_t *move;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
u64 bb_new;
|
u64 bb_new;
|
||||||
|
|
||||||
@@ -441,7 +542,7 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
IS_WHITE(color)? "white": "black",
|
IS_WHITE(color)? "white": "black",
|
||||||
P_NAME(piece),
|
P_NAME(piece),
|
||||||
square,
|
square,
|
||||||
FILE2C(GET_F(square)), RANK2C(GET_R(square)));
|
FILE2C(F88(square)), RANK2C(R88(square)));
|
||||||
log_i(5, "vector=%ld ndirs=%d slide=%d\n", vector-vectors, ndirs, slide);
|
log_i(5, "vector=%ld ndirs=%d slide=%d\n", vector-vectors, ndirs, slide);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@@ -458,41 +559,40 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
bb_new = SQ88_2_BB(new);
|
bb_new = SQ88_2_BB(new);
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(2, "trying %#x=%c%c bb=%#lx\n",
|
log_i(2, "trying %#x=%c%c bb=%#lx\n",
|
||||||
new, FILE2C(GET_F(new)), RANK2C(GET_R(new)),
|
new, FILE2C(F88(new)), RANK2C(R88(new)),
|
||||||
bb_new);
|
bb_new);
|
||||||
//bitboard_print(new_bitboard);
|
//bitboard_print(new_bitboard);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
pos->controlled[vcolor] |= bb_new;;
|
pos->controlled[color] |= bb_new;;
|
||||||
|
|
||||||
/* king: do not move to opponent controlled square */
|
/* king: do not move to opponent controlled square */
|
||||||
if (piece == KING && pos->controlled[OPPONENT(vcolor)] & bb_new) {
|
if (piece == KING && pos->controlled[OPPONENT(color)] & bb_new) {
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(2, "%s king cannot move to %c%c\n",
|
log_i(2, "%s king cannot move to %c%c\n",
|
||||||
IS_WHITE(color)? "white": "black",
|
IS_WHITE(color)? "white": "black",
|
||||||
FILE2C(GET_F(new)), RANK2C(GET_R(new)));
|
FILE2C(F88(new)), RANK2C(R88(new)));
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bb_new & pos->occupied[vcolor]) {
|
if (bb_new & pos->occupied[color]) {
|
||||||
//bitboard_print(pos->occupied[vcolor]);
|
//bitboard_print(pos->occupied[color]);
|
||||||
//bitboard_print(pos->occupied[OPPONENT(vcolor)]);
|
//bitboard_print(pos->occupied[OPPONENT(color)]);
|
||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_i(2, "BB: skipping %#llx [%c%c] (same color piece)\n",
|
log_i(2, "BB: skipping %#lx [%c%c] (same color piece)\n",
|
||||||
new, FILE2C(GET_F(new)), RANK2C(GET_R(new)));
|
bb_new, FILE2C(F88(new)), RANK2C(R88(new)));
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we are sure the move is valid : we create move */
|
/* we are sure the move is valid : we create move */
|
||||||
//log_f(2, "piece mobility\n");
|
if (piece != KING || do_king) {
|
||||||
pos->mobility[vcolor]++;
|
pos->mobility[color]++;
|
||||||
if (doit && color == pos->turn) {
|
count++;
|
||||||
if ((move = move_add(pos, ppiece->piece, square, new))) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (doit)
|
||||||
|
move_add(pos, ppiece->piece, square, new);
|
||||||
if (board[new].piece) { /* stopper move */
|
if (board[new].piece) { /* stopper move */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -500,10 +600,31 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# ifdef DEBUG_MOVE
|
||||||
|
log_f(2, "pos:%p turn:%s piece:%d [%s %s] at %#04x[%c%c] count=%d\n",
|
||||||
|
pos,
|
||||||
|
IS_WHITE(pos->turn)? "white": "black",
|
||||||
|
piece,
|
||||||
|
IS_WHITE(color)? "white": "black",
|
||||||
|
P_NAME(piece),
|
||||||
|
square,
|
||||||
|
FILE2C(F88(square)), RANK2C(R88(square)), count);
|
||||||
|
# endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int moves_gen(pos_t *pos, bool color, bool doit)
|
/**
|
||||||
|
* moves_gen() - move generation for one color
|
||||||
|
* @pos: &position
|
||||||
|
* @color: side
|
||||||
|
* @doit: add move to moves list
|
||||||
|
* @do_king: count king moves
|
||||||
|
*
|
||||||
|
* Calculate all possible moves for @color.
|
||||||
|
* If @doit is true, add moves to @pos' moves list.
|
||||||
|
* If @do_king is true, account king moves (incl. castle) to mobility.
|
||||||
|
*/
|
||||||
|
int moves_gen(pos_t *pos, bool color, bool doit, bool do_king)
|
||||||
{
|
{
|
||||||
struct list_head *p_cur, *tmp, *piece_list;
|
struct list_head *p_cur, *tmp, *piece_list;
|
||||||
piece_list_t *piece;
|
piece_list_t *piece;
|
||||||
@@ -512,59 +633,252 @@ int moves_gen(pos_t *pos, bool color, bool doit)
|
|||||||
# ifdef DEBUG_MOVE
|
# ifdef DEBUG_MOVE
|
||||||
log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit);
|
log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
/* do not generate moves if already done for color */
|
||||||
|
if (!list_empty(&pos->moves[color]))
|
||||||
|
doit = false;
|
||||||
|
|
||||||
piece_list = &pos->pieces[color];
|
piece_list = &pos->pieces[color];
|
||||||
|
pos->mobility[color] = 0;
|
||||||
pos->mobility[color]=0;
|
pos->controlled[color] = 0;
|
||||||
if (doit)
|
count += pseudo_moves_castle(pos, color, doit, do_king);
|
||||||
pseudo_moves_castle(pos);
|
|
||||||
list_for_each_safe(p_cur, tmp, piece_list) {
|
list_for_each_safe(p_cur, tmp, piece_list) {
|
||||||
|
|
||||||
piece = list_entry(p_cur, piece_list_t, list);
|
piece = list_entry(p_cur, piece_list_t, list);
|
||||||
if (PIECE(piece->piece) != PAWN)
|
if (PIECE(piece->piece) != PAWN)
|
||||||
pseudo_moves_gen(pos, piece, doit);
|
count += pseudo_moves_gen(pos, piece, doit, do_king);
|
||||||
else
|
else
|
||||||
pseudo_moves_pawn(pos, piece, doit);
|
count += pseudo_moves_pawn(pos, piece, doit);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int move_doit(pos_t *pos, move_t *move)
|
/**
|
||||||
|
* moves_gen_king_moves() - adjust king mobility
|
||||||
|
* @pos: &position
|
||||||
|
* @color: king color
|
||||||
|
* @doit: add move to moves list
|
||||||
|
*
|
||||||
|
* Compute the number of king moves (incl. castle), after opponent controlled
|
||||||
|
* are known.
|
||||||
|
* If @doit is true, add moves to @pos' moves list.
|
||||||
|
*
|
||||||
|
* @return: The number of possible king moves.
|
||||||
|
*/
|
||||||
|
int moves_gen_king_moves(pos_t *pos, bool color, bool doit)
|
||||||
{
|
{
|
||||||
# ifdef DEBUG_MOVE_TOTO
|
int count = 0;
|
||||||
log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit);
|
piece_list_t *king = list_first_entry(&pos->pieces[color], piece_list_t, list);
|
||||||
# endif
|
count = pseudo_moves_castle(pos, king, doit, true);
|
||||||
if (pos && move)
|
count += pseudo_moves_gen(pos, king, doit, true);
|
||||||
return 1;
|
return count;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BIN_move
|
static int moves_cmp_eval(__unused void *data, const struct list_head *h1, const struct list_head *h2)
|
||||||
#include "fen.h"
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
{
|
||||||
pos_t *pos;
|
move_t *m1 = list_entry(h1, move_t, list);
|
||||||
|
move_t *m2 = list_entry(h2, move_t, list);
|
||||||
|
return m2->eval_simple - m1->eval_simple;
|
||||||
|
}
|
||||||
|
|
||||||
debug_init(1);
|
/**
|
||||||
piece_pool_init();
|
* moves_sort() sort - sort moves list, best eval first.
|
||||||
moves_pool_init();
|
* @pos: &position.
|
||||||
pos_pool_init();
|
*/
|
||||||
pos = pos_get();
|
void moves_sort(pos_t *pos)
|
||||||
|
{
|
||||||
|
list_sort(NULL, &pos->moves[pos->turn], moves_cmp_eval);
|
||||||
|
}
|
||||||
|
|
||||||
if (ac == 1) {
|
/**
|
||||||
pos_startpos(pos);
|
* moves_gen_all_eval_sort() - calculate/generate/sort moves for side to play.
|
||||||
} else {
|
* @pos: &position
|
||||||
fen2pos(pos, av[1]);
|
*
|
||||||
|
* Generate positions for each move for player to move.
|
||||||
|
* For each of them generate opponents moves, calculate eval, and sort the moves list.
|
||||||
|
*/
|
||||||
|
void moves_gen_eval_sort(pos_t *pos)
|
||||||
|
{
|
||||||
|
move_t *move;
|
||||||
|
pos_t *newpos;
|
||||||
|
|
||||||
|
moves_gen_all(pos);
|
||||||
|
|
||||||
|
list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
||||||
|
newpos = move_do(pos, move);
|
||||||
|
move->pos = newpos;
|
||||||
|
//move_print(0, move, 0);
|
||||||
|
move->eval_simple = eval_simple(newpos);
|
||||||
|
newpos->eval_simple = move->eval_simple;
|
||||||
}
|
}
|
||||||
//printf("turn = %d opponent = %d\n", pos->turn, OPPONENT(pos->turn));
|
moves_sort(pos);
|
||||||
moves_gen(pos, OPPONENT(pos->turn), false);
|
//moves_print(pos, 0);
|
||||||
moves_gen(pos, pos->turn, true);
|
}
|
||||||
pos_print(pos);
|
|
||||||
pos_pieces_print(pos);
|
/**
|
||||||
moves_print(pos, M_PR_SEPARATE);
|
* moves_gen_all() - calculate all moves, and generate moves for side to play.
|
||||||
|
* @pos: &position
|
||||||
//bitboard_print2(castle_squares[0].controlled, castle_squares[1].controlled);
|
*
|
||||||
//bitboard_print2(castle_squares[0].occupied, castle_squares[1].occupied);
|
* Compute pseudo moves for both sides, and generate moves for player to move.
|
||||||
|
*/
|
||||||
|
void moves_gen_all(pos_t *pos)
|
||||||
|
{
|
||||||
|
//log_f(1, "turn=%d opponent=%d\n", pos->turn, OPPONENT(pos->turn));
|
||||||
|
if (!pos->moves_generated) {
|
||||||
|
if (!pos->moves_counted) {}
|
||||||
|
moves_gen(pos, OPPONENT(pos->turn), false, false);
|
||||||
|
moves_gen(pos, pos->turn, true, true);
|
||||||
|
if (!pos->moves_counted)
|
||||||
|
moves_gen_king_moves(pos, OPPONENT(pos->turn), false);
|
||||||
|
pos->moves_counted = true;
|
||||||
|
pos->moves_generated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* moves_gen_all_nomoves() - calculate number of moves for each player.
|
||||||
|
* @pos: &position
|
||||||
|
*/
|
||||||
|
void moves_gen_all_nomoves(pos_t *pos)
|
||||||
|
{
|
||||||
|
//log_f(1, "turn=%d opponent=%d\n", pos->turn, OPPONENT(pos->turn));
|
||||||
|
if (!pos->moves_counted) {
|
||||||
|
moves_gen(pos, OPPONENT(pos->turn), false, false);
|
||||||
|
moves_gen(pos, pos->turn, false, true);
|
||||||
|
moves_gen_king_moves(pos, OPPONENT(pos->turn), false);
|
||||||
|
pos->moves_counted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move_do() - execute move in a duplicated position.
|
||||||
|
* @pos: &pos_t struct on which move will be applied
|
||||||
|
* @move: &move_t struct to apply
|
||||||
|
*
|
||||||
|
* @return: &new position
|
||||||
|
*/
|
||||||
|
pos_t *move_do(pos_t *pos, move_t *move)
|
||||||
|
{
|
||||||
|
# ifdef DEBUG_MOVE
|
||||||
|
//log(1, "new move: ");
|
||||||
|
//move_print(0, move, M_PR_NL | M_PR_LONG);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
pos_t *new = pos_dup(pos);
|
||||||
|
piece_t piece = PIECE(move->piece), newpiece = piece, captured = move->capture;
|
||||||
|
int color = COLOR(move->piece);
|
||||||
|
square_t from = move->from, to = move->to;
|
||||||
|
u64 bb_from = SQ88_2_BB(from), bb_to = SQ88_2_BB(to);
|
||||||
|
|
||||||
|
if (move->capture || piece == PAWN) /* 50 moves */
|
||||||
|
new->clock_50 = 0;
|
||||||
|
else
|
||||||
|
new->clock_50++;
|
||||||
|
|
||||||
|
if (move->flags & M_CAPTURE) { /* capture */
|
||||||
|
if (move->flags & M_EN_PASSANT) {
|
||||||
|
uchar ep_file = F88(pos->en_passant);
|
||||||
|
square_t ep_grab = color == WHITE ? SQ88(ep_file, 4): SQ88(ep_file, 3);
|
||||||
|
u64 bb_ep_grab = SQ88_2_BB(ep_grab);
|
||||||
|
|
||||||
|
log_f(5, "en-passant=%d,%d\n", ep_file, color == WHITE ? 4 : 3);
|
||||||
|
piece_del(&new->board[ep_grab].s_piece->list);
|
||||||
|
new->board[ep_grab].piece = 0;
|
||||||
|
new->occupied[OPPONENT(color)] &= ~bb_ep_grab;
|
||||||
|
new->bb[OPPONENT(color)][BB_PAWN] &= ~bb_ep_grab;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
piece_del(&new->board[to].s_piece->list);
|
||||||
|
new->board[to].piece = 0;
|
||||||
|
new->occupied[OPPONENT(color)] &= ~bb_to;
|
||||||
|
new->bb[OPPONENT(color)][PIECETOBB(captured)] &= ~bb_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (move->flags & M_CASTLE_Q) {
|
||||||
|
uchar row = R88(from);
|
||||||
|
square_t rook_from = SQ88(0, row);
|
||||||
|
square_t rook_to = SQ88(3, row);
|
||||||
|
u64 bb_rook_from = SQ88_2_BB(rook_from);
|
||||||
|
u64 bb_rook_to = SQ88_2_BB(rook_to);
|
||||||
|
|
||||||
|
new->board[rook_to] = new->board[rook_from];
|
||||||
|
new->board[rook_to].s_piece->square = rook_to;
|
||||||
|
new->occupied[color] &= ~bb_rook_from;
|
||||||
|
new->occupied[color] |= bb_rook_to;
|
||||||
|
new->bb[color][PIECETOBB(BB_ROOK)] &= ~bb_rook_from;
|
||||||
|
new->bb[color][PIECETOBB(BB_ROOK)] |= bb_rook_to;
|
||||||
|
new->board[rook_from].piece = 0;
|
||||||
|
new->board[rook_from].s_piece = NULL;
|
||||||
|
//new->castle &= color == WHITE? ~CASTLE_W: ~CASTLE_B;
|
||||||
|
|
||||||
|
} else if (move->flags & M_CASTLE_K) {
|
||||||
|
uchar row = R88(from);
|
||||||
|
square_t rook_from = SQ88(7, row);
|
||||||
|
square_t rook_to = SQ88(5, row);
|
||||||
|
u64 bb_rook_from = SQ88_2_BB(rook_from);
|
||||||
|
u64 bb_rook_to = SQ88_2_BB(rook_to);
|
||||||
|
|
||||||
|
new->board[rook_to] = new->board[rook_from];
|
||||||
|
new->board[rook_to].s_piece->square = rook_to;
|
||||||
|
new->occupied[color] &= ~bb_rook_from;
|
||||||
|
new->occupied[color] |= bb_rook_to;
|
||||||
|
new->bb[color][PIECETOBB(BB_ROOK)] &= ~bb_rook_from;
|
||||||
|
new->bb[color][PIECETOBB(BB_ROOK)] |= bb_rook_to;
|
||||||
|
new->board[rook_from].piece = 0;
|
||||||
|
new->board[rook_from].s_piece = NULL;
|
||||||
|
// new->castle &= color == WHITE? ~CASTLE_W: ~CASTLE_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->board[to] = new->board[from];
|
||||||
|
/* fix dest square */
|
||||||
|
new->board[to].s_piece->square = to;
|
||||||
|
if (move->flags & M_PROMOTION) {
|
||||||
|
log_f(5, "promotion to %s\n", P_SYM(move->promotion));
|
||||||
|
log_f(5, "newpiece=%#x p=%#x\n", move->promotion, PIECE(move->promotion));
|
||||||
|
newpiece = PIECE(move->promotion);
|
||||||
|
new->board[to].piece = move->promotion;
|
||||||
|
new->board[to].s_piece->piece = move->promotion;
|
||||||
|
}
|
||||||
|
/* replace old occupied bitboard by new one */
|
||||||
|
new->occupied[color] &= ~bb_from;
|
||||||
|
new->occupied[color] |= bb_to;
|
||||||
|
new->bb[color][PIECETOBB(piece)] &= ~bb_from;
|
||||||
|
new->bb[color][PIECETOBB(newpiece)] |= bb_to;
|
||||||
|
if (move->flags & M_PROMOTION) {
|
||||||
|
log_f(5, "promotion color=%d bbpiece=%d\n", color, PIECETOBB(newpiece));
|
||||||
|
//bitboard_print(new->bb[color][PIECETOBB(newpiece)]);
|
||||||
|
}
|
||||||
|
/* set en_passant */
|
||||||
|
new->en_passant = 0;
|
||||||
|
if (piece == PAWN) {
|
||||||
|
if (R88(from) == 1 && R88(to) == 3)
|
||||||
|
pos->en_passant = SQ88(F88(from), 2);
|
||||||
|
else if (R88(from) == 6 && R88(to) == 4)
|
||||||
|
pos->en_passant = SQ88(F88(from), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always make "from" square empty */
|
||||||
|
new->board[from].piece = 0;
|
||||||
|
new->board[from].s_piece = NULL;
|
||||||
|
|
||||||
|
//printf("old turn=%d ", color);
|
||||||
|
SET_COLOR(new->turn, OPPONENT(color)); /* pos color */
|
||||||
|
//printf("new turn=%d\n", new->turn);
|
||||||
|
//fflush(stdout);
|
||||||
|
/* adjust castling flags */
|
||||||
|
if ((bb_from | bb_to) & (A1 | E1))
|
||||||
|
new->castle &= ~CASTLE_WQ;
|
||||||
|
else if ((bb_from | bb_to) & (E1 | H1))
|
||||||
|
new->castle &= ~CASTLE_WK;
|
||||||
|
else if ((bb_from | bb_to) & (A8 | E8))
|
||||||
|
new->castle &= ~CASTLE_BQ;
|
||||||
|
else if ((bb_from | bb_to) & (E8 | H8))
|
||||||
|
new->castle &= ~CASTLE_BK;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_undo(pos_t *pos, __unused move_t *move)
|
||||||
|
{
|
||||||
|
pos_del(pos);
|
||||||
}
|
}
|
||||||
#endif /* BIN_move */
|
|
||||||
|
|||||||
36
src/move.h
36
src/move.h
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -32,34 +32,48 @@ typedef unsigned char move_flags_t;
|
|||||||
|
|
||||||
/* moves_print flags
|
/* moves_print flags
|
||||||
*/
|
*/
|
||||||
#define M_PR_SEPARATE 0x40 /* separate capture/non capture */
|
|
||||||
#define M_PR_LONG 0x80
|
|
||||||
#define M_PR_CAPT 0x01
|
#define M_PR_CAPT 0x01
|
||||||
#define M_PR_NCAPT 0x02
|
#define M_PR_NCAPT 0x02
|
||||||
|
#define M_PR_NUM 0x04
|
||||||
|
#define M_PR_NL 0x08
|
||||||
|
#define M_PR_EVAL 0x20 /* separate captures */
|
||||||
|
#define M_PR_SEPARATE 0x40 /* separate captures */
|
||||||
|
#define M_PR_LONG 0x80
|
||||||
|
|
||||||
typedef struct move_s {
|
typedef struct move_s {
|
||||||
piece_t piece;
|
piece_t piece;
|
||||||
square_t from, to;
|
square_t from, to;
|
||||||
piece_t taken; /* removed piece */
|
piece_t capture; /* captured piece */
|
||||||
piece_t promotion; /* promoted piece */
|
piece_t promotion; /* promoted piece */
|
||||||
move_flags_t flags;
|
move_flags_t flags;
|
||||||
|
eval_t negamax;
|
||||||
|
eval_t eval;
|
||||||
|
eval_t eval_simple;
|
||||||
|
pos_t *pos;
|
||||||
struct list_head list; /* next move */
|
struct list_head list; /* next move */
|
||||||
struct pos_s *newpos; /* resulting position */
|
|
||||||
} move_t;
|
} move_t;
|
||||||
|
|
||||||
pool_t *moves_pool_init();
|
pool_t *moves_pool_init();
|
||||||
void moves_pool_stats();
|
void moves_pool_stats();
|
||||||
int move_print(move_t *move, move_flags_t flags);
|
int move_print(int movenum, move_t *move, move_flags_t flags);
|
||||||
void moves_print(pos_t *move, move_flags_t flags);
|
void moves_print(pos_t *move, move_flags_t flags);
|
||||||
int pseudo_moves_castle(pos_t *pos);
|
|
||||||
|
|
||||||
void move_del(struct list_head *ptr);
|
void move_del(struct list_head *ptr);
|
||||||
int moves_del(pos_t *pos);
|
int moves_del(pos_t *pos);
|
||||||
|
|
||||||
int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit);
|
int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool do_king);
|
||||||
|
int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool do_king);
|
||||||
int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece, bool doit);
|
int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece, bool doit);
|
||||||
int moves_gen(pos_t *pos, bool color, bool doit);
|
int moves_gen(pos_t *pos, bool color, bool doit, bool do_king);
|
||||||
|
int moves_gen_king_moves(pos_t *pos, bool color, bool doit);
|
||||||
|
|
||||||
int move_doit(pos_t *pos, move_t *move);
|
void moves_sort(pos_t *pos);
|
||||||
|
void moves_gen_eval_sort(pos_t *pos);
|
||||||
|
|
||||||
#endif /* MODE_H */
|
void moves_gen_all(pos_t *pos);
|
||||||
|
void moves_gen_all_nomoves(pos_t *pos);
|
||||||
|
|
||||||
|
pos_t *move_do(pos_t *pos, move_t *move);
|
||||||
|
void move_undo(pos_t *pos, move_t *move);
|
||||||
|
|
||||||
|
#endif /* MOVE_H */
|
||||||
|
|||||||
80
src/piece.c
80
src/piece.c
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -14,10 +14,14 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
#include <pool.h>
|
||||||
|
#include <list.h>
|
||||||
|
|
||||||
#include "chessdefs.h"
|
#include "chessdefs.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "debug.h"
|
#include "bitboard.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
static pool_t *pieces_pool;
|
static pool_t *pieces_pool;
|
||||||
@@ -41,8 +45,8 @@ void piece_list_print(struct list_head *list)
|
|||||||
piece = list_entry(p_cur, piece_list_t, list);
|
piece = list_entry(p_cur, piece_list_t, list);
|
||||||
|
|
||||||
printf("%s%c%c ", P_SYM(piece->piece),
|
printf("%s%c%c ", P_SYM(piece->piece),
|
||||||
FILE2C(GET_F(piece->square)),
|
FILE2C(F88(piece->square)),
|
||||||
RANK2C(GET_R(piece->square)));
|
RANK2C(R88(piece->square)));
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@@ -50,7 +54,7 @@ void piece_list_print(struct list_head *list)
|
|||||||
pool_t *piece_pool_init()
|
pool_t *piece_pool_init()
|
||||||
{
|
{
|
||||||
if (!pieces_pool)
|
if (!pieces_pool)
|
||||||
pieces_pool = pool_init("pieces", 128, sizeof(piece_list_t));
|
pieces_pool = pool_create("pieces", 128, sizeof(piece_list_t));
|
||||||
return pieces_pool;
|
return pieces_pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,32 +64,26 @@ void piece_pool_stats()
|
|||||||
pool_stats(pieces_pool);
|
pool_stats(pieces_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static eval_t pieces_values[] = {
|
|
||||||
[PAWN] = PAWN_VALUE,
|
|
||||||
[KNIGHT] = KNIGHT_VALUE,
|
|
||||||
[BISHOP] = BISHOP_VALUE,
|
|
||||||
[ROOK] = ROOK_VALUE,
|
|
||||||
[QUEEN] = QUEEN_VALUE,
|
|
||||||
[KING] = KING_VALUE
|
|
||||||
};
|
|
||||||
|
|
||||||
piece_list_t *piece_add(pos_t *pos, piece_t piece, square_t square)
|
piece_list_t *piece_add(pos_t *pos, piece_t piece, square_t square)
|
||||||
{
|
{
|
||||||
piece_list_t *new;
|
piece_list_t *new;
|
||||||
short color = VCOLOR(piece);
|
short color = COLOR(piece);
|
||||||
|
|
||||||
# ifdef DEBUG_PIECE
|
# ifdef DEBUG_PIECE
|
||||||
log_f(3, "piece=%02x square=%02x\n", piece, square);
|
log_f(3, "piece=%02x square=%02x\n", piece, square);
|
||||||
log_f(5, "Adding %s %s on %c%c\n", color? "Black": "White",
|
log_f(5, "Adding %s %s on %c%c\n", color? "Black": "White",
|
||||||
P_NAME(piece), FILE2C(GET_F(square)), RANK2C(GET_R(square)));
|
P_NAME(piece), FILE2C(F88(square)), RANK2C(R88(square)));
|
||||||
# endif
|
# endif
|
||||||
if ((new = pool_get(pieces_pool))) {
|
if ((new = pool_get(pieces_pool))) {
|
||||||
list_add_tail(&new->list, &pos->pieces[color]);
|
/* first piece is always king */
|
||||||
//color? &pos->pieces_black: &pos->pieces_white);
|
if (PIECE(piece) == KING)
|
||||||
|
list_add(&new->list, &pos->pieces[color]);
|
||||||
|
else
|
||||||
|
list_add_tail(&new->list, &pos->pieces[color]);
|
||||||
new->piece = piece;
|
new->piece = piece;
|
||||||
new->square = square;
|
new->square = square;
|
||||||
new->castle = 0;
|
new->castle = 0;
|
||||||
new-> value = pieces_values[PIECE(piece)];
|
new-> value = piece_details[PIECE(piece)].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
@@ -118,47 +116,3 @@ int pieces_del(pos_t *pos, short color)
|
|||||||
# endif
|
# endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BIN_piece
|
|
||||||
#include "fen.h"
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
|
||||||
pos_t *pos;
|
|
||||||
|
|
||||||
debug_init(5);
|
|
||||||
pos_pool_init();
|
|
||||||
pos = pos_get();
|
|
||||||
piece_pool_init();
|
|
||||||
|
|
||||||
if (ac == 1) {
|
|
||||||
pos_startpos(pos);
|
|
||||||
} else {
|
|
||||||
fen2pos(pos, av[1]);
|
|
||||||
}
|
|
||||||
pos_print(pos);
|
|
||||||
pos_pieces_print(pos);
|
|
||||||
printf("0x1c:\n");
|
|
||||||
bitboard_print(0x1c);
|
|
||||||
printf("0x70:\n");
|
|
||||||
bitboard_print(0x70);
|
|
||||||
printf("0x0e:\n");
|
|
||||||
bitboard_print(0x0e);
|
|
||||||
printf("0x60:\n");
|
|
||||||
bitboard_print(0x60);
|
|
||||||
|
|
||||||
printf("A1:\n");
|
|
||||||
bitboard_print(A1);
|
|
||||||
printf("1:\n");
|
|
||||||
bitboard_print(1L);
|
|
||||||
printf("H1:\n");
|
|
||||||
bitboard_print(H1);
|
|
||||||
printf("C1:\n");
|
|
||||||
bitboard_print(C1);
|
|
||||||
printf("D1:\n");
|
|
||||||
bitboard_print(D1);
|
|
||||||
printf("C1|D1:\n");
|
|
||||||
bitboard_print(C1|D1);
|
|
||||||
printf("H8:\n");
|
|
||||||
bitboard_print(H8);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -34,7 +34,7 @@ typedef struct piece_list_s {
|
|||||||
piece_t piece;
|
piece_t piece;
|
||||||
square_t square;
|
square_t square;
|
||||||
short castle;
|
short castle;
|
||||||
int64_t value;
|
s64 value;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
} piece_list_t;
|
} piece_list_t;
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ extern struct piece_details {
|
|||||||
char *symbol_w;
|
char *symbol_w;
|
||||||
char *symbol_b; /* used for game notation */
|
char *symbol_b; /* used for game notation */
|
||||||
char *name;
|
char *name;
|
||||||
int64_t value;
|
s64 value;
|
||||||
} piece_details[];
|
} piece_details[];
|
||||||
|
|
||||||
#define P_NAME(p) piece_details[E_PIECE(p)].name
|
#define P_NAME(p) piece_details[E_PIECE(p)].name
|
||||||
@@ -56,6 +56,7 @@ extern struct piece_details {
|
|||||||
piece_details[E_PIECE(p)].abbrev_b)
|
piece_details[E_PIECE(p)].abbrev_b)
|
||||||
#define P_CSYM(p) (IS_WHITE(p)? piece_details[E_PIECE(p)].symbol_w: \
|
#define P_CSYM(p) (IS_WHITE(p)? piece_details[E_PIECE(p)].symbol_w: \
|
||||||
piece_details[E_PIECE(p)].symbol_b)
|
piece_details[E_PIECE(p)].symbol_b)
|
||||||
|
#define P_VALUE(p) (piece_details[E_PIECE(p)].value)
|
||||||
/* use short name or symbol - no effect
|
/* use short name or symbol - no effect
|
||||||
*/
|
*/
|
||||||
#define P_USE_UTF 1
|
#define P_USE_UTF 1
|
||||||
|
|||||||
179
src/pool.c
179
src/pool.c
@@ -1,179 +0,0 @@
|
|||||||
/* pool.c - A simple pool manager.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "list.h"
|
|
||||||
#include "pool.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
void pool_stats(pool_t *pool)
|
|
||||||
{
|
|
||||||
if (pool) {
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s] pool [%p]: avail:%u alloc:%u grow:%u eltsize:%lu\n",
|
|
||||||
pool->name, (void *)pool, pool->available, pool->allocated,
|
|
||||||
pool->growsize, pool->eltsize);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pool_t *pool_init(const char *name, uint32_t growsize, size_t eltsize)
|
|
||||||
{
|
|
||||||
pool_t *pool;
|
|
||||||
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "name=[%s] growsize=%u eltsize=%lu\n",
|
|
||||||
name, growsize, eltsize);
|
|
||||||
# endif
|
|
||||||
/* we need at least this space in struct */
|
|
||||||
if (eltsize < sizeof (struct list_head))
|
|
||||||
return NULL;
|
|
||||||
if ((pool = malloc(sizeof (*pool)))) {
|
|
||||||
pool->name = strdup(name);
|
|
||||||
pool->growsize = growsize;
|
|
||||||
pool->eltsize = eltsize;
|
|
||||||
pool->available = 0;
|
|
||||||
pool->allocated = 0;
|
|
||||||
INIT_LIST_HEAD(&pool->head);
|
|
||||||
}
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t _pool_add(pool_t *pool, struct list_head *elt)
|
|
||||||
{
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(10, "pool=%p &head=%p elt=%p off1=%lu off2=%lu\n",
|
|
||||||
(void *)pool,
|
|
||||||
(void *)&pool->head,
|
|
||||||
(void *)elt,
|
|
||||||
(void *)&pool->head-(void *)pool,
|
|
||||||
offsetof(pool_t, head));
|
|
||||||
# endif
|
|
||||||
|
|
||||||
list_add(elt, &pool->head);
|
|
||||||
return ++pool->available;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pool_add(pool_t *pool, void *elt)
|
|
||||||
{
|
|
||||||
return _pool_add(pool, elt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct list_head *_pool_get(pool_t *pool)
|
|
||||||
{
|
|
||||||
struct list_head *res = pool->head.next;
|
|
||||||
pool->available--;
|
|
||||||
list_del(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pool_get(pool_t *pool)
|
|
||||||
{
|
|
||||||
if (!pool)
|
|
||||||
return NULL;
|
|
||||||
if (!pool->available) {
|
|
||||||
void *alloc = malloc(pool->eltsize * pool->growsize);
|
|
||||||
void *cur;
|
|
||||||
uint32_t i;
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(1, "[%s]: growing pool from %u to %u elements.\n",
|
|
||||||
pool->name,
|
|
||||||
pool->allocated,
|
|
||||||
pool->allocated + pool->growsize);
|
|
||||||
# endif
|
|
||||||
if (!alloc)
|
|
||||||
return NULL;
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(5, " (old=%u)\n", pool->allocated);
|
|
||||||
# endif
|
|
||||||
pool->allocated += pool->growsize;
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(5, " (new=%u)\n", pool->allocated);
|
|
||||||
# endif
|
|
||||||
for (i = 0; i < pool->growsize; ++i) {
|
|
||||||
cur = alloc + i * pool->eltsize;
|
|
||||||
# ifdef DEBUG_POOL
|
|
||||||
log_f(5, "alloc=%p cur=%p\n", alloc, cur);
|
|
||||||
# endif
|
|
||||||
_pool_add(pool, (struct list_head *)cur);
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
}
|
|
||||||
/* this is the effective address if the object (and also the
|
|
||||||
* pool list_head address)
|
|
||||||
*/
|
|
||||||
return _pool_get(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BIN_pool
|
|
||||||
struct d {
|
|
||||||
uint16_t data1;
|
|
||||||
char c;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
static LIST_HEAD (head);
|
|
||||||
|
|
||||||
int main(int ac, char**av)
|
|
||||||
{
|
|
||||||
pool_t *pool;
|
|
||||||
int total;
|
|
||||||
int action=0;
|
|
||||||
uint16_t icur=0;
|
|
||||||
char ccur='z';
|
|
||||||
struct d *elt;
|
|
||||||
|
|
||||||
debug_init(3);
|
|
||||||
log_f(1, "%s: sizeof(d)=%lu sizeof(*d)=%lu off=%lu\n", *av, sizeof(elt),
|
|
||||||
sizeof(*elt), offsetof(struct d, list));
|
|
||||||
|
|
||||||
if ((pool = pool_init("dummy", 3, sizeof(*elt)))) {
|
|
||||||
pool_stats(pool);
|
|
||||||
for (int cur=1; cur<ac; ++cur) {
|
|
||||||
total = atoi(av[cur]);
|
|
||||||
if (action == 0) { /* add elt to list */
|
|
||||||
log_f(2, "adding %d elements\n", total);
|
|
||||||
for (int i = 0; i < total; ++i) {
|
|
||||||
elt = pool_get(pool);
|
|
||||||
elt->data1 = icur++;
|
|
||||||
elt->c = ccur--;
|
|
||||||
list_add(&elt->list, &head);
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
action = 1;
|
|
||||||
} else { /* remove one elt from list */
|
|
||||||
log_f(2, "deleting %d elements\n", total);
|
|
||||||
for (int i = 0; i < total; ++i) {
|
|
||||||
if (!list_empty(&head)) {
|
|
||||||
elt = list_last_entry(&head, struct d, list);
|
|
||||||
printf("elt=[%d, %c]\n", elt->data1, elt->c);
|
|
||||||
list_del(&elt->list);
|
|
||||||
pool_add(pool, elt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
action = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool_stats(pool);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
35
src/pool.h
35
src/pool.h
@@ -1,35 +0,0 @@
|
|||||||
/* pool.h - A simple memory pool manager.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 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.htmlL>.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef POOL_H
|
|
||||||
#define POOL_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *name;
|
|
||||||
uint32_t available;
|
|
||||||
uint32_t allocated;
|
|
||||||
uint32_t growsize;
|
|
||||||
size_t eltsize;
|
|
||||||
struct list_head head;
|
|
||||||
} pool_t;
|
|
||||||
|
|
||||||
void pool_stats(pool_t *pool);
|
|
||||||
pool_t *pool_init(const char *name, uint32_t grow, size_t size);
|
|
||||||
void *pool_get(pool_t *pool);
|
|
||||||
uint32_t pool_add(pool_t *pool, void *elt);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
165
src/position.c
165
src/position.c
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "fen.h"
|
#include "fen.h"
|
||||||
#include "piece.h"
|
#include "piece.h"
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
static pool_t *pos_pool;
|
static pool_t *pos_pool;
|
||||||
|
|
||||||
@@ -54,6 +55,10 @@ inline void bitboard_print2(bitboard_t bb1, bitboard_t bb2)
|
|||||||
BYTE2BIN(bb2>>i));
|
BYTE2BIN(bb2>>i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pos_pieces_print() - Print position pieces
|
||||||
|
* @pos: &position
|
||||||
|
*/
|
||||||
void pos_pieces_print(pos_t *pos)
|
void pos_pieces_print(pos_t *pos)
|
||||||
{
|
{
|
||||||
printf("White pieces (%d): \t", popcount64(pos->occupied[WHITE]));
|
printf("White pieces (%d): \t", popcount64(pos->occupied[WHITE]));
|
||||||
@@ -62,16 +67,31 @@ void pos_pieces_print(pos_t *pos)
|
|||||||
piece_list_print(&pos->pieces[BLACK]);
|
piece_list_print(&pos->pieces[BLACK]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* void pos_print - Print position on stdout.
|
/**
|
||||||
* @pos: Position address (pos_t * )
|
* pos_bitboards_print() - Print position bitboards
|
||||||
*
|
* @pos: &position
|
||||||
* Return: None.
|
*/
|
||||||
|
void pos_bitboards_print(pos_t *pos)
|
||||||
|
{
|
||||||
|
printf("Bitboards occupied :\n");
|
||||||
|
bitboard_print2(pos->occupied[WHITE], pos->occupied[BLACK]);
|
||||||
|
printf("Bitboards controlled :\n");
|
||||||
|
bitboard_print2(pos->controlled[WHITE], pos->controlled[BLACK]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pos_print() - Print position on stdout.
|
||||||
|
* @pos: &position
|
||||||
*/
|
*/
|
||||||
void pos_print(pos_t *pos)
|
void pos_print(pos_t *pos)
|
||||||
{
|
{
|
||||||
int rank, file;
|
int rank, file;
|
||||||
piece_t piece;
|
piece_t piece;
|
||||||
board_t *board = pos->board;
|
board_t *board = pos->board;
|
||||||
|
piece_list_t *wk = list_first_entry(&pos->pieces[WHITE], piece_list_t, list),
|
||||||
|
*bk = list_first_entry(&pos->pieces[BLACK], piece_list_t, list);
|
||||||
|
|
||||||
|
|
||||||
printf(" +---+---+---+---+---+---+---+---+\n");
|
printf(" +---+---+---+---+---+---+---+---+\n");
|
||||||
for (rank = 7; rank >= 0; --rank) {
|
for (rank = 7; rank >= 0; --rank) {
|
||||||
@@ -85,18 +105,19 @@ void pos_print(pos_t *pos)
|
|||||||
printf(" A B C D E F G H\n\n");
|
printf(" A B C D E F G H\n\n");
|
||||||
printf("Turn: %s.\n", IS_WHITE(pos->turn) ? "white" : "black");
|
printf("Turn: %s.\n", IS_WHITE(pos->turn) ? "white" : "black");
|
||||||
printf("Kings: W:%c%c B:%c%c\n",
|
printf("Kings: W:%c%c B:%c%c\n",
|
||||||
FILE2C(GET_F(pos->king[WHITE])),
|
FILE2C(F88(wk->square)),
|
||||||
RANK2C(GET_R(pos->king[WHITE])),
|
RANK2C(R88(wk->square)),
|
||||||
FILE2C(GET_F(pos->king[BLACK])),
|
FILE2C(F88(bk->square)),
|
||||||
RANK2C(GET_R(pos->king[BLACK])));
|
RANK2C(R88(bk->square)));
|
||||||
printf("Possible en-passant: [%#x] ", pos->en_passant);
|
printf("Possible en-passant: [%#x] ", pos->en_passant);
|
||||||
if (pos->en_passant == 0)
|
if (pos->en_passant == 0)
|
||||||
printf("None.\n");
|
printf("None.\n");
|
||||||
else
|
else
|
||||||
printf("%d %d = %c%c\n", GET_F(pos->en_passant),
|
printf("%d %d = %c%c\n",
|
||||||
GET_R(pos->en_passant),
|
F88(pos->en_passant),
|
||||||
FILE2C(GET_F(pos->en_passant)),
|
R88(pos->en_passant),
|
||||||
RANK2C(GET_R(pos->en_passant)));
|
FILE2C(F88(pos->en_passant)),
|
||||||
|
RANK2C(R88(pos->en_passant)));
|
||||||
|
|
||||||
printf("castle [%#x] : ", pos->castle);
|
printf("castle [%#x] : ", pos->castle);
|
||||||
|
|
||||||
@@ -115,10 +136,52 @@ void pos_print(pos_t *pos)
|
|||||||
popcount64(pos->controlled[BLACK]));
|
popcount64(pos->controlled[BLACK]));
|
||||||
printf("Mobility: W:%u B:%u\n", pos->mobility[WHITE],
|
printf("Mobility: W:%u B:%u\n", pos->mobility[WHITE],
|
||||||
pos->mobility[BLACK]);
|
pos->mobility[BLACK]);
|
||||||
printf("Bitboards occupied :\n");
|
}
|
||||||
bitboard_print2(pos->occupied[WHITE], pos->occupied[BLACK]);
|
|
||||||
printf("Bitboards controlled :\n");
|
/**
|
||||||
bitboard_print2(pos->controlled[WHITE], pos->controlled[BLACK]);
|
* pos_check() - extensive position consistenci check.
|
||||||
|
* @pos: &position
|
||||||
|
*/
|
||||||
|
void pos_check(pos_t *pos)
|
||||||
|
{
|
||||||
|
int rank, file;
|
||||||
|
piece_t piece;
|
||||||
|
board_t *board = pos->board;
|
||||||
|
|
||||||
|
/* check that board and bitboard reflect same information */
|
||||||
|
for (rank = 7; rank >= 0; --rank) {
|
||||||
|
for (file = 0; file < 8; ++file) {
|
||||||
|
piece_list_t *ppiece;
|
||||||
|
printf("checking %c%c ", file+'a', rank+'1');
|
||||||
|
|
||||||
|
piece = board[SQ88(file, rank)].piece;
|
||||||
|
ppiece= board[SQ88(file, rank)].s_piece;
|
||||||
|
printf("piece=%s ", P_CSYM(piece));
|
||||||
|
if (ppiece)
|
||||||
|
printf("ppiece=%s/sq=%#x ", P_CSYM(ppiece->piece), ppiece->square);
|
||||||
|
switch(PIECE(piece)) {
|
||||||
|
case PAWN:
|
||||||
|
printf("pawn" );
|
||||||
|
break;
|
||||||
|
case KNIGHT:
|
||||||
|
printf("knight ");
|
||||||
|
break;
|
||||||
|
case BISHOP:
|
||||||
|
printf("bishop ");
|
||||||
|
break;
|
||||||
|
case ROOK:
|
||||||
|
printf("rook ");
|
||||||
|
break;
|
||||||
|
case QUEEN:
|
||||||
|
printf("queen ");
|
||||||
|
break;
|
||||||
|
case KING:
|
||||||
|
printf("king ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_t *pos_clear(pos_t *pos)
|
pos_t *pos_clear(pos_t *pos)
|
||||||
@@ -137,19 +200,23 @@ pos_t *pos_clear(pos_t *pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SET_WHITE(pos->turn);
|
SET_WHITE(pos->turn);
|
||||||
|
pos->node_count = 0;
|
||||||
pos->castle = 0;
|
pos->castle = 0;
|
||||||
pos->clock_50 = 0;
|
pos->clock_50 = 0;
|
||||||
pos->curmove = 0;
|
pos->curmove = 0;
|
||||||
pos->eval = 0;
|
pos->eval = 0;
|
||||||
pos->en_passant = 0;
|
pos->en_passant = 0;
|
||||||
pos->king[WHITE] = 0;
|
|
||||||
pos->king[BLACK] = 0;
|
|
||||||
pos->occupied[WHITE] = 0;
|
pos->occupied[WHITE] = 0;
|
||||||
pos->occupied[BLACK] = 0;
|
pos->occupied[BLACK] = 0;
|
||||||
|
for (int color=0; color<2; ++color)
|
||||||
|
for (int piece = BB_ALL; piece < BB_END; ++piece)
|
||||||
|
pos->bb[color][piece] = 0;
|
||||||
pos->controlled[WHITE] = 0;
|
pos->controlled[WHITE] = 0;
|
||||||
pos->controlled[BLACK] = 0;
|
pos->controlled[BLACK] = 0;
|
||||||
pos->mobility[WHITE] = 0;
|
pos->mobility[WHITE] = 0;
|
||||||
pos->mobility[BLACK] = 0;
|
pos->mobility[BLACK] = 0;
|
||||||
|
pos->moves_generated = false;
|
||||||
|
pos->moves_counted = false;
|
||||||
/* remove pieces / moves */
|
/* remove pieces / moves */
|
||||||
pieces_del(pos, WHITE);
|
pieces_del(pos, WHITE);
|
||||||
pieces_del(pos, BLACK);
|
pieces_del(pos, BLACK);
|
||||||
@@ -158,6 +225,18 @@ pos_t *pos_clear(pos_t *pos)
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pos_del() - delete a position.
|
||||||
|
* @pos: &position.
|
||||||
|
*/
|
||||||
|
void pos_del(pos_t *pos)
|
||||||
|
{
|
||||||
|
pieces_del(pos, WHITE);
|
||||||
|
pieces_del(pos, BLACK);
|
||||||
|
moves_del(pos);
|
||||||
|
pool_add(pos_pool, pos);
|
||||||
|
}
|
||||||
|
|
||||||
pos_t *pos_startpos(pos_t *pos)
|
pos_t *pos_startpos(pos_t *pos)
|
||||||
{
|
{
|
||||||
static char *startfen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
static char *startfen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
@@ -171,16 +250,36 @@ pos_t *pos_get()
|
|||||||
if (pos) {
|
if (pos) {
|
||||||
INIT_LIST_HEAD(&pos->pieces[WHITE]);
|
INIT_LIST_HEAD(&pos->pieces[WHITE]);
|
||||||
INIT_LIST_HEAD(&pos->pieces[BLACK]);
|
INIT_LIST_HEAD(&pos->pieces[BLACK]);
|
||||||
INIT_LIST_HEAD(&pos->moves);
|
|
||||||
|
INIT_LIST_HEAD(&pos->moves[WHITE]);
|
||||||
|
INIT_LIST_HEAD(&pos->moves[BLACK]);
|
||||||
pos_clear(pos);
|
pos_clear(pos);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "zobaaa\n");
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: merge with pos_get - NULL for init, non null for duplicate */
|
/**
|
||||||
|
* pos_dup() - duplicate a position.
|
||||||
|
* @pos: &position to duplicate.
|
||||||
|
*
|
||||||
|
* New position is the same as source one (with duplicated pieces list),
|
||||||
|
* except:
|
||||||
|
* - moves list is empty
|
||||||
|
* - bestmove is NULL
|
||||||
|
* - nodecount is set to zero
|
||||||
|
* - eval is set to EVAL_INVALID
|
||||||
|
* - moves_generated ans moves_counted are unset
|
||||||
|
* - check is set to zero
|
||||||
|
*
|
||||||
|
* @return: The new position.
|
||||||
|
*
|
||||||
|
* TODO: merge with pos_get - NULL for init, non null for duplicate
|
||||||
|
*/
|
||||||
pos_t *pos_dup(pos_t *pos)
|
pos_t *pos_dup(pos_t *pos)
|
||||||
{
|
{
|
||||||
struct list_head *p_cur, *tmp, *piece_list;
|
struct list_head *p_cur, *piece_list;
|
||||||
piece_list_t *oldpiece;
|
piece_list_t *oldpiece;
|
||||||
board_t *board;
|
board_t *board;
|
||||||
pos_t *new = pool_get(pos_pool);
|
pos_t *new = pool_get(pos_pool);
|
||||||
@@ -188,22 +287,24 @@ pos_t *pos_dup(pos_t *pos)
|
|||||||
if (new) {
|
if (new) {
|
||||||
board = new->board;
|
board = new->board;
|
||||||
*new = *pos;
|
*new = *pos;
|
||||||
INIT_LIST_HEAD(&new->pieces[WHITE]);
|
for (int color = 0; color < 2; ++color) {
|
||||||
INIT_LIST_HEAD(&new->pieces[BLACK]);
|
INIT_LIST_HEAD(&new->pieces[color]);
|
||||||
INIT_LIST_HEAD(&new->moves);
|
INIT_LIST_HEAD(&new->moves[color]);
|
||||||
|
/* duplicate piece list */
|
||||||
/* duplicate piece list */
|
|
||||||
for (int color=0; color<2; ++color) {
|
|
||||||
piece_list = &pos->pieces[color]; /* white/black piece list */
|
piece_list = &pos->pieces[color]; /* white/black piece list */
|
||||||
|
|
||||||
list_for_each_safe(p_cur, tmp, piece_list) {
|
list_for_each(p_cur, piece_list) {
|
||||||
oldpiece = list_entry(p_cur, piece_list_t, list);
|
oldpiece = list_entry(p_cur, piece_list_t, list);
|
||||||
board[oldpiece->square].s_piece =
|
board[oldpiece->square].s_piece =
|
||||||
piece_add(new, oldpiece->piece, oldpiece->square);
|
piece_add(new, oldpiece->piece, oldpiece->square);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
new->bestmove = NULL;
|
||||||
|
new->node_count = 0;
|
||||||
|
new->eval = EVAL_INVALID;
|
||||||
|
new->moves_generated = false;
|
||||||
|
new->moves_counted = false;
|
||||||
|
new->check[WHITE] = new->check[BLACK] = 0;
|
||||||
}
|
}
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
@@ -211,7 +312,7 @@ pos_t *pos_dup(pos_t *pos)
|
|||||||
pool_t *pos_pool_init()
|
pool_t *pos_pool_init()
|
||||||
{
|
{
|
||||||
if (!pos_pool)
|
if (!pos_pool)
|
||||||
pos_pool = pool_init("positions", 128, sizeof(pos_t));
|
pos_pool = pool_create("positions", 128, sizeof(pos_t));
|
||||||
return pos_pool;
|
return pos_pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* Some rights reserved. See COPYING.
|
* Some rights reserved. See COPYING.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this
|
* 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.htmlL>.
|
* 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>
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
*
|
*
|
||||||
@@ -15,38 +15,51 @@
|
|||||||
#define POSITION_H
|
#define POSITION_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "chessdefs.h"
|
#include <pool.h>
|
||||||
|
#include <list.h>
|
||||||
|
#include <bits.h>
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "pool.h"
|
#include "chessdefs.h"
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
typedef struct pos_s {
|
typedef struct pos_s {
|
||||||
|
u64 node_count; /* evaluated nodes */
|
||||||
piece_t turn; /* we use only color bit */
|
piece_t turn; /* we use only color bit */
|
||||||
castle_t castle;
|
castle_t castle;
|
||||||
u16 clock_50;
|
u16 clock_50;
|
||||||
u16 curmove;
|
u16 curmove;
|
||||||
u16 mobility[2];
|
|
||||||
eval_t eval;
|
eval_t eval;
|
||||||
|
int check[2];
|
||||||
|
int eval_simple_phase;
|
||||||
|
eval_t eval_simple;
|
||||||
|
move_t *bestmove;
|
||||||
|
bool moves_generated;
|
||||||
|
bool moves_counted;
|
||||||
board_t board[BOARDSIZE];
|
board_t board[BOARDSIZE];
|
||||||
|
|
||||||
square_t en_passant;
|
square_t en_passant;
|
||||||
square_t king[2];
|
|
||||||
bitboard_t occupied[2];
|
bitboard_t bb[2][BB_END]; /* use: pieces[BLACK][BB_PAWN] */
|
||||||
|
bitboard_t occupied[2]; /* OR of bb[COLOR][x] */
|
||||||
bitboard_t controlled[2];
|
bitboard_t controlled[2];
|
||||||
struct list_head pieces[2];
|
u16 mobility[2];
|
||||||
struct list_head moves;
|
struct list_head pieces[2]; /* pieces list, King is first */
|
||||||
|
struct list_head moves[2];
|
||||||
} pos_t;
|
} pos_t;
|
||||||
|
|
||||||
void bitboard_print(bitboard_t bb);
|
void bitboard_print(bitboard_t bb);
|
||||||
void bitboard_print2(bitboard_t bb1, bitboard_t bb2);
|
void bitboard_print2(bitboard_t bb1, bitboard_t bb2);
|
||||||
void pos_pieces_print(pos_t *pos);
|
void pos_pieces_print(pos_t *pos);
|
||||||
|
void pos_bitboards_print(pos_t *pos);
|
||||||
void pos_print(pos_t *pos);
|
void pos_print(pos_t *pos);
|
||||||
pos_t *pos_clear(pos_t *pos);
|
pos_t *pos_clear(pos_t *pos);
|
||||||
|
void pos_del(pos_t *pos);
|
||||||
pos_t *pos_startpos(pos_t *pos);
|
pos_t *pos_startpos(pos_t *pos);
|
||||||
pos_t *pos_create();
|
pos_t *pos_create();
|
||||||
pool_t *pos_pool_init();
|
pool_t *pos_pool_init();
|
||||||
void pos_pool_stats();
|
void pos_pool_stats();
|
||||||
pos_t *pos_get();
|
pos_t *pos_get();
|
||||||
pos_t *pos_dup(pos_t *pos);
|
pos_t *pos_dup(pos_t *pos);
|
||||||
|
void pos_check(pos_t *pos);
|
||||||
|
|
||||||
#endif /* POSITION_H */
|
#endif /* POSITION_H */
|
||||||
|
|||||||
237
src/search.c
Normal file
237
src/search.c
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* search.c - search good moves.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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 <br.h>
|
||||||
|
#include <list.h>
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "move.h"
|
||||||
|
#include "eval.h"
|
||||||
|
#include "search.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* negamax() - search position negamax.
|
||||||
|
* @pos: &position to search
|
||||||
|
* @depth: Wanted depth.
|
||||||
|
* @color: 1 for white, -1 for black.
|
||||||
|
*
|
||||||
|
* Calculate the negamax value of @pos. This is an extensive search, with
|
||||||
|
* absolutely no cutoff.
|
||||||
|
*
|
||||||
|
* @return: The @pos negamax evaluation.
|
||||||
|
*/
|
||||||
|
eval_t negamax(pos_t *pos, int depth, int color)
|
||||||
|
{
|
||||||
|
move_t *move;
|
||||||
|
pos_t *newpos;
|
||||||
|
eval_t best = EVAL_MIN, score;
|
||||||
|
|
||||||
|
pos->node_count++;
|
||||||
|
if (depth == 0) {
|
||||||
|
moves_gen_all_nomoves(pos);
|
||||||
|
score = eval(pos) * color;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
moves_gen_all(pos);
|
||||||
|
list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
||||||
|
newpos = move_do(pos, move);
|
||||||
|
score = -negamax(newpos, depth - 1, -color);
|
||||||
|
pos->node_count += newpos->node_count;
|
||||||
|
move->negamax = score;
|
||||||
|
if (score > best) {
|
||||||
|
best = score;
|
||||||
|
pos->bestmove = move;
|
||||||
|
}
|
||||||
|
move_undo(newpos, move);
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pvs() - Principal Variation Search.
|
||||||
|
* @pos: &position to search
|
||||||
|
* @depth: wanted depth.
|
||||||
|
* @alpha: alpha value.
|
||||||
|
* @beta: beta value.
|
||||||
|
* @color: 1 for white, -1 for black.
|
||||||
|
*
|
||||||
|
* Calculate the PVS value of @pos.
|
||||||
|
* See https://en.wikipedia.org/wiki/Principal_variation_search
|
||||||
|
*
|
||||||
|
* Moves list should be first generated and evaluated/sorted.
|
||||||
|
*
|
||||||
|
* @return: The @pos PVS evaluation.
|
||||||
|
*/
|
||||||
|
eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color)
|
||||||
|
{
|
||||||
|
move_t *move;
|
||||||
|
pos_t *newpos;
|
||||||
|
eval_t score = EVAL_INVALID;
|
||||||
|
bool firstchild = true;
|
||||||
|
|
||||||
|
pos->node_count++;
|
||||||
|
|
||||||
|
if (depth == 0) {
|
||||||
|
//return quiesce(p, alpha, beta); /* leaf node */
|
||||||
|
moves_gen_all_nomoves(pos);
|
||||||
|
score = eval(pos) * color;
|
||||||
|
log_f(2, "Terminal: depth=%d ", depth);
|
||||||
|
log_f(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta);
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
moves_gen_all(pos);
|
||||||
|
//moves_print(pos, M_PR_EVAL);
|
||||||
|
/* do the full search for first child */
|
||||||
|
//move = list_first_entry_or_null(&pos->moves[pos->turn], move_t, list);
|
||||||
|
|
||||||
|
list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
||||||
|
newpos = move_do(pos, move);
|
||||||
|
log(2, "%.*s", 5 - depth, " ");
|
||||||
|
if (firstchild) { /* first child */
|
||||||
|
score = -pvs(newpos, depth - 1, -beta, -alpha, -color);
|
||||||
|
log_f(2, "First child depth=%d move=", depth);
|
||||||
|
//move_print(0, move, 0);
|
||||||
|
log(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta);
|
||||||
|
pos->bestmove = move;
|
||||||
|
} else {
|
||||||
|
/* search with a null window */
|
||||||
|
score = -pvs(newpos, depth - 1, -alpha - 1, -alpha, -color);
|
||||||
|
log_f(2, "Other child depth=%d move=", depth);
|
||||||
|
//move_print(0, move, 0);
|
||||||
|
log_f(2, "score=%d alpha=%d beta=%d ", score, alpha, beta);
|
||||||
|
/* for fail-soft: if (score > alpha && score < beta) */
|
||||||
|
if (score > alpha) {
|
||||||
|
/* if failed high, do a full re-search */
|
||||||
|
log_f(2, "doing full search.");
|
||||||
|
score = -pvs(newpos, depth - 1, -beta, -alpha, -color);
|
||||||
|
}
|
||||||
|
log(2, "\n");
|
||||||
|
}
|
||||||
|
pos->node_count += newpos->node_count;
|
||||||
|
move_undo(newpos, move);
|
||||||
|
if (score >= beta) { /* fail-hard hard beta cut-off */
|
||||||
|
log(2, "%.*s", 5 - depth, " ");
|
||||||
|
log_f(2, "depth=%d score=%d alpha=%d beta=%d beta cut-off.\n",
|
||||||
|
depth, score, alpha, beta);
|
||||||
|
return beta;
|
||||||
|
}
|
||||||
|
if (score > alpha) {
|
||||||
|
log(2, "%.*s", 5 - depth, " ");
|
||||||
|
log_f(2, "depth=%d setting new alpha from %d to %d\n",
|
||||||
|
depth, alpha, score);
|
||||||
|
alpha = score;
|
||||||
|
pos->bestmove = move;
|
||||||
|
}
|
||||||
|
move->pos = NULL;
|
||||||
|
move->negamax = score;
|
||||||
|
firstchild = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* int negascout (pos_t *pos, int depth, int alpha, int beta )
|
||||||
|
* { /\* compute minimax value of position p *\/
|
||||||
|
* move_t *move;
|
||||||
|
* pos_t *newpos;
|
||||||
|
* eval_t best = EVAL_MIN, score;
|
||||||
|
*
|
||||||
|
* int a, b, t, i;
|
||||||
|
*
|
||||||
|
* if (depth == 0) {
|
||||||
|
* //return quiesce(p, alpha, beta); /\* leaf node *\/
|
||||||
|
* moves_gen_all_nomoves(pos);
|
||||||
|
* score = eval(pos) * color;
|
||||||
|
* return score;
|
||||||
|
* }
|
||||||
|
* moves_gen_all(pos);
|
||||||
|
* a = alpha;
|
||||||
|
* b = beta;
|
||||||
|
* list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
||||||
|
* log(1, "%.*s", 5 - depth, " ");
|
||||||
|
* newpos = move_do(pos, move);
|
||||||
|
* // for ( i = 1; i <= w; i++ ) {
|
||||||
|
* t = -negascout (newpos, depth - 1, -b, -alpha);
|
||||||
|
* if ( (t > a) && (t < beta) && (i > 1) )
|
||||||
|
* t = -NegaScout ( p_i, -beta, -alpha ); /\* re-search *\/
|
||||||
|
* alpha = max( alpha, t );
|
||||||
|
* if ( alpha >= beta )
|
||||||
|
* return alpha; /\* cut-off *\/
|
||||||
|
* b = alpha + 1; /\* set new null window *\/
|
||||||
|
* }
|
||||||
|
* return alpha;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* int quiesce(pos_t *pos, int alpha, int beta)
|
||||||
|
* {
|
||||||
|
* int stand_pat = eval(pos);
|
||||||
|
*
|
||||||
|
* if( stand_pat >= beta )
|
||||||
|
* return beta;
|
||||||
|
* if( alpha < stand_pat )
|
||||||
|
* alpha = stand_pat;
|
||||||
|
*
|
||||||
|
* /\*
|
||||||
|
* * until( every_capture_has_been_examined ) {
|
||||||
|
* * MakeCapture();
|
||||||
|
* * score = -Quiesce( -beta, -alpha );
|
||||||
|
* * TakeBackMove();
|
||||||
|
* *
|
||||||
|
* * if( score >= beta )
|
||||||
|
* * return beta;
|
||||||
|
* * if( score > alpha )
|
||||||
|
* * alpha = score;
|
||||||
|
* * }
|
||||||
|
* *\/
|
||||||
|
* return alpha;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ab_negamax() - search position negamax with alpha-beta cutoff.
|
||||||
|
* @pos: &position to search
|
||||||
|
* @depth: Wanted depth.
|
||||||
|
* @color: 1 for white, -1 for black.
|
||||||
|
*
|
||||||
|
* Calculate the negamax value of @pos, with alpha-beta pruning.
|
||||||
|
*
|
||||||
|
* @return: The @pos negamax evaluation.
|
||||||
|
*/
|
||||||
|
/*int ab_negamax(pos_t *pos, int alpha, int beta, int depth)
|
||||||
|
{
|
||||||
|
move_t *move;
|
||||||
|
pos_t *newpos;
|
||||||
|
eval_t best = EVAL_MIN, score;
|
||||||
|
|
||||||
|
if(depth == 0) {
|
||||||
|
//return quiesce( alpha, beta );
|
||||||
|
moves_gen_all_nomoves(pos);
|
||||||
|
score = eval(pos) * color;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
for ( all moves) {
|
||||||
|
score = -alphaBeta( -beta, -alpha, depthleft - 1 );
|
||||||
|
if( score >= beta )
|
||||||
|
return beta; // fail hard beta-cutoff
|
||||||
|
if( score > alpha )
|
||||||
|
alpha = score; // alpha acts like max in MiniMax
|
||||||
|
}
|
||||||
|
return alpha;
|
||||||
|
}
|
||||||
|
*/
|
||||||
22
src/search.h
Normal file
22
src/search.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* search.h - search for perfect move.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 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 SEARCH_H
|
||||||
|
#define SEARCH_H
|
||||||
|
|
||||||
|
#include "position.h"
|
||||||
|
|
||||||
|
eval_t negamax(pos_t *pos, int depth, int color);
|
||||||
|
eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color);
|
||||||
|
|
||||||
|
#endif /* SEARCH_H */
|
||||||
35
test/eval.c
Normal file
35
test/eval.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "../src/position.h"
|
||||||
|
#include "../src/eval.h"
|
||||||
|
#include "../src/fen.h"
|
||||||
|
#include "../src/move.h"
|
||||||
|
|
||||||
|
int main(int ac, char**av)
|
||||||
|
{
|
||||||
|
pos_t *pos;
|
||||||
|
eval_t res;
|
||||||
|
|
||||||
|
debug_init(5, stderr, true);
|
||||||
|
|
||||||
|
piece_pool_init();
|
||||||
|
moves_pool_init();
|
||||||
|
pos_pool_init();
|
||||||
|
pos = pos_get();
|
||||||
|
|
||||||
|
if (ac == 1) {
|
||||||
|
pos_startpos(pos);
|
||||||
|
} else {
|
||||||
|
fen2pos(pos, av[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos_print(pos);
|
||||||
|
pos_pieces_print(pos);
|
||||||
|
|
||||||
|
moves_gen_all(pos);
|
||||||
|
|
||||||
|
pos_print(pos);
|
||||||
|
moves_print(pos, M_PR_SEPARATE);
|
||||||
|
res = eval(pos);
|
||||||
|
printf("eval=%d centipawns)\n", res);
|
||||||
|
}
|
||||||
20
test/fen.c
Normal file
20
test/fen.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "debug.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "../src/position.h"
|
||||||
|
#include "../src/fen.h"
|
||||||
|
|
||||||
|
int main(int ac, char**av)
|
||||||
|
{
|
||||||
|
pos_t *pos;
|
||||||
|
|
||||||
|
debug_init(5, stderr, true);
|
||||||
|
piece_pool_init();
|
||||||
|
pos_pool_init();
|
||||||
|
pos = pos_get();
|
||||||
|
if (ac == 1) {
|
||||||
|
pos_startpos(pos);
|
||||||
|
} else {
|
||||||
|
fen2pos(pos, av[1]);
|
||||||
|
}
|
||||||
|
pos_print(pos);
|
||||||
|
}
|
||||||
31
test/move.c
Normal file
31
test/move.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
55
test/piece.c
Normal file
55
test/piece.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "../src/fen.h"
|
||||||
|
#include "../src/position.h"
|
||||||
|
#include "../src/bitboard.h"
|
||||||
|
|
||||||
|
int main(int ac, char**av)
|
||||||
|
{
|
||||||
|
pos_t *pos;
|
||||||
|
printf("zobi\n");fflush(stdout);
|
||||||
|
debug_init(6, stderr, true);
|
||||||
|
log_f(5, "kfsjdhg\n");
|
||||||
|
pos_pool_init();
|
||||||
|
pos = pos_get();
|
||||||
|
piece_pool_init();
|
||||||
|
|
||||||
|
if (ac == 1) {
|
||||||
|
printf("zoba\n");fflush(stdout);
|
||||||
|
pos_startpos(pos);
|
||||||
|
} else {
|
||||||
|
fen2pos(pos, av[1]);
|
||||||
|
}
|
||||||
|
pos_print(pos);
|
||||||
|
pos_pieces_print(pos);
|
||||||
|
|
||||||
|
printf("0x1c = 11100 = C1-E1:\n");
|
||||||
|
bitboard_print(0x1c);
|
||||||
|
|
||||||
|
printf("0x70 = 111 = A1-C1\n");
|
||||||
|
bitboard_print(0x70);
|
||||||
|
|
||||||
|
printf("0x0e = 1110 = B1-D1\n");
|
||||||
|
bitboard_print(0x0e);
|
||||||
|
|
||||||
|
printf("0x60 = 1100000 = F1-G1\n");
|
||||||
|
bitboard_print(0x60);
|
||||||
|
|
||||||
|
printf("A1:\n");
|
||||||
|
bitboard_print(A1);
|
||||||
|
|
||||||
|
printf("1:\n");
|
||||||
|
bitboard_print(1L);
|
||||||
|
printf("H1:\n");
|
||||||
|
bitboard_print(H1);
|
||||||
|
printf("C1:\n");
|
||||||
|
bitboard_print(C1);
|
||||||
|
printf("D1:\n");
|
||||||
|
bitboard_print(D1);
|
||||||
|
printf("C1|D1:\n");
|
||||||
|
bitboard_print(C1|D1);
|
||||||
|
printf("H8:\n");
|
||||||
|
bitboard_print(H8);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user