Get started

Making moves with {chess} is easier than it looks. It has a PGN-like syntax that facilitates interaction and translation, so using the package should not be a problem if you have ever seen moves written down in a chess book.

If you haven’t, PGN means Portable Game Notation and is “a standard plain text format for recording chess games (both the moves and related data), which can be read by humans and is also supported by most chess software.”

Here you can see the beginning of a game between Fischer and Sherwin, played in 1957 at the New Jersey Open Championship. Each move is recorded in SAN and numbers followed by periods indicate the turn for each pair of half-moves. A number followed by three periods indicates the second half of the turn, or the move made by Black. Finally, parentheses indicate variations (not to be confused with variants) which are “commentaries” made by the annotator, showcasing one or more alternatives for a move and how the game could have been.

1. e4 c5 2. Nf3 e6 3. d3 Nc6 4. g3 Nf6 ( 4... d5 5. Nbd2 Bd6 6. Bg2 Nge7 7. O-O
O-O 8. Nh4 ) 5. Bg2 Be7 6. O-O O-O ( 6... d5 ) 7. Nbd2

If you think about it as a tree, this is what it would look like (rotated 90°):

                                                                ,->  d5
                                                                |
e4-> c5-> Nf3-> e6-> d3-> Nc6-> g3-> Nf6-> Bg2->  Be7-> O-O-> O-O->  Nbd2
                                 |
                                 `-> d5->  Nbd2-> Bd6-> Bg2-> Nge7-> O-O-> O-O-> Nh4

In R, the only way we can create a data structure that allows for nested substructures is with list()s. If each move was a string and each parenthesis (branch of the tree) was a list(), we would have something like this:

"e4", "c5", "Nf3", "e6", "d3", "Nc6", "g3", "Nf6", list("d5", "Nbd2", "Bd6", "Bg2",
"Nge7", "O-O", "O-O", "Nh4"), "Bg2", "Be7", "O-O", "O-O", list("d5"), "Nbd2"

Now we can pass this on to move() and create a faithful reproduction to Fisher’s annotations in {chess}, and, since the function is very flexible, you can also break down the tree into multiple moves:

library(chess)

# Add moves to a new game
fischer_sherwin <- game() %>%
  move(
    "e4", "c5", "Nf3", "e6", "d3", "Nc6", "g3", "Nf6", list("d5", "Nbd2", "Bd6", "Bg2",
    "Nge7", "O-O", "O-O", "Nh4"), "Bg2", "Be7", "O-O", "O-O", list("d5"), "Nbd2"
  )

# See the last move from the mainline
fischer_sherwin
#>       <7. Nbd2>
#> r . b q . r k .
#> p p . p b p p p
#> . . n . p n . .
#> . . p . . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P N . P B P
#> R . B Q . R K .

# Mainline and variations added separately
fischer_sherwin <- game() %>%
  move("e4", "c5", "Nf3", "e6", "d3", "Nc6", "g3", "Nf6") %>%
  move(list("d5", "Nbd2", "Bd6", "Bg2", "Nge7", "O-O", "O-O", "Nh4")) %>%
  move("Bg2", "Be7", "O-O", "O-O") %>%
  move(list("d5")) %>%
  move("Nbd2")

# The same as above
fischer_sherwin
#>       <7. Nbd2>
#> r . b q . r k .
#> p p . p b p p p
#> . . n . p n . .
#> . . p . . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P N . P B P
#> R . B Q . R K .

With the game fully prepared, we can start to move up and down the tree, exploring each element of the game as well as its variations. forward() and back() advance and go back through the game, while variations() and variation() make seeing and entering variations possible.

# Get the start of the game
start <- root(fischer_sherwin)

# Checkout the first move
start %>%
  forward()
#>         <1. e4>
#> 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

# Checkout the seventh move
start %>%
  forward(7)
#>         <4. g3>
#> r . b q k b n r
#> p p . p . p p p
#> . . n . p . . .
#> . . p . . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P . . P . P
#> R N B Q K B . R

# See possibilities for eighth move
start %>%
  forward(7) %>%
  variations()
#>      <4... Nf6>          <4... d5>
#> r . b q k b . r    r . b q k b n r
#> p p . p . p p p    p p . . . p p p
#> . . n . p n . .    . . n . p . . .
#> . . p . . . . .    . . p p . . . .
#> . . . . P . . .    . . . . P . . .
#> . . . P . N P .    . . . P . N P .
#> P P P . . P . P    P P P . . P . P
#> R N B Q K B . R    R N B Q K B . R

# Checkout the first move of variation
start %>%
  forward(7) %>%
  variation(2)
#>       <4... d5>
#> r . b q k b n r
#> p p . . . p p p
#> . . n . p . . .
#> . . p p . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P . . P . P
#> R N B Q K B . R

# Variation 1 is always the "trunk"
start %>%
  forward(7) %>%
  variation(1)
#>      <4... Nf6>
#> r . b q k b . r
#> p p . p . p p p
#> . . n . p n . .
#> . . p . . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P . . P . P
#> R N B Q K B . R

# Checkout second move of variation
start %>%
  forward(7) %>%
  variation(2) %>%
  forward()
#>       <5. Nbd2>
#> r . b q k b n r
#> p p . . . p p p
#> . . n . p . . .
#> . . p p . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P N . P . P
#> R . B Q K B . R

# Checkout second to last move
fischer_sherwin %>%
  back()
#>      <6... O-O>
#> r . b q . r k .
#> p p . p b p p p
#> . . n . p n . .
#> . . p . . . . .
#> . . . . P . . .
#> . . . P . N P .
#> P P P . . P B P
#> R N B Q . R K .

# Checkout other possibilities for that
fischer_sherwin %>%
  back(2) %>%
  variations()
#>      <6... O-O>          <6... d5>
#> r . b q . r k .    r . b q k . . r
#> p p . p b p p p    p p . . b p p p
#> . . n . p n . .    . . n . p n . .
#> . . p . . . . .    . . p p . . . .
#> . . . . P . . .    . . . . P . . .
#> . . . P . N P .    . . . P . N P .
#> P P P . . P B P    P P P . . P B P
#> R N B Q . R K .    R N B Q . R K .