Giter Site home page Giter Site logo

chess.jl's Introduction

Chess

A Julia library for computer chess. Visit the documentation for more details.

chess.jl's People

Contributors

mcognetta avatar natesolon avatar romstad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

chess.jl's Issues

No threefold repetion draw

Is it on purpose that the isdraw(g::Game) doesn't look if it's a draw by threefold repetition, but only for material and fifty move rule?

Crazyhouse / nonstandard notation (Invalid character: @)

Hi, thanks for making a very cool package!

I was trying to read my own Lichess games but I encountered an issue with the crazyhouse variant. The problem is that dropped pieces are stored as for example "N@g3" to indicate that a knight is dropped at g3. However, when I try to read this file I get:

nested task error: Chess.PGN.PGNException("Invalid character: @")

now, obviously, the "@" is the issue. Is there a recommended workaround for this? I'm not necessarily interested in reading the games with the crazyhouse variant, so I'd be happy to skip this game if that's possible. However, my goal is to read in the larger Lichess datasets, and in those files all variants are mixed.

full example:

Chess.PGN.gamefromstring("""
[Event "Hourly Crazyhouse Arena"]
[Site "https://lichess.org/urHSzup4"]
[Date "2021.04.06"]
[White "vandenman"]
[Black "damatte"]
[Result "0-1"]
[UTCDate "2021.04.06"]
[UTCTime "17:22:01"]
[WhiteElo "1869"]
[BlackElo "2181"]
[WhiteRatingDiff "-4"]
[BlackRatingDiff "+2"]
[Variant "Crazyhouse"]
[TimeControl "300+0"]
[ECO "B02"]
[Termination "Normal"]
1. e4 Nf6 2. e5 Nc6 3. exf6 exf6 4. d4 d5 5. Bb5 Bd6 6. Bxc6+ bxc6 7. N@h5 O-O 8. Nxg7 Kxg7 9. N@h5+ Kg8 10. P@g7 Re8+ 11. Qe2 B@g4 12. Qxe8+ Qxe8+ 13. Be3 Q@d1# 0-1
""")

ERROR: Chess.PGN.PGNException("Invalid character: @")
Stacktrace:
 [1] readtoken(p::Chess.PGN.PGNReader)
   @ Chess.PGN ~/.julia/packages/Chess/oXD5R/src/pgn.jl:351
 [2] readgame(p::Chess.PGN.PGNReader; annotations::Bool)
   @ Chess.PGN ~/.julia/packages/Chess/oXD5R/src/pgn.jl:444
 [3] #gamefromstring#6
   @ ~/.julia/packages/Chess/oXD5R/src/pgn.jl:557 [inlined]
 [4] gamefromstring(s::String)
   @ Chess.PGN ~/.julia/packages/Chess/oXD5R/src/pgn.jl:557
 [5] top-level scope
   @ REPL[29]:1

attacksfrom() and the N-queens problem

Apologies for coming from left field...

I'm trying to solve the N-queens problem using Chess.jl by doing a:

julia> b = fromfen("Q7/2Q5/8/8/8/8/8/8 w - - 0 1")
Board (Q7/2Q5/8/8/8/8/8/8 w - -):
 Q  -  -  -  -  -  -  -
 -  -  Q  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -

Then calling attacksfrom():

julia> pprint(b, highlight=attacksfrom(b, SQ_A8));
+---+---+---+---+---+---+---+---+
| Q | * | * | * | * | * | * | * |
+---+---+---+---+---+---+---+---+
| * | * | Q |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
| * |   | * |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
| * |   |   | * |   |   |   |   |
+---+---+---+---+---+---+---+---+
| * |   |   |   | * |   |   |   |
+---+---+---+---+---+---+---+---+
| * |   |   |   |   | * |   |   |
+---+---+---+---+---+---+---+---+
| * |   |   |   |   |   | * |   |
+---+---+---+---+---+---+---+---+
| * |   |   |   |   |   |   | * |
+---+---+---+---+---+---+---+---+
Q7/2Q5/8/8/8/8/8/8 w - -

But the above doesn't have the attacksfrom() of the second (or... N) queen.

I'm looking at the code at squareset.jl and I'm not sure how to make queenattacks() etc. to return a set that takes into account all the queens.

Any assistance very much appreciated.

Thank you.

Suppress Printing of Game When Loading from PGN

First, thanks for the package. It is awesome and I know writing open source code can be a little thankless. Second, I have a suspicion that I'm doing something wrong here, but is there a way to suppress the printing of the entire game when you return a game from a pgn?

I have functions that look like those below, and when I run the get_game function it prints the entire game. I am a Julia noob so I might be missing something painfully obvious, and if so apologies in advance.

