all repos

tyess @ 86915526855677c54de7f98b478ab064ea6d6b75

chess in typst

tyess/board.typ (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
switch to cburnett piece set, 26 days ago
1
// Pieces
2
3
#let piece-type(p) = { if p == "." { return "." }; upper(p) }
4
#let is-white(p) = p != "." and p == upper(p)
5
#let is-black(p) = p != "." and p == lower(p)
6
7
#let piece-assets = (
8
  "K": "wking.svg",   "k": "bking.svg",
9
  "Q": "wqueen.svg",  "q": "bqueen.svg",
10
  "R": "wrook.svg",   "r": "brook.svg",
11
  "N": "wknight.svg", "n": "bknight.svg",
12
  "B": "wbishop.svg", "b": "bbishop.svg",
13
  "P": "wpawn.svg",   "p": "bpawn.svg",
14
)
15
16
#let starting-grid = (
17
  ("r", "n", "b", "q", "k", "b", "n", "r"),
18
  ("p", "p", "p", "p", "p", "p", "p", "p"),
19
  (".", ".", ".", ".", ".", ".", ".", "."),
20
  (".", ".", ".", ".", ".", ".", ".", "."),
21
  (".", ".", ".", ".", ".", ".", ".", "."),
22
  (".", ".", ".", ".", ".", ".", ".", "."),
23
  ("P", "P", "P", "P", "P", "P", "P", "P"),
24
  ("R", "N", "B", "Q", "K", "B", "N", "R"),
25
)
26
27
// Coordinates
28
29
#let col-to-file = ("a", "b", "c", "d", "e", "f", "g", "h")
30
#let file-to-col = (
31
  "a": 0, "b": 1, "c": 2, "d": 3,
32
  "e": 4, "f": 5, "g": 6, "h": 7,
33
)
34
35
#let coords-to-square(col, row) = col-to-file.at(col - 1) + str(9 - row)
36
#let square-to-coords(sq) = ((file-to-col.at(sq.at(0)) + 1), (9 - int(sq.at(1))))
37
38
// Grid
39
40
#let copy-grid(g) = g.map(r => r.map(c => c))
41
#let on-board(col, row) = col >= 1 and col <= 8 and row >= 1 and row <= 8
42
#let at(grid, col, row) = {
43
  if not on-board(col, row) { return "." }
44
  grid.at(row - 1).at(col - 1)
45
}
46
47
#let find-pieces(grid, color, type) = {
48
  let pieces = ()
49
  let test = if color == "white" { is-white } else { is-black }
50
  for r in range(8) {
51
    for c in range(8) {
52
      let p = grid.at(r).at(c)
53
      if p != "." and piece-type(p) == type and test(p) {
54
        pieces.push((c + 1, r + 1))
55
      }
56
    }
57
  }
58
  pieces
59
}
60
61
#let apply-move(grid, col, row, dest-col, dest-row, promotion: none, en-passant: none) = {
62
  let g = copy-grid(grid)
63
  let piece = g.at(row - 1).at(col - 1)
64
  g.at(row - 1).at(col - 1) = "."
65
66
  if en-passant != none {
67
    g.at(en-passant.at(1) - 1).at(en-passant.at(0) - 1) = "."
68
  }
69
70
  if promotion != none {
71
    let color = if is-white(piece) { upper } else { lower }
72
    g.at(dest-row - 1).at(dest-col - 1) = color(promotion)
73
  } else {
74
    g.at(dest-row - 1).at(dest-col - 1) = piece
75
  }
76
  g
77
}
78
79
// Board
80
81
#let is-dark-sq(file, rank) = calc.rem(file + rank, 2) == 1
82
83
#let render-board(board) = {
84
  let files = ("a", "b", "c", "d", "e", "f", "g", "h")
85
  let ranks = ("8", "7", "6", "5", "4", "3", "2", "1")
86
  let cell-size = 2.8em
87
  let label-size = 0.4em
88
  let white = rgb("#f0d9b5")
89
  let black = rgb("#b58863")
90
91
  align(center + horizon, grid(
92
    columns: (cell-size,) * 8,
93
    rows: (cell-size,) * 8,
94
    ..{
95
      let cells = ()
96
      for rank in range(8) {
97
        for file in range(8) {
98
          let piece = board.at(rank).at(file)
99
          let sq-color = if is-dark-sq(file, rank) { black } else { white }
100
          let display = if piece == "." { [] } else {
101
            image("assets/" + piece-assets.at(piece), width: cell-size * 0.85)
102
          }
103
104
          let labels = ()
105
          if rank == 7 {
106
            labels.push(place(bottom + left, dx: 0.15em, dy: -0.15em, text(
107
              size: label-size,
108
              fill: if is-dark-sq(file, 7) { white } else { black },
109
              files.at(file),
110
            )))
111
          }
112
          if file == 7 {
113
            labels.push(place(top + right, dx: -0.15em, dy: 0.15em, text(
114
              size: label-size,
115
              fill: if is-dark-sq(7, rank) { white } else { black },
116
              ranks.at(rank),
117
            )))
118
          }
119
120
          cells.push(box(
121
            width: cell-size,
122
            height: cell-size,
123
            fill: sq-color,
124
            place(center + horizon, display) + labels.fold([], (acc, l) => acc + l),
125
          ))
126
        }
127
      }
128
      cells
129
    },
130
  ))
131
}