Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion example.typ
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#import "lib.typ": go-board, go-board-9, go-board-19
#import "lib.typ": go-board, go-board-19, go-board-9, sgf_metadata_table, sgf_moves_board


#set page(margin: 1cm, height: auto)
Expand Down Expand Up @@ -46,3 +46,19 @@
kind: "goban",
supplement: [Goban],
)

#pagebreak()
= Use `SGF` files
== Metadata Table
#sgf_metadata_table("./pietsch-vs-norimoto-1997.sgf")

== Moves on a Board
#go-board(
size: 19,
stones: (
sgf_moves_board("./pietsch-vs-norimoto-1997.sgf")
),
stone-diameter-ratio: 1,
board-fill: none,
add-played-number: true,
)
119 changes: 119 additions & 0 deletions lib.typ
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,122 @@
marks: ((2, 2), (6, 2), (2, 6), (6, 6), (4, 4)),
)

#let sgf_parse(file_path) = {
let file_contents = read(file_path)
let lines = file_contents.split(";")

let metadata_raw = lines.at(1).replace("\n", "").split("]")
if metadata_raw.at(-1) == "" {
metadata_raw.pop()
}
let metadata = ()

for m_raw in metadata_raw {
metadata.insert(metadata.len(), m_raw.split("["))
}

let entries = ()
let moves = ()
let entries = lines.slice(2)

for entry in entries {
let entry_list = entry.split("[")

let player = ""
if entry_list.at(0) == "B" {
player = "Black"
} else if entry_list.at(0) == "W" {
player = "White"
}

let move_pre = entry_list.at(1).split("]").at(0)
let move = move_pre.at(1) + move_pre.at(0)

let commentary = ""
if entry_list.len() > 2 {
commentary = entry_list.at(2).replace("])", "")
}

moves.insert(moves.len(), (player, move, commentary))
}

return (metadata, moves)
}

#let sgf_metadata_dict(file_path) = {
let metadata = sgf_parse(file_path).at(0)
let metadata_dict = metadata.to-dict()
return metadata_dict
}

#let sgf_moves(file_path) = {
let data = sgf_parse(file_path)
return data.at(1)
}

#let sgf_metadata_table(file_path) = {
let mapping = (
AB: "Player - Black – Initial Locations of Stones",
AW: "Player - White – Initial Locations of Stones",
AN: "Misc - Annotations",
AP: "File - Creating Application",
B: "Player - Black – Move",
BR: "Player - Black – Rank",
BT: "Player - Black – Name of Team",
C: "Misc - Comment",
CP: "Misc - Copyright",
DT: "Game - Date",
EV: "Event - Name",
FF: "File - Format – SGF Version",
GM: "Game - Type",
GN: "Game - Name",
HA: "Game - Handicap",
KM: "Game - Komi",
ON: "Game - Opening",
OT: "Game - Overtime",
PB: "Player - Black – Name",
PC: "Game - Place",
PL: "Game - Color of starting Player",
PW: "Player - White – Name",
RE: "Game - Result",
RO: "Game - Round",
RU: "Game - Ruleset",
SO: "File - Source",
SZ: "Board - Size",
TM: "Game - Time limit [s]",
US: "File - Creator",
W: "Player - White – Move",
WR: "Player - White – Rank",
WT: "Player - White – Name of Team",
)

let metadata_dict = sgf_metadata_dict(file_path)
let metadata = ()
let cat-key = ()
for m in metadata_dict {
if m.at(0) in mapping {
cat-key = mapping.at(m.at(0)).split(" - ")
metadata.insert(metadata.len(), (cat-key.at(0), cat-key.at(1), m.at(1)))
}
}

let metadata_sorted = metadata.sorted(key: it => (it.at(0), it.at(1)))

return [
#table(
columns: (auto, auto, auto),
inset: 6pt,
align: horizon,
table.header([*Category*], [*Key*], [*Value*]),
..metadata_sorted.flatten(),
)]
}

