Skip to content

Commit

Permalink
movegen, perft and play random moves
Browse files Browse the repository at this point in the history
  • Loading branch information
vinymeuh committed Jan 26, 2024
1 parent b7d4d28 commit 938cc25
Show file tree
Hide file tree
Showing 53 changed files with 2,590 additions and 2,422 deletions.
4 changes: 4 additions & 0 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
template: |
## What's Changed
$CHANGES
40 changes: 40 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
on:
push:
tags:
- 'v*'

name: Release

jobs:
create_draft_release:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: ${{ github.ref_name }}
version: ${{ github.ref_name }}

# release:
# strategy:
# matrix:
# include:
# - os: ubuntu-latest
# artifact_file: hifumi-linux-amd64.tgz
# runs-on: ${{ matrix.os }}
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - name: Setup Go
# uses: actions/setup-go@v4
# with:
# go-version-file: './go.mod'
# - name: Build release
# run: |
# go build -o hifumi cmd/hifumi/main.go
27 changes: 0 additions & 27 deletions .github/workflows/sonarcloud.yml

This file was deleted.

26 changes: 19 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
---
name: Tests

on:
push:
tags-ignore:
- v*
pull_request:
branches:
- main
workflow_dispatch:

name: Tests

jobs:
gotest:
name: Go Tests
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -20,6 +22,16 @@ jobs:
uses: actions/setup-go@v4
with:
go-version-file: './go.mod'
- name: Unit Tests
run: go test -coverprofile=coverage.out -covermode=count ./shogi/... ./engine/...

- name: Run tests for shogi package
run: |
go test -covermode=count -coverprofile=coverage.out \
-coverpkg=github.com/vinymeuh/hifumi/shogi ./shogi ./tests_perft
- name: Retrieve total coverage for shogi package
run: |
totalCoverage=$(go tool cover -func=coverage.out | awk '/total:/ {print $3}')
echo "Current test coverage: $totalCoverage"
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/hifumi
*.prof
coverage.out
/tests_perft.test
*.pprof
*.out
*.html
6 changes: 3 additions & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ linters:
- unused

linters-settings:
gocritic:
disabled-checks:
- exitAfterDefer
govet:
enable-all: true
revive:
Expand Down Expand Up @@ -38,6 +41,3 @@ linters-settings:
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
exhaustruct:
exclude:
- '.*\.Shift$'
44 changes: 44 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
SHELL := /usr/bin/env bash -o pipefail

EXE_NAME=hifumi

## help: print this help message
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
.PHONY: help

## build: build the application
build:
go build -o ${EXE_NAME} cmd/hifumi/main.go
.PHONY: build

## run: run the application
run: build
@./hifumi
.PHONY: run

## test: run all tests
test:
go test ./...
.PHONY: test

## test/perft: run perft tests
test/perft:
go test ./shogi ./tests_perft -covermode=count -coverpkg=github.com/vinymeuh/hifumi/shogi
.PHONY: test/perft

## bench/perft: run perft benchmarks
bench/perft:
go test ./tests_perft -bench=. -run=^# -benchmem -memprofile memprofile.out -cpuprofile profile.out
.PHONY: bench/perft

## bench/perft/cpu: run perft benchmarks then pprof cpu usage
bench/perft/cpu: bench/perft
go tool pprof profile.out
.PHONY: bench/perft/cpu

