/baduk-lua.tex
LaTeX | 570 lines | 373 code | 135 blank | 62 comment | 0 complexity | a252292a2c798479898157dc15a3e982 MD5 | raw file
-
- \writestatus{loading}{Go/WeiQi/Baduk Lua module}
-
-
- \startluacode
-
- Game = [[
- (;CA[Windows-1252]SZ[19]AP[MultiGo:4.4.4]EV[14th ch-kr Tengen, game 1]DT[2010-07-11]
- PB[Chen Yaoye]BR[9p]PW[Park Junghwan]WR[8p]KM[6.5]RE[B+R]
- ;B[pd];W[dd];B[qp];W[dq];B[co];W[oq];B[mp];W[qf];B[pi];W[md];B[qe];W[pf];B[oe];W[pe]
- ;B[qd];W[od];B[of];W[og];B[nd];W[oc];B[nc];W[pc];B[rf];W[rg];B[ng];W[qc];B[rc];W[sf]
- ;B[rd];W[rb];B[ob];W[qb];B[pg];W[re];B[oh];W[oo];B[qn];W[pn];B[pm];W[om];B[pl];W[kp]
- ;B[mn];W[pp];B[ep];W[qq];B[qo];W[eq];B[fp];W[gq];B[gp];W[hq];B[hp];W[rq];B[iq];W[ir]
- ;B[jr];W[ip];B[jq];W[cq];B[nr];W[or];B[cf];W[di];B[ef];W[fc];B[dk];W[fi];B[gf];W[ek]
- ;B[el];W[dl];B[cl];W[dm];B[ck];W[fk];B[em];W[id];B[eh];W[ei];B[cc];W[cd];B[bd];W[dc]
- ;B[bb];W[cb];B[bc];W[mc];B[mb];W[ne];B[nb];W[kc];B[me];W[en];B[dn];W[ri];B[hk];W[hi]
- ;B[jd];W[ic];B[gd];W[gc];B[jk];W[fl];B[cm];W[ji];B[kd];W[le];B[jc];W[jf];B[mf];W[jb]
- ;B[kb];W[ib];B[np];W[ol];B[po];W[op];B[on];W[nn];B[no];W[pn];B[qg];W[rf];B[on];W[ce]
- ;B[be];W[pn];B[gh];W[fh];B[fg];W[hh];B[on];W[cg];B[bf];W[pn];B[bp];W[is];B[on];W[jp]
- ;B[lq];W[pn];B[br];W[cr];B[on];W[il];B[nm];W[jl];B[kl];W[kk];B[km];W[lk];B[hl];W[hm]
- ;B[jj];W[dg];B[df];W[kj];B[gm];W[kn];B[hn];W[jm];B[lm];W[ik];B[jn])
- ]]
-
-
- EMPTY = 0
- BLACK = 1
- WHITE = 2
- ONSTACK = 4
- DEAD = 5
-
- Status = {FirstMove = 1, LastMove = 999, FirstMoveLabel = 1, LastMoveLabel = 999}
-
- function displayMove (num)
- if num < Status.FirstMove or num > Status.LastMove then return false else return true end
- end
-
-
- function writeLabel (num)
- if num < Status.FirstMoveLabel or num > Status.LastMoveLabel then return false else return true end
- end
-
-
- function setLabelBoundaries (start, stop)
- Status.FirstMoveLabel = start
- Status.LastMoveLabel = stop
- end
-
-
- function setMoveBoundaries (start, stop)
- Status.FirstMove = start
- Status.LastMove = stop
- end
-
- Board = { Size = 19, LastColor = WHITE, MoveNumber = 0, Label = {}; {}}
-
- Big = { Board = 15, Grid = 0.7, Stone = 14.5, Label = 0.9 } --> Big sized goban
- Medium = { Board = 12, Grid = 0.5, Stone = 11.5, Label = 0.7 } --> Medium sized goban
- Small = { Board = 10, Grid = 0.4, Stone = 9.5, Label = 0.55 } --> Small sized goban
-
- Unit = Big
-
- Hoshi19 = {{x=4, y=4}, {x=4, y=10}, {x=4, y=16}, {x=10, y=4}, {x=10, y=10}, {x=10, y=16}, {x=16, y=4}, {x=16, y=10},{x=16, y=16}}
- Hoshi13 = {{x=4, y=4}, {x=4, y=10}, {x=10, y=4}, {x=10, y=10}, {x=7, y=7}}
- Hoshi9 = {{x=3, y=3}, {x=3, y=7}, {x=7, y=3}, {x=7, y=7}, {x=5, y=5}}
-
- Hoshi = Hoshi19
-
- ---------------------------------------------------------
- --- TeX (MetaPost) drawing functions
- ---------------------------------------------------------
-
- function stone (x, y, c) --> x, y: number; c: string (color: white or black)
- tex.sprint("fill fullcircle scaled " .. Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withcolor " .. c .. " ;")
- tex.sprint("draw fullcircle scaled " .. Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withcolor black ;")
- end
-
-
- function circleMarker (x, y, c)
- tex.sprint("draw fullcircle scaled " .. 0.6*Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withpen pencircle scaled (" .. 2*Unit.Grid .. ") withcolor " .. c .. " ;")
- end
-
-
- function label (l, x, y, c)
- tex.sprint("label(textext(\"\\color[" .. c .. "]{\\bf\\ssxx " .. l .. "}\"),(" .. x*Unit.Board .. ',' .. y*-Unit.Board .. ')) ;')
- end
-
-
- function drawGoban ()
- for i=1, Board.Size do
- tex.sprint("draw (" .. Unit.Board .. "," .. i*-Unit.Board .. ") -- (" .. Board.Size*Unit.Board .. "," .. i*-Unit.Board .. ") withpen pencircle scaled " .. Unit.Grid .. " ;")
- tex.sprint("draw (" .. i*Unit.Board .. "," .. -Unit.Board .. ") -- (" .. i*Unit.Board .. "," .. Board.Size*-Unit.Board .. ") withpen pencircle scaled " .. Unit.Grid .. " ;")
- end
-
- tex.sprint("draw (" .. Unit.Board .. "," .. -Unit.Board .. ") -- (" .. Board.Size*Unit.Board .. "," .. -Unit.Board ..") -- (" .. Board.Size*Unit.Board .. "," .. Board.Size*-Unit.Board .. ") -- (" .. Unit.Board .. "," .. Board.Size*-Unit.Board .. ") -- cycle withpen pencircle scaled (" ..2.5*Unit.Grid .. ") ;")
-
- for i=1, #Hoshi do
- x = Hoshi[i].x; y = Hoshi[i].y
- tex.sprint("drawdot (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withpen pencircle scaled (" .. 5*Unit.Grid .. ") ;")
- end
- end
-
-
- function drawStones ()
- for i=1, Board.Size do
- for j=1, Board.Size do
- if Board[i][j] == BLACK then stone(i, j, "black") elseif Board[i][j] == WHITE then stone(i, j, "white") end
- if Board.Label[i][j] > 0 then
- if Board[i][j] == BLACK then
- label(Board.Label[i][j], i, j, "white")
- elseif Board[i][j] == WHITE then
- label(Board.Label[i][j], i, j, "black")
- end
- elseif Board.Label[i][j] < 0 then
- if Board[i][j] == BLACK then circleMarker(i, j, "white") else circleMarker(i, j, "black") end
- end
- end
- end
- end
-
-
- function displayBoard (name, size, p1, p2)
-
- if size == "small" then
- Unit = Small
- elseif size == "medium" then
- Unit = Medium
- else
- Unit = Big
- end
-
- tex.sprint("\\startuseMPgraphic{" .. name .. "}{}")
- tex.sprint("path p ;")
-
- drawGoban()
- drawStones()
-
- if p1 then
- local x1, y1 = Point(p1)
- local x2, y2 = Point(p2)
- tex.sprint("p:= (" .. (x1-1)*Unit.Board .. "," .. (y1-1)*-Unit.Board ..") -- (" .. x2*Unit.Board .. "," .. (y1-1)*-Unit.Board .. ") -- (" .. x2*Unit.Board .. "," .. y2*-Unit.Board .. ") -- (" .. (x1-1)*Unit.Board .. "," .. y2*-Unit.Board .. ") -- cycle ;")
- tex.sprint("clip currentpicture to p shifted (" .. Unit.Board/2 .. "," .. -Unit.Board/2 .. ") ;")
- end
-
- tex.sprint("\\stopuseMPgraphic")
- tex.sprint("\\useMPgraphic{" .. name .. "}")
- end
-
-
- function setStone (p, c) --> c = "black", "white" or "empty" (AB, AW, AE)
- local x, y = Point(p)
- if c == "black" then
- Board[x][y] = BLACK
- elseif c == "white" then
- Board[x][y] = WHITE
- elseif c == "empty" then
- Board[x][y] = EMPTY
- end
- end
-
-
- function Point (p)
- local x, y = 0, 0
- local l = "abcdefghijklmnopqrstuvwxyz"
- x = string.find(l, string.sub(p, 1, 1))
- y = string.find(l, string.sub(p, 2, 2))
- return x, y
- end
-
-
- function setMarker (p)
- local x, y = Point(p)
- if Board[x][y] > 0 then Board.Label[x][y] = -1 end
- end
-
-
- function playMove (p, c) --> if p not defined -> pass
- Board.MoveNumber = Board.MoveNumber + 1
- if displayMove(Board.MoveNumber) then
- if c then
- if c == "white" then Board.LastColor = WHITE else Board.LastColor = BLACK end
- else
- if Board.LastColor == BLACK then Board.LastColor = WHITE else Board.LastColor = BLACK end
- end
- if p then
- local x, y = Point(p)
- Board[x][y] = Board.LastColor
- if writeLabel(Board.MoveNumber) then
- Board.Label[x][y] = Board.MoveNumber
- else
- testDeadStones(x, y) --> only test dead stones if you dont write label
- end
- -- here should be test for suicide move, allowed on some rules version
- end
- end
- end
-
-
- function setBoardSize (s)
- if s == "small" then
- Board.Size = 9
- Hoshi = Hoshi9
- elseif s == "medium" then
- Board.Size = 13
- Hoshi=Hoshi13
- else
- Board.Size = 19
- Hoshi = Hoshi19
- end
- setLabelBoundaries(1, 999)
- end
-
-
- function resetBoard ()
- Board.LastColor = WHITE
- Board.MoveNumber = 0
- for i=1, Board.Size do
- Board[i] = {}
- Board.Label[i] = {}
- for j=1, Board.Size do
- Board[i][j] = EMPTY
- Board.Label[i][j] = EMPTY
- end
- end
- end
-
-
- ---------------------------------------------------------
- --- Deadstone calculator
- ---------------------------------------------------------
-
- --- Stack implementation for deadstone calculator
-
- function resetStack ()
- stack = {}
- end
-
-
- function push (x, y)
- stack = {next = stack, x = x, y = y}
- end
-
-
- function pop ()
- if stack then
- local x, y = stack.x, stack.y
- stack = stack.next
- return x, y
- end
- end
-
-
- --- Deadstone calculator
-
- --- Are x, y valid coordinates?
-
- function isValid (x, y)
- if x >= 1 and x <= Board.Size and y >= 1 and y <= Board.Size then return true end
- return false
- end
-
- --- Reset shadow Goban
-
- shadowboard = {}
-
- function resetShadowBoard (size)
- for i = 1, size do
- shadowboard[i] = {}
- end
- end
-
- --- Na základě stínového gobanu odstraní kameny označené jako mrtvé ze skutečného gobanu.
-
- function removeDeadStones ()
- for i, k in pairs(shadowboard) do
- for j, v in pairs(k) do Board[i][j] = EMPTY end
- end
- end
-
- --- Test, je-li x, y prázdná.
- -- V opačném případě je-li na x, y soupeřův kámen, uloží do zásobníku jeho pozici.
-
- function isEmpty (x, y)
- if Board[x][y] == EMPTY then
- return true
- elseif Board[x][y] ~= myColor and shadowboard[x][y] ~= DEAD then
- push(x, y)
- end
- return false
- end
-
- --- Testuje, zda má kámen na pozici x, y svobodu.
- -- V případě že ne, vrací true, jinak false.
-
- function isDead (x, y)
- if isValid(x, y+1) and isEmpty(x, y+1) then return false end
- if isValid(x-1, y) and isEmpty(x-1, y) then return false end
- if isValid(x, y-1) and isEmpty(x, y-1) then return false end
- if isValid(x+1, y) and isEmpty(x+1, y) then return false end
- return true
- end
-
- --- Test for dead group.
- -- If the group with stone on (x, y) is dead, it removes it from goban.
- -- Can be used to test for suicide.
-
- function deadStones (x, y)
- resetStack()
- resetShadowBoard(Board.Size)
- while isDead(x, y) do
- shadowboard [x][y] = DEAD
- x, y = pop()
- if not x then
- removeDeadStones()
- break
- end
- end
- end
-
- --- Main entry point for deadstone calculator.
- -- For each neighbour stone it starts test for dead group.
-
- function testDeadStones (x, y)
- myColor = Board[x][y]
- if isValid(x+1, y) and Board[x+1][y] ~= EMPTY and Board[x+1][y] ~= myColor then deadStones(x+1, y) end
- if isValid(x, y+1) and Board[x][y+1] ~= EMPTY and Board[x][y+1] ~= myColor then deadStones(x, y+1) end
- if isValid(x-1, y) and Board[x-1][y] ~= EMPTY and Board[x-1][y] ~= myColor then deadStones(x-1, y) end
- if isValid(x, y-1) and Board[x][y-1] ~= EMPTY and Board[x][y-1] ~= myColor then deadStones(x, y-1) end
- end
-
-
- ---------------------------------------------------------
- --- SGF parser
- ---------------------------------------------------------
-
- --- Very ugly looking first implementation of SGF parser mainly for testing deadstone calculator
-
-
- function blackmove (a, b, c)
- playMove(c, "black")
- return b
- end
-
-
- function whitemove (a, b, c)
- playMove(c, "white")
- return b
- end
-
-
- function blackstone (a, b, c)
- print("\\stone[black]{"..c.."}")
- return b
- end
-
-
- function whitestone (a, b, c)
- print("\\stone[white]{"..c.."}")
- return b
- end
-
-
- function emptystone (a, b, c)
- print("\\stone[empty]{"..c.."}")
- return b
- end
-
-
- function parseSGF(SGFstring)
- emptychar = (lpeg.S(" \t\r\n"))^1
- letter = lpeg.R("az", "AZ")
- number = (lpeg.R("09"))^1
- text = (letter + number + lpeg.S(" .,:;+-=_?!@#$%^&*()/"))^1
-
- axis = letter * letter
- shortparam = axis + ""
- longparam = axis * ( ":" * axis )^-1
-
- FF = lpeg.P("FF[4]") * emptychar^0
- GM = lpeg.P("GM[1]") * emptychar^0
- SZ = lpeg.P("SZ[") * number * lpeg.P("]") * emptychar^0
- DT = lpeg.P("DT[") * text * lpeg.P("]") * emptychar^0
- EV = lpeg.P("EV[") * text * lpeg.P("]") * emptychar^0
- PB = lpeg.P("PB[") * text * lpeg.P("]") * emptychar^0
- PW = lpeg.P("PW[") * text * lpeg.P("]") * emptychar^0
- BR = lpeg.P("BR[") * text * lpeg.P("]") * emptychar^0
- WR = lpeg.P("WR[") * text * lpeg.P("]") * emptychar^0
- KM = lpeg.P("KM[") * text * lpeg.P("]") * emptychar^0
- RE = lpeg.P("RE[") * text * lpeg.P("]") * emptychar^0
- CA = lpeg.P("CA[") * text * lpeg.P("]") * emptychar^0
- AP = lpeg.P("AP[") * text * lpeg.P("]") * emptychar^0
- DT = lpeg.P("DT[") * text * lpeg.P("]") * emptychar^0
-
-
-
- B = lpeg.P("B[") * lpeg.Cmt(shortparam, blackmove) * lpeg.P("]") * emptychar^0
- W = lpeg.P("W[") * lpeg.Cmt(shortparam, whitemove) * lpeg.P("]") * emptychar^0
-
- rootproperty = FF + GM + SZ + DT + EV + PB + PW + BR + WR + KM + RE + CA + AP + DT
- property = B + W
-
- rootnode = lpeg.P(";") * (rootproperty)^1
- node = lpeg.P(";") * property
-
- sequence = rootnode^0 * node^1
-
- gameTree = lpeg.P("(") * sequence^1 * lpeg.P(")")
-
- -- tex.sprint("SGFparse: " .. SGFstring)
- -- tex.sprint("::")
- -- tex.sprint()
-
- resetBoard ()
- if not lpeg.match(gameTree, SGFstring) then
- tex.sprint("Invalid SGF file")
- end
-
- end
-
-
- \stopluacode
-
- \def\move#1%
- {\ctxlua{playMove("#1")}}
-
- %\def\move
- % {\dosingleargument\domove}
-
- %\def\domove[#1]{#2}
- % {\iffirstargument
- % \ctxlua{playMove("#2", "#1")}
- % \else
- % \ctxlua{playMove("#2")}
- % \fi}
-
- \def\pass
- {\ctxlua{playMove()}}
-
- \def\stone[#1]#2%
- {\ctxlua{setStone("#2", "#1")}}
-
- \def\marker#1%
- {\ctxlua{setMarker("#1")}}
-
- \def\newboard
- {\dosingleargument\donewboard}
-
- \def\donewboard[#1]%
- {\iffirstargument
- \ctxlua{setBoardSize("#1")}
- \else
- \ctxlua{setBoardSize("big")}
- \fi}
-
- \def\resetnumbering
- {\ctxlua{resetBoard()}}
-
- \def\drawboard
- {\dosingleargument\dodrawboard}
-
- \def\dodrawboard[#1]%
- {\iffirstargument
- \ctxlua{displayBoard(0, "#1")}
- \else
- \ctxlua{displayBoard(0, "medium")}
- \fi}
-
- \def\drawpartialboard#1#2%
- {\ctxlua{displayBoard(0, "medium", "#1", "#2")}}
-
- \def\parse#1%
- {\ctxlua{parseSGF("#1")}}
-
- \def\position
- {\dosingleargument\doposition}
-
- \def\doposition[#1]%
- {\iffirstargument
- \ctxlua{setMoveBoundaries(1, #1); parseSGF(Game)}
- \else
- {\ctxlua{parseSGF(Game)}}
- \fi}
-
- \def\labels#1#2%
- {\ctxlua{setLabelBoundaries(#1, #2)}}
-
-
- \starttext
-
-
- \newboard
-
- \position[40]
- \drawboard
-
- \labels{41}{999}
- \position[100]
- \drawboard[small]
-
- \labels{101}{999}
- \position[999]
- \drawboard[big]
-
- \labels{999}{999}
- \position{999}
- \drawboard
-
- The annual bilateral Tengen championship is back. This year, Park Junghwan Chunwon (Korean for Tengen) meet Chen Yaoye Tianyuan (Chinese for Tengen). This tournament is sponsored by Sports Korea newspaper and Xinmin Wanbo evening paper.
-
- Chen Yaoye of China opened the first game by an early 165 moves resignation game. Chen who played black in the first game ended the game by cutting Park's group. The cut will lead to a favorable ko fight for black. I'm not sure whether white group can survive here or not, but perhaps Park didn't think he'll win the fight, so he resigned.
-
- % \newboard
- % \parse{;B[pd];W[dd];B[pq];W[dp];B[fq];W[cn];B[qk];W[jp];B[dr];W[gq];B[fp];W[fr];B[er];W[gr]
- % ;B[cp];W[cq];B[bq];W[bp];B[co];W[bo];B[do];W[br];B[dq];W[cr];B[dn];W[mq];B[cm];W[bn]
- % ;B[po];W[dm];B[nc];W[fc];B[be];W[ce];B[bd];W[bf];B[cf];W[cg];B[df];W[bg];B[dg];W[dh]
- % ;B[eh];W[di];B[dc];W[cc];B[cb];W[cd];B[bc];W[db];B[ec];W[ed];B[eb];W[eg];B[ef];W[fe]
- % ;B[gd];W[fd];B[da];W[fg]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[em];W[dl];B[qe];W[fm];B[fn];W[el];B[gm];W[en]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[eo];W[ok]
- % ;B[oj];W[nj];B[pj];W[nk];B[ni];W[mi];B[mh];W[li];B[pm];W[qc];B[em]}
- % \drawboard
- % \clearnumbers
- % \parse{;W[re];B[rd];W[qd]
- % ;B[rc];W[nh];B[oi];W[pe];B[qf];W[pc];B[od];W[rf];B[rb];W[qg];B[pf];W[of];B[pg];W[ph]
- % ;B[og];W[oh];B[oe]}
- % \drawboard
- % \clearnumbers
- % \parse{;W[qi];B[ng];W[rk];B[rl];W[rj];B[ql];W[rh];B[fl];W[jd]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[lh];W[kh]
- % ;B[lf];W[ki];B[jf];W[he];B[kc];W[kd];B[jc];W[ic];B[ib];W[le];B[kg];W[lc];B[lb];W[kb]
- % ;B[jb];W[mb];B[ka];W[mc];B[ob];W[ig]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[ej];W[dj];B[fk];W[ek];B[lr];W[mr];B[iq];W[ip]
- % ;B[hp];W[jq];B[hq];W[jr];B[mo];W[or];B[pr];W[lp];B[ir];W[jg];B[me];W[fb];B[hb];W[fa]
- % ;B[ba];W[is];B[hs];W[js];B[gp];W[sl];B[sm];W[sk];B[rn];W[ps];B[qs];W[os];B[qr];W[if]
- % ;B[gi];W[md];B[mf];W[hj];B[ei];W[nm];B[jl];W[hl];B[lm];W[kl]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[km];W[jm];B[kk];W[ll]
- % ;B[ml];W[lk];B[mk];W[lj];B[mm];W[mj];B[mp];W[lo];B[nq];W[mn];B[nn];W[ln];B[lq];W[ls]
- % ;B[nr];W[ms];B[jn];W[im];B[cl];W[dk];B[ns];W[no];B[ks];W[on];B[kp];W[ko];B[in];W[hm]
- % ;B[hn];W[kn]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[hi];W[pn];B[qn];W[op];B[oq];W[pp];B[qp];W[ii]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[ih];W[gj];B[fj];W[ji]
- % ;B[sd];W[se];B[hg];W[ff];B[jo];W[kq];B[io];W[nl]}
- % \drawboard
- % \clearnumbers
- % \parse{;B[hd];W[id];B[gb];W[na];B[la];W[oa]
- % ;B[pa];W[nd];B[nb];W[ma];B[pb];W[fh];B[fi];W[ea];B[db];W[ge];B[ne];W[ld];B[pi];W[qh]
- % ;B[kr];W[kp];B[gk];W[hk];B[ds];W[cs];B[af];W[ag];B[ae];W[ga];B[ha];W[np];B[mq];W[pk]
- % ;B[qj];W[pl];B[om];W[gl];B[hh];W[jh];B[qm];W[nn];B[qo];W[hc];B[gc];W[ie];B[fm])}
- % \drawboard
- %
- Park Junghwan even the game by winning the second game by 2.5 points. The game was quite territory oriented. Black claimed the right side, while white went for the left side and aimed for the upper board. There was a big trade at move 205. White sacrificed his 7 stones (about 12 points) for black's 5 stones. The trade was even I think. However, black eventually came out ahead after the trade.
-
-
-
- \stoptext
-
- % ;FF[4];AW[gg:hh][ij][kl][op]AB[kk][gh]AB[ll]AW[oo]AE[hg];B[dd]BT[567];W[cc]WT[1234];B[];W[];B[dc];W[cd];B[ce];W[be];B[cf];W[bf];B[cg]