#let sgf_moves_board(file_path) = {
let moves = sgf_moves(file_path)
let moves_board = ()
for move in moves {
moves_board.insert(moves_board.len(), move.at(1))
}
return moves_board
}
42 changes: 42 additions & 0 deletions pietsch-vs-norimoto-1997.sgf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
(
;
FF[4]
EV[LG Cup,2,Korea,LG]
RO[1]
PB[Hans Pietsch]
BR[1 dan]
PW[Yoda Norimoto]
WR[9 dan]
DT[1997-06-27]
PC[Seoul, Korea]
RE[B+0.5]

;B[pd];W[dp];B[pp];W[ed];B[cd];W[cc];B[bc];W[dc];B[be];W[ic]
;B[df];W[cm];B[kc];W[ie];B[qf];W[ke];B[mc];W[nq];B[kp];W[no]
;B[pn];W[pr];B[qq];W[kr];B[nm];W[pj];B[mp];W[np];B[pl];W[nj]
;B[lj];W[eq];B[jd];W[id];B[ph];W[mk];B[lm];W[lk];B[jj];W[kj]
;B[ki];W[kk];B[ji];W[jc];B[jm];W[jk];B[ik];W[il];B[jl];W[ol]
;B[om];W[mn];B[mm];W[ql];B[qm];W[pk];B[rl];W[pm];B[jr];W[kq]
;B[jq];W[rm];B[pl];W[hk];B[ij];W[pm];B[qn];W[rk];B[qr];W[mq]
;B[lp];W[lq];B[io];W[oq];B[ck];W[dk];B[cl];W[dl];B[bm];W[cn]
;B[bn];W[bo];B[cj];W[dj];B[dm];W[dn];B[bp];W[ao];B[di];W[ci]
;B[bi];W[pc];B[qc];W[oc];B[qd];W[nd];B[le];W[nf];B[me];W[ne]
;B[nh];W[mg];B[kf];W[mh];B[je];W[jf];B[kd];W[jg];B[kg];W[lh]
;B[em];W[en];B[mf];W[ng];B[fm];W[ei];B[dh];W[fn];B[gm];W[gi]
;B[gg];W[hh];B[hl];W[eg];B[fe];W[dg];B[ch];W[eh];B[ee];W[fd]
;B[ge];W[dd];B[cf];W[hg];B[gr];W[fr];B[dr];W[er];B[gq];W[fp]
;B[ri];W[qb];B[rb];W[bb];B[ab];W[ba];B[hf];W[if];B[fj];W[gl]
;B[im];W[ej];B[fk];W[gh];B[ps];W[os];B[qs];W[ms];B[jb];W[ib]
;B[kb];W[ho];B[hp];W[hn];B[hj];W[in];B[jn];W[gp];B[hq];W[de]
;B[ef];W[pb];B[gd];W[gc];B[ia];W[ha];B[ja];W[hc];B[nb];W[ra]
;B[sb];W[oh];B[oi];W[ni];B[pi];W[pg];B[qg];W[ln];B[kn];W[pf]
;B[sn];W[pe];B[qe];W[rn];B[ro];W[sl];B[fi];W[fg];B[gf];W[fh]
;B[gn];W[go];B[pq];W[or];B[qj];W[rj];B[sj];W[ce];B[bd];W[cg]
;B[bg];W[js];B[is];W[ks];B[ga];W[hb];B[hs];W[li];B[nl];W[oj]
;B[pl];W[bl];B[bk];W[pm];B[co];W[cp];B[pl];W[qk];B[qi];W[pm]
;B[al];W[md];B[nc];W[od];B[ld];W[oo];B[pl];W[po];B[qo];W[pm]
;B[an];W[do];B[pl];W[hm];B[gk];W[pm];B[bq];W[cr];B[pl];W[sk]
;B[si];W[pm];B[br];W[cq];B[pl];W[rc];B[rd];W[pm];B[ap];W[co]
;B[pl];W[sm];B[ok];W[so];B[rp];W[nk];B[ol];W[lo];B[ko];W[fs]
;B[jh];W[oa];B[na];W[ob];B[sp];W[gs];B[kl];W[ih];B[lg];W[sn]
)