it is a quite large module 300 lines:
import Base.:<<,Base.:>>,Base.:~,Base.:&,Base.:β»,Base.:|,Base.copy
export Game,
canPlay,
play,
undo,
isOver,
score,
getplayer,
getboard,
getround,
gethash,
Move,
gen_moves
const N=7
const NN=N*N
struct Square
sq::Int
end
is_pass(sq::Square)=sq.sq==-1
struct Bitboard
data::UInt64
end
Base.:<<(b::Bitboard,n)=Bitboard(b.data<<n)
Base.:>>(b::Bitboard,n)=Bitboard(b.data>>n)
Base.:~(b::Bitboard)=Bitboard(~b.data & 0x7f7f7f7f7f7f7f)
Base.:β»(b1::Bitboard,b2::Bitboard)=Bitboard(b1.data β» b2.data)
Base.:&(b1::Bitboard,b2::Bitboard)=Bitboard(b1.data & b2.data)
Base.:|(b1::Bitboard,b2::Bitboard)=Bitboard(b1.data | b2.data)
Base.iterate(b::Bitboard)=(Square(trailing_zeros(b.data)),b.data&(b.data-0x1))
Base.iterate(b::Bitboard,state)=state==0x0 ? nothing : (Square(trailing_zeros(state)),state &(state-0x1))
function set(b::Bitboard,sq::Square)
Bitboard(b.data|UInt64(1)<<sq.sq)
end
function get(b::Bitboard,sq::Square)
b.data>>sq.sq & 1
end
Bitboard(sq::Square)=Bitboard(UInt64(1)<<sq.sq)
function singles(b::Bitboard)
Bitboard((b.data << 1 | b.data << 9 | b.data >> 7 | b.data << 8 | b.data >> 8 |
b.data >> 1 | b.data >> 9 | b.data << 7) & 0x7f7f7f7f7f7f7f)
end
function singles(sq::Square)
b=Bitboard(UInt64(1)<<sq.sq)
return singles(b)
end
function doubles(b::Bitboard)
Bitboard(((b.data << 2 | b.data << 10 | b.data << 18 | b.data >> 6 | b.data >> 14 | b.data << 17 | b.data >> 15) & 0x7e7e7e7e7e7e7e) |
((b.data << 16 | b.data >> 16) & 0x7f7f7f7f7f7f7f) |
((b.data >> 2 | b.data >> 10 | b.data >> 18 | b.data << 6 | b.data << 14 | b.data << 15 | b.data >> 17) & 0x3f3f3f3f3f3f3f)
)
end
function doubles(sq::Square)
b=Bitboard(UInt64(1)<<sq.sq)
return doubles(b)
end
is_empty(b::Bitboard)=b.data==0
is_full(b::Bitboard)=b.data==0x7f7f7f7f7f7f7f
function test()
b=Bitboard(0x7f7f7f7f7f7f7f)
for x in b
println(doubles(x))
end
end
struct Board
bplayer::Bitboard
bopp::Bitboard
end
mutable struct Game
board::Board
player::Int8
pass::Int8
round::Int
end
struct Move
from::Square
to::Square
end
function Game()
bb=Bitboard(0)
bb=set(bb,Square(0))
bb=set(bb,Square(54))
bw=Bitboard(0)
bw=set(bw,Square(6))
bw=set(bw,Square(48))
return Game(
Board(bb,bw),
1,
0,
0
)
end
score(pos,n=0) = abs(sum(pos.board[:,:,1])-sum(pos.board[:,:,2]))
getplayer(pos) = pos.player
function getboard(pos)
answer = zeros(Int8, N, N, 3, 1)
answer[:,:,1:2,1].=pos.board
answer[:, :, 3, 1] .= pos.player
# if pos.player==1
# answer[:,:,1,1].=(pos.board[:,:,1,1].-pos.board[:,:,2,1])
# else
# answer[:,:,1,1].=rot180(pos.board[:,:,2,1].-pos.board[:,:,1,1])
# end
return answer
end
gethash(pos) =(deepcopy(pos.board),pos.player,pos.round)#pos.hash
getround(pos) = pos.round
other(x)=-x
index(x)=x==1 ? 1 : 2
function isOver(pos)
bplayer=pos.board.bplayer
bopp=pos.board.bopp
p=count_ones(bplayer.data)
o=count_ones(bopp.data)
if is_empty(bplayer) || is_empty(bopp)
return true,(p-o)*pos.player
end
if is_full(bplayer|bopp)
return true,sign((p-o)*pos.player)
end
if pos.pass==2
return true,sign((p-o)*pos.player)
end
if pos.round>=200
return true,sign((p-o)*pos.player)
end
return false,0
end
@inbounds @inline function play(game, move::Move)
sqf=move.from
sqt=move.to
bplayer=game.board.bplayer
bopp=game.board.bopp
if is_pass(sqf)
return Game(Board(bopp,bplayer),other(game.player),game.pass+1,game.round+1)
end
if sqf!=sqt
bplayerβ»=Bitboard(sqf)
end
bplayer=set(bplayer,sqt)
turned=singles(sqt) & bopp
boppβ»=turned
bplayer|=turned
return Game(Board(bopp,bplayer),other(game.player),0,game.round+1)
end
function gen_moves(position,answer)
cpt = 0
for sq in singles(position.board.bplayer) & ~(position.board.bplayer | position.board.bopp)
#push!(answer,Move(sq,sq))
cpt+=1
answer[cpt]=Move(sq,sq)
end
for sqf in position.board.bplayer
for sqt in doubles(sqf) & ~(position.board.bplayer | position.board.bopp)
#push!(answer,Move(sqf,sqt))
cpt+=1
answer[cpt]=Move(sqf,sqt)
end
end
if cpt==0
cpt+=1
#push!(answer,Move(Square(-1),Square(-1)))
answer[cpt]=Move(Square(-1),Square(-1))
end
cpt
end
function gen_move(position,k)
move=Move(Square(-1),Square(-1))
cpt = 0
for sq in singles(position.board.bplayer) & ~(position.board.bplayer | position.board.bopp)
move=Move(sq,sq)
cpt+=1
if cpt==k
return move
end
end
for sqf in position.board.bplayer
for sqt in doubles(sqf) & ~(position.board.bplayer | position.board.bopp)
move=Move(sqf,sqt)
cpt+=1
if cpt==k
return move
end
end
end
end
function count_moves(position)
cpt = 0
for sq in singles(position.board.bplayer) & ~(position.board.bplayer | position.board.bopp)
cpt+=1
end
for sqf in position.board.bplayer
for sqt in doubles(sqf) & ~(position.board.bplayer | position.board.bopp)
cpt+=1
end
end
if cpt==0
push!(answer,Move(Square(-1),Square(-1)))
end
cpt
end
function perft(pos,depth,moves)
nodes=0
if isOver(pos)[1]
return 0
end
if depth==1
return count_moves(pos)
end
nmoves=gen_moves(pos,moves[depth])
for k in 1:nmoves
nodes+=perft(play(pos,moves[depth][k]),depth-1,moves)#@timeit to "nested"
end
return nodes
end
function perf(pos,depth)
moves=[Vector{Move}(undef,200) for k in 1:depth]
t=time()
nodes=perft(pos,depth,moves)
t=time()-t
MN=round(nodes/(10^6*t),digits=3)
println("nodes: $nodes, speed: $MN Mn/s")
end
end
using ..GAME
function main()
game=GAME.Game()
GAME.perf(game,6)
GAME.perf(game,6)
end
main()