|
1
|
#import "board.typ": file-to-col, square-to-coords |
|
2
|
|
|
3
|
#let str-index-of(s, c) = { |
|
4
|
for i in range(s.len()) { if s.at(i) == c { return i } } |
|
5
|
none |
|
6
|
} |
|
7
|
|
|
8
|
#let parse-move(move-str) = { |
|
9
|
let s = move-str.trim() |
|
10
|
let suffix = "" |
|
11
|
if s.len() > 0 and (s.at(-1) == "+" or s.at(-1) == "#") { |
|
12
|
suffix = s.at(-1) |
|
13
|
s = s.slice(0, -1) |
|
14
|
} |
|
15
|
|
|
16
|
// promotion (e8=Q, e8) |
|
17
|
let promotion = none |
|
18
|
let idx = str-index-of(s, "=") |
|
19
|
if idx != none { |
|
20
|
promotion = s.slice(idx + 1, s.len()) |
|
21
|
s = s.slice(0, idx) |
|
22
|
} |
|
23
|
|
|
24
|
// castling |
|
25
|
if lower(s) == "o-o" or s == "0-0" { return (kind: "castle", side: "kingside", suffix: suffix) } |
|
26
|
if lower(s) == "o-o-o" or s == "0-0-0" { return (kind: "castle", side: "queenside", suffix: suffix) } |
|
27
|
|
|
28
|
// determine piece type |
|
29
|
let ptype = "P" |
|
30
|
let pi = 0 |
|
31
|
if s.len() > 0 and "KQRNBkqrn".contains(s.at(0)) { |
|
32
|
ptype = ("k": "K", "q": "Q", "r": "R", "n": "N").at(s.at(0), default: s.at(0)) |
|
33
|
pi = 1 |
|
34
|
} |
|
35
|
|
|
36
|
// find dest square |
|
37
|
let dest-start = -1 |
|
38
|
for i in range(pi, s.len() - 1) { |
|
39
|
if "abcdefgh".contains(s.at(i)) and "12345678".contains(s.at(i + 1)) { dest-start = i } |
|
40
|
} |
|
41
|
|
|
42
|
if dest-start == -1 { return (kind: "error", raw: s) } |
|
43
|
let dest = square-to-coords(s.at(dest-start) + s.at(dest-start + 1)) |
|
44
|
|
|
45
|
// check for capture by scanning for 'x' before destination |
|
46
|
let is-capture = false |
|
47
|
for i in range(pi, dest-start) { |
|
48
|
if s.at(i) == "x" { |
|
49
|
is-capture = true |
|
50
|
break |
|
51
|
} |
|
52
|
} |
|
53
|
|
|
54
|
// disambiguation between piece and destination |
|
55
|
let disambig = none |
|
56
|
if dest-start > pi { |
|
57
|
let between = s.slice(pi, dest-start) |
|
58
|
let capture-fix = if is-capture { between.replace("x", "") } else { between } |
|
59
|
if capture-fix.len() == 1 { |
|
60
|
if "abcdefgh".contains(capture-fix) { disambig = (type: "file", value: capture-fix) } |
|
61
|
else if "12345678".contains( capture-fix,) { disambig = (type: "rank", value: capture-fix) } |
|
62
|
} else if capture-fix.len() == 2 { |
|
63
|
if "abcdefgh".contains(capture-fix.at(0)) and "12345678".contains(capture-fix.at(1)) { |
|
64
|
disambig = (type: "square", value: capture-fix) |
|
65
|
} |
|
66
|
} |
|
67
|
} |
|
68
|
|
|
69
|
return ( |
|
70
|
kind: "move", |
|
71
|
piece: ptype, |
|
72
|
dest: dest, |
|
73
|
capture: is-capture, |
|
74
|
promotion: promotion, |
|
75
|
suffix: suffix, |
|
76
|
disambig: disambig, |
|
77
|
raw: s, |
|
78
|
) |
|
79
|
} |