all repos

tyess @ 9d6800b9bd7749121b543980527b071ac0d497f6

chess in typst

tyess/board.typ (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
what's creamy, 27 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.png",   "k": "bking.png",
9
  "Q": "wqueen.png",  "q": "bqueen.png",
10
  "R": "wrook.png",   "r": "brook.png",
11
  "N": "wknight.png", "n": "bknight.png",
12
  "B": "wbishop.png", "b": "bbishop.png",
13
  "P": "wpawn.png",   "p": "bpawn.png",
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
87
  let light-square = rgb("#f0d9b5")
88
  let dark-square = rgb("#b58863")
89
90
  let cell-size = 2.8em
91
  let coord-size = 0.6em
92
93
  align(center + horizon, grid(
94
    columns: (coord-size,) + (cell-size,) * 8,
95
    rows: (cell-size,) * 8 + (coord-size,),
96
    ..{
97
      let rows = ()
98
      for rank in range(8) {
99
        rows.push(text(size: coord-size, ranks.at(rank)))
100
        for file in range(8) {
101
          let piece = board.at(rank).at(file)
102
          let sq-color = if is-dark-sq(file, rank) { dark-square } else { light-square }
103
          let display = if piece == "." { [] } else { image("assets/" + piece-assets.at(piece), width: cell-size * 0.85) }
104
          rows.push(box(width: cell-size,
105
                        height: cell-size,
106
                        fill: sq-color,
107
                        align(center + horizon, display)))
108
        }
109
      }
110
      rows.push([])
111
      for f in files { rows.push(text(size: coord-size, f)) }
112
113
      rows
114
    },
115
  ))
116
}