function create_game_id(g)
         # creates game IDs based on players, site and date played
	  white_player = Chess.whiteplayer(g)
	  black_player = Chess.blackplayer(g)
	  site         = Chess.site(g)
	  date_played  = Chess.dateplayed(g)
	  game_string  = string(white_player, " - ", black_player, " | ", site, " ", date_played)
	  game_string
end

function get_game(pgn, game_id)
        # searches the pgn file for game IDs
	for g in gamesinfile(pgn, annotations = true)
		if(create_game_id(g) == game_id)
			return g
		end
	end
end

pgn          = "C:\\Users\\<user>\\Desktop\\Chess\\Books\\PGN\\CaroKannMBM.pgn"
game_name    = "Atkins, H. - Capablanca, J. | nothing 1922-01-01"
g = get_game(pgn, game_name)

PIECE_TYPE_NONE out of bounds read

The implementation of empty square is
const PIECE_TYPE_NONE = PieceType(7)
however, Board has the field
bytype::MVector{6,SquareSet},
and the implementation of pieces is

function pieces(b::Board, t::PieceType)::SquareSet
    @inbounds b.bytype[t.val]
end

so the following will result in an out of bounds read (possible crash?)

julia> pieces(startboard(), PIECE_TYPE_NONE)
SquareSet:
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  -

I am not sure how much it would cost to introduce a branch in that statement, but somenthing like the following should be a solution;

function pieces(b::Board, t::PieceType)::SquareSet
    if t.val != 7
        @inbounds b.bytype[t.val]
    else
        return -reduce(union, b.bytype)
    end
end

If the practical cost is too high it might not be worth the fix.

b not defined

For not getting this error when you are first trying Chess.jl I think that in the documentation it should be:

b = startboard()
domove(b, "e4")

New release

Could you please stage a new release for Chess.jl? The most recent PRs are mostly performance related, but there is one bug fix #28, which I think warrants a new release so it is easier to access through the package manager.

Thanks!

Graphical board and link in Jupyter notebook

In the documentation it is said that "If you are using Chess.jl through a Pluto or Jupyter notebook, you'll see a graphical board, along with a link for opening the board in lichess." But I could not find a graphical board, nor a link in the Jupyter notebook

Custom piece types

In order to implement chess variants with nonstandard pieces, would it be possible to extend PieceType manually? I suspect that if I define const MYPIECE = PieceType(42), I will run into a whole lot of issues with the rest of the codebase?

Formatting deprecation notice

When precompiling I got this notice.

