From 8f220d4a49ca1da119a4c6a6417e78ba1ddd13ec Mon Sep 17 00:00:00 2001 From: Tony Congqian Wang Date: Sun, 16 Mar 2025 03:45:53 +0100 Subject: [PATCH 1/3] added c_interface to project with python example code --- .gitignore | 14 +++++++++ Makefile | 34 +++++++++++++++++----- c_interface_test.py | 25 ++++++++++++++++ solver_c_interface.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 c_interface_test.py create mode 100644 solver_c_interface.cpp diff --git a/.gitignore b/.gitignore index b04df31..d49ca89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,17 @@ +# Opening Tables +*.book + # Compiled Object files *.slo *.lo *.o *.obj +# Compiled Dynamic libraries +*.so +*.dll +*.def + # Precompiled Headers *.gch *.pch @@ -29,3 +37,9 @@ # vim swap file *.swp + +# Make artifacts +.depend + +# Visual Studio +.vs \ No newline at end of file diff --git a/Makefile b/Makefile index 55ad168..7240d89 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,39 @@ CXX=g++ -CXXFLAGS=--std=c++11 -W -Wall -O3 -DNDEBUG +CXXFLAGS=--std=c++11 -W -Wall -O3 -DNDEBUG -fPIC +LDLIBS= SRCS=Solver.cpp OBJS=$(subst .cpp,.o,$(SRCS)) -c4solver:$(OBJS) main.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o c4solver main.o $(OBJS) $(LDLIBS) +ifeq ($(OS),Windows_NT) # Windows + SHARED_LIB_EXT=dll + LDFLAGS=-Wl,--output-def,solver_c_interface.def -Wl,--export-all-symbols -Wl,--out-implib,solver_c_interface.lib +else # Linux/macOS + SHARED_LIB_EXT=so + LDFLAGS= +endif + +all: c4solver generator c4solver_c_interface + +c4solver: $(OBJS) main.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o c4solver main.o $(OBJS) $(LDLIBS) generator: generator.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o generator generator.o $(LDLIBS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o generator generator.o $(LDLIBS) + +c4solver_c_interface: $(OBJS) solver_c_interface.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o c4solver_c_interface.$(SHARED_LIB_EXT) solver_c_interface.o $(OBJS) $(LDLIBS) .depend: $(SRCS) - $(CXX) $(CXXFLAGS) -MM $^ > ./.depend - + $(CXX) $(CXXFLAGS) -MM $^ > ./.depend + -include .depend clean: - rm -f *.o .depend c4solver generator - +ifeq ($(OS),Windows_NT) + del *.o .depend c4solver.exe generator.exe c4solver_c_interface.dll c4solver_c_interface.def c4solver_c_interface.lib +else + rm -f *.o .depend c4solver generator c4solver_c_interface.so +endif +PHONY: clean all \ No newline at end of file diff --git a/c_interface_test.py b/c_interface_test.py new file mode 100644 index 0000000..25e6470 --- /dev/null +++ b/c_interface_test.py @@ -0,0 +1,25 @@ +import ctypes + +# Load the shared library +solver_lib = ctypes.CDLL(r"./c4solver_c_interface.dll") + +# Define argument and return types +solver_lib.solver_init.argtypes = [ctypes.c_char_p] +solver_lib.solver_init.restype = ctypes.POINTER(ctypes.c_void_p) + +solver_lib.solver_delete.argtypes = [ctypes.POINTER(ctypes.c_void_p)] +solver_lib.solver_delete.restype = None + +solver_lib.solver_solve.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_char_p, ctypes.c_bool, ctypes.c_bool, ctypes.c_char_p, ctypes.c_size_t] +solver_lib.solver_solve.restype = ctypes.c_char_p + +# Example usage +handle = solver_lib.solver_init(None) #or None for default +result_buffer = ctypes.create_string_buffer(256) +result = solver_lib.solver_solve(handle, b"123", True, False, result_buffer, 256) +print(result.decode()) + +result = solver_lib.solver_solve(handle, b"123445622", False, True, result_buffer, 256) +print(result.decode()) + +solver_lib.solver_delete(handle) diff --git a/solver_c_interface.cpp b/solver_c_interface.cpp new file mode 100644 index 0000000..9005ebf --- /dev/null +++ b/solver_c_interface.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include "Solver.hpp" + +#ifdef _WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +using namespace GameSolver::Connect4; + +extern "C" { + + struct SolverHandle { + Solver solver; + }; + + DLLEXPORT SolverHandle* solver_init(const char* opening_book) { + SolverHandle* handle = new SolverHandle; + handle->solver.loadBook(opening_book ? opening_book : "7x6.book"); + return handle; + } + + DLLEXPORT void solver_delete(SolverHandle* handle) { + delete handle; + } + + DLLEXPORT const char* solver_solve(SolverHandle* handle, const char* past_moves, bool weak, bool analyze, char* result_buffer, size_t buffer_size) { + if (!handle || !past_moves || !result_buffer || buffer_size == 0) { + return nullptr; + } + + Position P; + std::string moves_str(past_moves); + if (P.play(moves_str) != moves_str.size()) { + snprintf(result_buffer, buffer_size, "Invalid move"); + return result_buffer; + } + + std::stringstream ss; + ss << moves_str; + + if (analyze) { + std::vector scores = handle->solver.analyze(P, weak); + for (int score : scores) { + ss << " " << score; + } + } + else { + int score = handle->solver.solve(P, weak); + ss << " " << score; + } + + std::string result = ss.str(); + if (result.size() >= buffer_size) { + snprintf(result_buffer, buffer_size, "Result too long"); + return result_buffer; + } + + strcpy(result_buffer, result.c_str()); + return result_buffer; + } +} \ No newline at end of file From 2968deda0a14fd3cbd6babda67440f56167e0f54 Mon Sep 17 00:00:00 2001 From: Tony Wang <35334345+TonyCongqianWang@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:21:49 +0200 Subject: [PATCH 2/3] Update generator.cpp --- generator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generator.cpp b/generator.cpp index 7afeb8e..8f96a12 100644 --- a/generator.cpp +++ b/generator.cpp @@ -81,7 +81,8 @@ void generate_opening_book() { int main(int argc, char** argv) { if(argc > 1) { int depth = atoi(argv[1]); - char pos_str[depth + 1] = {0}; + std::vector pos_vec(depth + 1, 0); + char* pos_str = pos_vec.data(); explore(Position(), pos_str, depth); } else generate_opening_book(); } From 8065bae8f5834f8a3b504e2e47d6b5acf48fac56 Mon Sep 17 00:00:00 2001 From: Tony Wang <35334345+TonyCongqianWang@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:46:16 +0200 Subject: [PATCH 3/3] Update generator.cpp --- generator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/generator.cpp b/generator.cpp index 8f96a12..cb75be8 100644 --- a/generator.cpp +++ b/generator.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace GameSolver::Connect4;