## bench/perft/mem: run perft benchmarks then pprof memory usage
bench/perft/mem: bench/perft
go tool pprof memprofile.out
.PHONY: bench/perft/mem
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,28 @@
[![Tests Status](https://github.com/vinymeuh/hifumi/actions/workflows/tests.yml/badge.svg)](https://github.com/vinymeuh/hifumi/actions?query=workflow%3Atests)

A Shogi USI engine written in Go.

---

## Status

Currently, calling it Shogi engine might be a bit of an exaggeration: **hifumi** plays by choosing a move at random. Only the movement generator is implemented but it is slow and certainly buggy. At least we have already been able to play and lose lots of games against [Fairy Stockfish](https://github.com/fairy-stockfish/Fairy-Stockfish) :satisfied: .

## Building from source

Clone this repository then run ```go build -o hifumi cmd/hifumi/main.go```.

## Features implemented

* Board representation
* Hybrid solution mixing mailbox (9x9) and bitboards
* Move generation
* Using bitboards for non-sliding pieces
* Magic bitboards for sliding pieces (lance, bishop and rook)

## Resources

* [The Chess Programming Wiki](https://www.chessprogramming.org/)
* [The Universal Shogi Interface](http://hgm.nubati.net/usi.html)
* [Chess Move Generation with Magic Bitboards](https://essays.jwatzman.org/essays/chess-move-generation-with-magic-bitboards.html)
* [Magical Bitboards and How to Find Them: Sliding move generation in chess](https://analog-hors.github.io/site/magic-bitboards/)
68 changes: 68 additions & 0 deletions cmd/findmagic/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2023 VinyMeuh
// SPDX-License-Identifier: MIT
package main

import (
"fmt"
"os"
"runtime/pprof"

"github.com/vinymeuh/hifumi/shogi"
"github.com/vinymeuh/hifumi/shogi/movegen"
)

type findPieceMagicFunc func(sq uint8) uint64

func findMagic(fn findPieceMagicFunc) {
for sq := uint8(0); sq < shogi.SQUARES; sq++ {
magic := fn(sq)
if magic > 0 {
if sq%9 == 0 && sq != 0 {
fmt.Println()
}
fmt.Printf(" 0x%0X,", magic)
} else {
fmt.Fprintf(os.Stderr, "unable to find magic number")
return
}
}
}

func usage() {
fmt.Println("Usage: findmagic blacklance|whitelance|bishop|rook-h|rook-v")
}

func main() {
if len(os.Args) != 2 {
usage()
os.Exit(1)
}

f, err := os.Create("./findmagic.prof")
if err == nil {
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}

switch os.Args[1] {
case "blacklance":
fmt.Println("var blackLanceMagics = [shogi.SQUARES]uint64{")
findMagic(movegen.FindBlackLanceMagic)
case "whitelance":
fmt.Println("var whiteLanceMagics = [shogi.SQUARES]uint64{")
findMagic(movegen.FindWhiteLanceMagic)
case "bishop":
fmt.Println("var bishopMagics = [shogi.SQUARES]uint64{")
findMagic(movegen.FindBishopMagic)
case "rook-h":
fmt.Println("var rookHMagics = [shogi.SQUARES]uint64{")
findMagic(movegen.FindRookHMagic)
case "rook-v":
fmt.Println("var rookVMagics = [shogi.SQUARES]uint64{")
findMagic(movegen.FindRookVMagic)
default:
usage()
defer os.Exit(1)
}
fmt.Printf("\n}\n")
}
44 changes: 44 additions & 0 deletions cmd/hifumi/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2023 VinyMeuh
// SPDX-License-Identifier: MIT
package main

import (
"fmt"
"log"
"os"
"runtime"
"runtime/pprof"
"time"

"github.com/vinymeuh/hifumi/engine"
)

func main() {
prefix := fmt.Sprintf("%s-%s-%s-", engine.EngineName, engine.EngineVersion, time.Now().Format("2006-01-02T150405"))
if _, ok := os.LookupEnv("HIFUMI_PPROF"); ok {
f, err := os.Create(prefix + "cpu.pprof")
if err != nil {
log.Fatal("could not create CPU profile file:", err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile:", err)
}
defer pprof.StopCPUProfile()
}

engine.UsiLoop()

if _, ok := os.LookupEnv("HIFUMI_PPROF"); ok {
runtime.GC()
f, err := os.Create(prefix + "mem.pprof")
if err != nil {
log.Fatal("could not create Heap profile file:", err)
}
defer f.Close()
runtime.MemProfileRate = 2048
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write Heap profile:", err)
}
}
}
Loading

0 comments on commit 938cc25

Please sign in to comment.