A Go-based optimization solver for the game Lords and Knights using greedy simulation heuristics. Provides both CLI tools and a gRPC server for integration with automation bots.
- Greedy Simulation Solver: Smart build order with resource accumulation over time
- Dual Queue System: Separate building queue and research queue (parallel execution)
- Technology Prerequisites: Library research unlocks higher building levels (e.g., Farm 15/25/30)
- gRPC Server: Exposes solver as a service for bot integration
- CLI with Cobra: Full command-line interface with flags
- Pretty Tables: Beautiful colored output with tablewriter
- Data-Driven: All building and technology data loaded from JSON files
- Deterministic: Same input always produces same output (fuzz-tested)
- Go 1.23+ (uses Go 1.25 features)
- Protocol Buffers compiler (
protoc) - protoc-gen-go and protoc-gen-go-grpc plugins
# Clone with submodules
git clone --recursive git@github.com:Napolitain/solver-lnk.git
cd solver-lnk
# Install protoc plugins (one-time)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# Generate protobuf code
go generate ./...
# Install dependencies
go mod download
# Build all binaries
go build -o castle ./cmd/castle/
go build -o server ./cmd/server/
go build -o units ./cmd/units/# Run castle solver CLI
./castle -d data
# Run gRPC server (for bot-lnk integration)
./server
# Run units solver CLI
./units -d datasolver-lnk/
├── cmd/
│ ├── castle/ # Castle build order CLI
│ ├── server/ # gRPC server for bot integration
│ └── units/ # Units solver CLI
├── internal/
│ ├── converter/ # Proto <-> internal model conversion
│ ├── loader/ # JSON data loaders
│ ├── models/ # Data models (buildings, resources, tech)
│ └── solver/
│ ├── castle/ # Castle build order solver
│ └── units/ # Units recruitment solver
├── proto/ # Protobuf definitions (submodule → proto-lnk)
├── data/ # Game data files (JSON)
│ ├── buildings/ # Building upgrade costs and times
│ └── technologies/ # Technology research data
├── go.mod
└── go.sum
# Run with default settings
./castle -d data
# Quiet mode (minimal output)
./castle -d data --quiet
# See all options
./castle --help# Start server (default port 50051)
./server
# Server listens for Solve requests from bot-lnk./units -d data╭───────────────────────────╮
│ Lords and Knights │
│ Build Order Optimizer │
│ (Go Version) │
╰───────────────────────────╯
📦 Loaded 13 buildings, 3 technologies
🔄 Solving...
✓ Found solution with 255 building upgrades and 3 research tasks!
┌─────┬─────────────┬──────────────────┬─────────┬────────────┬────────────┬──────────┬─────────────────────────────┐
│ # │ QUEUE │ ACTION │ UPGRADE │ START │ END │ DURATION │ COSTS │
├─────┼─────────────┼──────────────────┼─────────┼────────────┼────────────┼──────────┼─────────────────────────────┤
│ 1 │ 🏗️ Building │ Lumberjack │ 1 → 2 │ 00:00:00 │ 00:06:00 │ 00:06:00 │ W: 31 S: 26 I: 7 F: 2 │
│ 2 │ 🏗️ Building │ Quarry │ 1 → 2 │ 00:06:00 │ 00:11:00 │ 00:05:00 │ W: 20 S: 25 I: 12 F: 1 │
...
-
Priority-based: Buildings are ranked by priority:
- Lumberjack (wood production) → Quarry (stone) → Ore Mine (iron)
- Storage buildings when capacity needed
- Core buildings (Keep, Library) and military last
-
Resource Simulation: Tracks resource production and accumulation over real time
- Production rates based on building levels
- Storage capacity limits enforced
-
Wait-and-Build: If can't afford next priority upgrade, waits for resources to accumulate
-
Technology Prerequisites:
- Farm Level 15 requires "Crop Rotation" research
- Farm Level 25 requires "Yoke" research
- Farm Level 30 requires "Cellar Storeroom" research
The game has two parallel construction queues:
- Building Queue: All regular buildings (can only build one at a time)
- Research Queue: Library upgrades + Technology research (independent from buildings)
# Generate protobuf (after proto changes)
go generate ./...
# Build all binaries
go build ./cmd/castle && go build ./cmd/server && go build ./cmd/units
# Lint (required before commit)
golangci-lint run
# Run tests
go test ./...
# Run tests with race detection
go test -race ./...
# Run tests with coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
# Format code
go fmt ./...go test ./... # Run all tests (includes fuzz seed corpus)
go test -race ./... # With race detection
go test -coverprofile=coverage.out ./... # With coverage
go tool cover -func=coverage.out # Show coverage reportgo test ./... runs fuzz tests against their seed corpus (regression tests), but does NOT run the fuzzing engine with random generation. To actually fuzz:
Castle solver fuzz tests (internal/solver/castle/):
go test -fuzz=FuzzSolverDeterminism -fuzztime=30s ./internal/solver/castle
go test -fuzz=FuzzSolverResources -fuzztime=30s ./internal/solver/castle
go test -fuzz=FuzzSolverBuildingLevels -fuzztime=30s ./internal/solver/castleUnits solver fuzz tests (internal/solver/units/):
go test -fuzz=FuzzSolverConstraints -fuzztime=30s ./internal/solver/units
go test -fuzz=FuzzUnitThroughput -fuzztime=30s ./internal/solver/units
go test -fuzz=FuzzUnitResourceCosts -fuzztime=30s ./internal/solver/unitsgolangci-lint run && go test -race ./...This project uses golangci-lint for linting. Install it via:
# macOS
brew install golangci-lint
# Linux
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# Go install
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestAlways run before committing:
golangci-lint run
go test ./...The proto/ folder is a git submodule pointing to proto-lnk. To update:
cd proto
git pull origin master
cd ..
git add proto
git commit -m "chore: update proto submodule"- Greedy simulation solver with resource accumulation
- Storage capacity constraints
- Farm-only-when-needed logic
- Technology prerequisites (Library research)
- Dual queue system (building + research)
- Export build plans to JSON
- Custom target configurations
- Web interface for visualization
- CP-SAT solver for optimal solutions
MIT