┌ Formatting [59287772-0a20-5a39-b81b-1366585eb4c0]
│  ┌ Warning: DEPRECATION NOTICE
│  │ 
│  │ Formatting.jl has been unmaintained for a while, with some serious
│  │ correctness bugs compromising the original purpose of the package. As a result,        
│  │ it has been deprecated - consider using an alternative, such as
│  │ `Format.jl` (https://github.com/JuliaString/Format.jl) or the `Printf` stdlib directly.
│  │ 
│  │ If you are not using Formatting.jl as a direct dependency, please consider
│  │ opening an issue on any packages you are using that do use it as a dependency.
│  │ From Julia 1.9 onwards, you can query `]why Formatting` to figure out which
│  │ package originally brings it in as a dependency.
│  └ @ Formatting C:\Users\dimer\.julia\packages\Formatting\3VxOt\src\Formatting.jl:12
└

Tablebase support

Are there plans to allow reading of syzygy or gaviota TBs from this library? Imo, if that was added, this would be at feature parity with Python Chess.

pickbookmove() potentially broken?

Hi there, noticed that the pickbookmove() function broke in my code after this commit:
529b11b
(I noticed this issue after updating the package)

My exact call is:
move = pickbookmove(board, "my-book.obk")
and the error I now get is
ERROR: LoadError: MethodError: no method matching pickbookmove(::Board, ::String) Closest candidates are: pickbookmove(::Board; bookfile, minscore, mingamecount) at /home/vscode/.julia/packages/Chess/86E71/src/book.jl:665

Did something change about how this function is called? I can't seem to find any working examples/documentation on if the way to use this function has changed.

Thanks!

fen(...) returns incomplete FEN

The fen() function returns incomplete FEN, missing fields 5 ("halfmove clock") and 6 ("fullmove number"). For example:

julia> b = fromfen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
Board (rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3):
 r  n  b  q  k  b  n  r
 p  p  p  p  p  p  p  p
 -  -  -  -  -  -  -  -
 -  -  -  -  -  -  -  -
 -  -  -  -  P  -  -  -
 -  -  -  -  -  -  -  -
 P  P  P  P  -  P  P  P
 R  N  B  Q  K  B  N  R

julia> fen(b)
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3"

The halfmove clock is easy to fix by using board.r50, but fullmove number requires adjustments to Board structure. I can provide a patch, but I'm not sure if the current behaviour is intentional (if it is, it would be nice to have it documented somewhere).

trying the book making functions

Hi,

I'm not a programmer, but I want to try the book making functions.
What exactly do I have to type for making a book from a pgn database?
If the folder location of the pgn is: C:\Users\Jonathan\Downloads\pgn\Magnus White.pgn

I tried to follow the manual but without succes. I must be doing sommeting wrong.
I have made a video capture of it to better explain what is going wrong:

error.bookmaking.mp4

Possible Bug in "ismovecheck()"

When trying to call ismovecheck() during a tree search I stumbled across the error

LoadError: MethodError: no method matching bishoplike(::PieceColor)
�[0mClosest candidates are:
�[0m  bishoplike(�[91m::Board�[39m) at /home/fabio/.julia/packages/Chess/86E71/src/board.jl:600
�[0m  bishoplike(�[91m::Board�[39m, �[91m::PieceColor�[39m) at /home/fabio/.julia/packages/Chess/86E71/src/board.jl:625
MethodError: no method matching bishoplike(::PieceColor)
Closest candidates are:
  bishoplike(::Board) at /home/fabio/.julia/packages/Chess/86E71/src/board.jl:600
  bishoplike(::Board, ::PieceColor) at /home/fabio/.julia/packages/Chess/86E71/src/board.jl:625

The functions bishoplike() and rooklike() take indeed a board and a color as argument but only a color is passed.

# src/board.jl:1263

# En passant checks
if moveisep(b, m)
    capsq = Square(file(t), rank(f))
    newocc = occ - f + t - capsq
    if !isempty(bishopattacks(newocc, ksq) ∩ bishoplike(us))
        return true
    end
    if !isempty(rookattacks(newocc, ksq) ∩ rooklike(us))
        return true
    end
end

I just added the board to the functions args and now it seems to work fine

# En passant checks
if moveisep(b, m)
    capsq = Square(file(t), rank(f))
    newocc = occ - f + t - capsq
    if !isempty(bishopattacks(newocc, ksq) ∩ bishoplike(b, us))
        return true
    end
    if !isempty(rookattacks(newocc, ksq) ∩ rooklike(b, us))
        return true
    end
end

List all captures in a game?

I'm experimenting with a little idea here, where I'd like to extract all the captures in a game. Something like "black pawn takes white bishop", or something like this.

Is there an easy way to use Chess.jl to get this info from a game?

Illegal move generated in castling edge case

Below is an example of an illegal move generation edge case due to improperly set castle rights.

Consider the following PGN:

1. g3 c5 2. Bg2 e6 3. d3 d5 4. Bd2 Nf6 5. e3 Be7 6. Qe2 O-O 7. f3 Nc6 8. g4 g6 9. h4 Ne8 10. h5 e5 11. hxg6 fxg6 12. Qf2 Rf7 13. Nh3 d4 14. e4 Be6 15. Ng5 Rg7 16. Nxe6 Qd7 17. Nxg7 Kxg7 18. Qg3 Bf6 19. Qh3 Nd6 20. Qxh7+ Kf8 21. Qxd7 Nf7 22. Rh7 Be7 23. Bh6+ Kg8 24. Rxf7 Kxf7 25. g5 Rd8 26. Qxb7 Na5 27. Qa6 Nc4 28. dxc4 Rd7 29. Nd2 Bd6 30. Qc6 Be7 31. Qxd7 a5 32. Qa7 Ke6 33. Qxa5 Bd6 34. Qb6 Kd7 35. b3 Bc7 36. Qf6 Kc8 37. Qxg6 Kb7 38. Qg8 Bd6 39. Bf8 Bc7 40. Qg7 Ka6 41. Be7 Bb6 42. Qg6 Ka5 43. Bf6 Kb4 44. Bxe5 Ba5 45. Qf6 Kc3 46. g6 Bb4 47. g7 Kb2 48. g8=Q Kxa1 49. Qff7 Bc3 50. Qh8 Kb2 51. Qh1 Kc1 52. Ke2+ Kb2 53. Qb1+ Ka3 54. Qa7+ Kb4 55. Qa4# 1-0

after 48. ... Kxa1, Chess.moves(b) generates the illegal move a1c1 (a kingside castle). The reasons are

  1. White never moved their king
  2. White never moved their rook
  3. Black captured the a1 rook and left their king there

The game in question is https://lichess.org/x7ej96mq#96.

If you directly import the FEN from that game/position (6Q1/8/5Q2/2p1B3/1bPpP3/1P3P2/P1PN2B1/k3K3 w - - 0 49), the illegal move is not generated, due to the castle property being properly set.

Check if black is in check?

Hello, I am currently trying to use this library to solve a variant of chess. However, the ischeck function doesn't seem to work in some positions where black is in check, even though I've used donullmove. For some reason I have to change the board into an FEN and convert back after performing the null move for it to work properly:

julia> board  = fromfen("1q2n2n/ppprkprr/1pp3pp/8/8/PPPP3P/BP2RQPB/R2BK2N w - - 0 1")
Board (1q2n2n/ppprkprr/1pp3pp/8/8/PPPP3P/BP2RQPB/R2BK2N w - -):
 -  q  -  -  n  -  -  n 
 p  p  p  r  k  p  r  r 
 -  p  p  -  -  -  p  p 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 P  P  P  P  -  -  -  P 
 B  P  -  -  R  Q  P  B 
 R  -  -  B  K  -  -  N 

julia> ischeck(board)
false

julia> ischeck(donullmove(board))   # should be true
false

julia> donullmove(board)
Board (1q2n2n/ppprkprr/1pp3pp/8/8/PPPP3P/BP2RQPB/R2BK2N b - -):
 -  q  -  -  n  -  -  n 
 p  p  p  r  k  p  r  r 
 -  p  p  -  -  -  p  p 
 -  -  -  -  -  -  -  - 
 -  -  -  -  -  -  -  - 
 P  P  P  P  -  -  -  P 
 B  P  -  -  R  Q  P  B 
 R  -  -  B  K  -  -  N 

# ^ This FEN is definitely a check, what's wrong??

julia> ischeck(fromfen(fen(donullmove(board))))  # why does this work?
true

There is certainly a check:

How can I check if black is in check properly? The workaround works for me, but doesn't seem like the proper way to do this. The problem (without looking at the internal code) is probably that the checkers bit-board isn't updated on a donullmove (maybe a call to findcheckers in that function would help?).

fromfen ignores halfmove clock.

The function fromfen seems to ignore the 5th component of the FEN string. Therefore, the following example does not work correctly:

fifty_move_board = fromfen("8/6k1/8/8/4R3/5r2/1K6/8 b - - 100 108") # position where 50 move rule has reached
isrule50draw(fifty_move_board)

Here, isrule50draw returns false. It should return true.

`pickbookmove` from compact opening book doesn't return a move

First of all I really like and appreciate this library, but haven't gotten around to really dig into the internals.

I have the following issue: when I pick a move from a "normal" opening book, it returns a move as expected, but when the book was written with the compact flag it does not.

julia> bk = createbook("lichess_elite_2021-11.pgn"); writebooktofile(bk, "lichess_elite.obk"); writebooktofile(bk, "lichess_elite_compact.obk", true);
julia> @time pickbookmove(b, bookfile="lichess_elite.obk")
  0.000294 seconds (86 allocations: 6.328 KiB)
Move(d2d4)

julia> @time pickbookmove(b, bookfile="lichess_elite_compact.obkc")
  0.000321 seconds (84 allocations: 5.844 KiB)

So it does seem to do something but does not make the chosen move accessible.

C++ Version?

This package has been incredibly useful for one of my Julia projects. However, I was wondering if you had a version of this in C++, or could point me towards a similar library for C++?

P.S. Thank you for your work on this! It's an incredibly simple interface!

Castling rights not properly updated

Given position: r1bqkbnr/ppp2pp1/2np4/4p3/6P1/2N1P3/PPPP1PB1/R1BQK1NR b KQkq - 0 6

If black plays Rxh1, the correct fen should be r1bqkbn1/ppp2pp1/2np4/4p3/6P1/2N1P3/PPPP1PB1/R1BQK1Nr w Qq - 0 7, but Chess.jl will give r1bqkbn1/ppp2pp1/2np4/4p3/6P1/2N1P3/PPPP1PB1/R1BQK1Nr w Qkq - thereby listing kingside catling as a legal move for black.

Unicode piece characters

Wouldn't be nice to print the board with the Unicode characters for the corresponding pieces (at least in environments that support Unicode, like Atom, and REPL if not in Windows)?:

  • P : ♙
  • N : ♘
  • B : ♗
  • R : ♖
  • Q : ♕
  • K : ♔
  • p : ♟
  • n : ♞
  • b : ♝
  • r : ♜
  • q : ♛
  • k : ♚

How do I get the opposite PieceColor?

x = rand(Bool) ? BLACK : WHITE

# it would be great if one of these would work:
the_other_color = -x
the_other_color = ~x
the_other_color = !x
the_other_color = inv(x)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.