PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/baduk-lua.tex

http://tex-baduk.googlecode.com/
LaTeX | 570 lines | 373 code | 135 blank | 62 comment | 0 complexity | a252292a2c798479898157dc15a3e982 MD5 | raw file
  1. \writestatus{loading}{Go/WeiQi/Baduk Lua module}
  2. \startluacode
  3. Game = [[
  4. (;CA[Windows-1252]SZ[19]AP[MultiGo:4.4.4]EV[14th ch-kr Tengen, game 1]DT[2010-07-11]
  5. PB[Chen Yaoye]BR[9p]PW[Park Junghwan]WR[8p]KM[6.5]RE[B+R]
  6. ;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]
  7. ;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]
  8. ;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]
  9. ;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]
  10. ;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]
  11. ;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]
  12. ;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]
  13. ;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]
  14. ;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]
  15. ;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]
  16. ;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]
  17. ;B[jj];W[dg];B[df];W[kj];B[gm];W[kn];B[hn];W[jm];B[lm];W[ik];B[jn])
  18. ]]
  19. EMPTY = 0
  20. BLACK = 1
  21. WHITE = 2
  22. ONSTACK = 4
  23. DEAD = 5
  24. Status = {FirstMove = 1, LastMove = 999, FirstMoveLabel = 1, LastMoveLabel = 999}
  25. function displayMove (num)
  26. if num < Status.FirstMove or num > Status.LastMove then return false else return true end
  27. end
  28. function writeLabel (num)
  29. if num < Status.FirstMoveLabel or num > Status.LastMoveLabel then return false else return true end
  30. end
  31. function setLabelBoundaries (start, stop)
  32. Status.FirstMoveLabel = start
  33. Status.LastMoveLabel = stop
  34. end
  35. function setMoveBoundaries (start, stop)
  36. Status.FirstMove = start
  37. Status.LastMove = stop
  38. end
  39. Board = { Size = 19, LastColor = WHITE, MoveNumber = 0, Label = {}; {}}
  40. Big = { Board = 15, Grid = 0.7, Stone = 14.5, Label = 0.9 } --> Big sized goban
  41. Medium = { Board = 12, Grid = 0.5, Stone = 11.5, Label = 0.7 } --> Medium sized goban
  42. Small = { Board = 10, Grid = 0.4, Stone = 9.5, Label = 0.55 } --> Small sized goban
  43. Unit = Big
  44. 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}}
  45. Hoshi13 = {{x=4, y=4}, {x=4, y=10}, {x=10, y=4}, {x=10, y=10}, {x=7, y=7}}
  46. Hoshi9 = {{x=3, y=3}, {x=3, y=7}, {x=7, y=3}, {x=7, y=7}, {x=5, y=5}}
  47. Hoshi = Hoshi19
  48. ---------------------------------------------------------
  49. --- TeX (MetaPost) drawing functions
  50. ---------------------------------------------------------
  51. function stone (x, y, c) --> x, y: number; c: string (color: white or black)
  52. tex.sprint("fill fullcircle scaled " .. Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withcolor " .. c .. " ;")
  53. tex.sprint("draw fullcircle scaled " .. Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withcolor black ;")
  54. end
  55. function circleMarker (x, y, c)
  56. tex.sprint("draw fullcircle scaled " .. 0.6*Unit.Stone .. " shifted (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withpen pencircle scaled (" .. 2*Unit.Grid .. ") withcolor " .. c .. " ;")
  57. end
  58. function label (l, x, y, c)
  59. tex.sprint("label(textext(\"\\color[" .. c .. "]{\\bf\\ssxx " .. l .. "}\"),(" .. x*Unit.Board .. ',' .. y*-Unit.Board .. ')) ;')
  60. end
  61. function drawGoban ()
  62. for i=1, Board.Size do
  63. tex.sprint("draw (" .. Unit.Board .. "," .. i*-Unit.Board .. ") -- (" .. Board.Size*Unit.Board .. "," .. i*-Unit.Board .. ") withpen pencircle scaled " .. Unit.Grid .. " ;")
  64. tex.sprint("draw (" .. i*Unit.Board .. "," .. -Unit.Board .. ") -- (" .. i*Unit.Board .. "," .. Board.Size*-Unit.Board .. ") withpen pencircle scaled " .. Unit.Grid .. " ;")
  65. end
  66. 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 .. ") ;")
  67. for i=1, #Hoshi do
  68. x = Hoshi[i].x; y = Hoshi[i].y
  69. tex.sprint("drawdot (" .. x*Unit.Board .. "," .. y*-Unit.Board .. ") withpen pencircle scaled (" .. 5*Unit.Grid .. ") ;")
  70. end
  71. end
  72. function drawStones ()
  73. for i=1, Board.Size do
  74. for j=1, Board.Size do
  75. if Board[i][j] == BLACK then stone(i, j, "black") elseif Board[i][j] == WHITE then stone(i, j, "white") end
  76. if Board.Label[i][j] > 0 then
  77. if Board[i][j] == BLACK then
  78. label(Board.Label[i][j], i, j, "white")
  79. elseif Board[i][j] == WHITE then
  80. label(Board.Label[i][j], i, j, "black")
  81. end
  82. elseif Board.Label[i][j] < 0 then
  83. if Board[i][j] == BLACK then circleMarker(i, j, "white") else circleMarker(i, j, "black") end
  84. end
  85. end
  86. end
  87. end
  88. function displayBoard (name, size, p1, p2)
  89. if size == "small" then
  90. Unit = Small
  91. elseif size == "medium" then
  92. Unit = Medium
  93. else
  94. Unit = Big
  95. end
  96. tex.sprint("\\startuseMPgraphic{" .. name .. "}{}")
  97. tex.sprint("path p ;")
  98. drawGoban()
  99. drawStones()
  100. if p1 then
  101. local x1, y1 = Point(p1)
  102. local x2, y2 = Point(p2)
  103. 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 ;")
  104. tex.sprint("clip currentpicture to p shifted (" .. Unit.Board/2 .. "," .. -Unit.Board/2 .. ") ;")
  105. end
  106. tex.sprint("\\stopuseMPgraphic")
  107. tex.sprint("\\useMPgraphic{" .. name .. "}")
  108. end
  109. function setStone (p, c) --> c = "black", "white" or "empty" (AB, AW, AE)
  110. local x, y = Point(p)
  111. if c == "black" then
  112. Board[x][y] = BLACK
  113. elseif c == "white" then
  114. Board[x][y] = WHITE
  115. elseif c == "empty" then
  116. Board[x][y] = EMPTY
  117. end
  118. end
  119. function Point (p)
  120. local x, y = 0, 0
  121. local l = "abcdefghijklmnopqrstuvwxyz"
  122. x = string.find(l, string.sub(p, 1, 1))
  123. y = string.find(l, string.sub(p, 2, 2))
  124. return x, y
  125. end
  126. function setMarker (p)
  127. local x, y = Point(p)
  128. if Board[x][y] > 0 then Board.Label[x][y] = -1 end
  129. end
  130. function playMove (p, c) --> if p not defined -> pass
  131. Board.MoveNumber = Board.MoveNumber + 1
  132. if displayMove(Board.MoveNumber) then
  133. if c then
  134. if c == "white" then Board.LastColor = WHITE else Board.LastColor = BLACK end
  135. else
  136. if Board.LastColor == BLACK then Board.LastColor = WHITE else Board.LastColor = BLACK end
  137. end
  138. if p then
  139. local x, y = Point(p)
  140. Board[x][y] = Board.LastColor
  141. if writeLabel(Board.MoveNumber) then
  142. Board.Label[x][y] = Board.MoveNumber
  143. else
  144. testDeadStones(x, y) --> only test dead stones if you dont write label
  145. end
  146. -- here should be test for suicide move, allowed on some rules version
  147. end
  148. end
  149. end
  150. function setBoardSize (s)
  151. if s == "small" then
  152. Board.Size = 9
  153. Hoshi = Hoshi9
  154. elseif s == "medium" then
  155. Board.Size = 13
  156. Hoshi=Hoshi13
  157. else
  158. Board.Size = 19
  159. Hoshi = Hoshi19
  160. end
  161. setLabelBoundaries(1, 999)
  162. end
  163. function resetBoard ()
  164. Board.LastColor = WHITE
  165. Board.MoveNumber = 0
  166. for i=1, Board.Size do
  167. Board[i] = {}
  168. Board.Label[i] = {}
  169. for j=1, Board.Size do
  170. Board[i][j] = EMPTY
  171. Board.Label[i][j] = EMPTY
  172. end
  173. end
  174. end
  175. ---------------------------------------------------------
  176. --- Deadstone calculator
  177. ---------------------------------------------------------
  178. --- Stack implementation for deadstone calculator
  179. function resetStack ()
  180. stack = {}
  181. end
  182. function push (x, y)
  183. stack = {next = stack, x = x, y = y}
  184. end
  185. function pop ()
  186. if stack then
  187. local x, y = stack.x, stack.y
  188. stack = stack.next
  189. return x, y
  190. end
  191. end
  192. --- Deadstone calculator
  193. --- Are x, y valid coordinates?
  194. function isValid (x, y)
  195. if x >= 1 and x <= Board.Size and y >= 1 and y <= Board.Size then return true end
  196. return false
  197. end
  198. --- Reset shadow Goban
  199. shadowboard = {}
  200. function resetShadowBoard (size)
  201. for i = 1, size do
  202. shadowboard[i] = {}
  203. end
  204. end
  205. --- Na základě stínového gobanu odstraní kameny označené jako mrtvé ze skutečného gobanu.
  206. function removeDeadStones ()
  207. for i, k in pairs(shadowboard) do
  208. for j, v in pairs(k) do Board[i][j] = EMPTY end
  209. end
  210. end
  211. --- Test, je-li x, y prázdná.
  212. -- V opačném případě je-li na x, y soupeřův kámen, uloží do zásobníku jeho pozici.
  213. function isEmpty (x, y)
  214. if Board[x][y] == EMPTY then
  215. return true
  216. elseif Board[x][y] ~= myColor and shadowboard[x][y] ~= DEAD then
  217. push(x, y)
  218. end
  219. return false
  220. end
  221. --- Testuje, zda kámen na pozici x, y svobodu.
  222. -- V případě že ne, vrací true, jinak false.
  223. function isDead (x, y)
  224. if isValid(x, y+1) and isEmpty(x, y+1) then return false end
  225. if isValid(x-1, y) and isEmpty(x-1, y) then return false end
  226. if isValid(x, y-1) and isEmpty(x, y-1) then return false end
  227. if isValid(x+1, y) and isEmpty(x+1, y) then return false end
  228. return true
  229. end
  230. --- Test for dead group.
  231. -- If the group with stone on (x, y) is dead, it removes it from goban.
  232. -- Can be used to test for suicide.
  233. function deadStones (x, y)
  234. resetStack()
  235. resetShadowBoard(Board.Size)
  236. while isDead(x, y) do
  237. shadowboard [x][y] = DEAD
  238. x, y = pop()
  239. if not x then
  240. removeDeadStones()
  241. break
  242. end
  243. end
  244. end
  245. --- Main entry point for deadstone calculator.
  246. -- For each neighbour stone it starts test for dead group.
  247. function testDeadStones (x, y)
  248. myColor = Board[x][y]
  249. if isValid(x+1, y) and Board[x+1][y] ~= EMPTY and Board[x+1][y] ~= myColor then deadStones(x+1, y) end
  250. if isValid(x, y+1) and Board[x][y+1] ~= EMPTY and Board[x][y+1] ~= myColor then deadStones(x, y+1) end
  251. if isValid(x-1, y) and Board[x-1][y] ~= EMPTY and Board[x-1][y] ~= myColor then deadStones(x-1, y) end
  252. if isValid(x, y-1) and Board[x][y-1] ~= EMPTY and Board[x][y-1] ~= myColor then deadStones(x, y-1) end
  253. end
  254. ---------------------------------------------------------
  255. --- SGF parser
  256. ---------------------------------------------------------
  257. --- Very ugly looking first implementation of SGF parser mainly for testing deadstone calculator
  258. function blackmove (a, b, c)
  259. playMove(c, "black")
  260. return b
  261. end
  262. function whitemove (a, b, c)
  263. playMove(c, "white")
  264. return b
  265. end
  266. function blackstone (a, b, c)
  267. print("\\stone[black]{"..c.."}")
  268. return b
  269. end
  270. function whitestone (a, b, c)
  271. print("\\stone[white]{"..c.."}")
  272. return b
  273. end
  274. function emptystone (a, b, c)
  275. print("\\stone[empty]{"..c.."}")
  276. return b
  277. end
  278. function parseSGF(SGFstring)
  279. emptychar = (lpeg.S(" \t\r\n"))^1
  280. letter = lpeg.R("az", "AZ")
  281. number = (lpeg.R("09"))^1
  282. text = (letter + number + lpeg.S(" .,:;+-=_?!@#$%^&*()/"))^1
  283. axis = letter * letter
  284. shortparam = axis + ""
  285. longparam = axis * ( ":" * axis )^-1
  286. FF = lpeg.P("FF[4]") * emptychar^0
  287. GM = lpeg.P("GM[1]") * emptychar^0
  288. SZ = lpeg.P("SZ[") * number * lpeg.P("]") * emptychar^0
  289. DT = lpeg.P("DT[") * text * lpeg.P("]") * emptychar^0
  290. EV = lpeg.P("EV[") * text * lpeg.P("]") * emptychar^0
  291. PB = lpeg.P("PB[") * text * lpeg.P("]") * emptychar^0
  292. PW = lpeg.P("PW[") * text * lpeg.P("]") * emptychar^0
  293. BR = lpeg.P("BR[") * text * lpeg.P("]") * emptychar^0
  294. WR = lpeg.P("WR[") * text * lpeg.P("]") * emptychar^0
  295. KM = lpeg.P("KM[") * text * lpeg.P("]") * emptychar^0
  296. RE = lpeg.P("RE[") * text * lpeg.P("]") * emptychar^0
  297. CA = lpeg.P("CA[") * text * lpeg.P("]") * emptychar^0
  298. AP = lpeg.P("AP[") * text * lpeg.P("]") * emptychar^0
  299. DT = lpeg.P("DT[") * text * lpeg.P("]") * emptychar^0
  300. B = lpeg.P("B[") * lpeg.Cmt(shortparam, blackmove) * lpeg.P("]") * emptychar^0
  301. W = lpeg.P("W[") * lpeg.Cmt(shortparam, whitemove) * lpeg.P("]") * emptychar^0
  302. rootproperty = FF + GM + SZ + DT + EV + PB + PW + BR + WR + KM + RE + CA + AP + DT
  303. property = B + W
  304. rootnode = lpeg.P(";") * (rootproperty)^1
  305. node = lpeg.P(";") * property
  306. sequence = rootnode^0 * node^1
  307. gameTree = lpeg.P("(") * sequence^1 * lpeg.P(")")
  308. -- tex.sprint("SGFparse: " .. SGFstring)
  309. -- tex.sprint("::")
  310. -- tex.sprint()
  311. resetBoard ()
  312. if not lpeg.match(gameTree, SGFstring) then
  313. tex.sprint("Invalid SGF file")
  314. end
  315. end
  316. \stopluacode
  317. \def\move#1%
  318. {\ctxlua{playMove("#1")}}
  319. %\def\move
  320. % {\dosingleargument\domove}
  321. %\def\domove[#1]{#2}
  322. % {\iffirstargument
  323. % \ctxlua{playMove("#2", "#1")}
  324. % \else
  325. % \ctxlua{playMove("#2")}
  326. % \fi}
  327. \def\pass
  328. {\ctxlua{playMove()}}
  329. \def\stone[#1]#2%
  330. {\ctxlua{setStone("#2", "#1")}}
  331. \def\marker#1%
  332. {\ctxlua{setMarker("#1")}}
  333. \def\newboard
  334. {\dosingleargument\donewboard}
  335. \def\donewboard[#1]%
  336. {\iffirstargument
  337. \ctxlua{setBoardSize("#1")}
  338. \else
  339. \ctxlua{setBoardSize("big")}
  340. \fi}
  341. \def\resetnumbering
  342. {\ctxlua{resetBoard()}}
  343. \def\drawboard
  344. {\dosingleargument\dodrawboard}
  345. \def\dodrawboard[#1]%
  346. {\iffirstargument
  347. \ctxlua{displayBoard(0, "#1")}
  348. \else
  349. \ctxlua{displayBoard(0, "medium")}
  350. \fi}
  351. \def\drawpartialboard#1#2%
  352. {\ctxlua{displayBoard(0, "medium", "#1", "#2")}}
  353. \def\parse#1%
  354. {\ctxlua{parseSGF("#1")}}
  355. \def\position
  356. {\dosingleargument\doposition}
  357. \def\doposition[#1]%
  358. {\iffirstargument
  359. \ctxlua{setMoveBoundaries(1, #1); parseSGF(Game)}
  360. \else
  361. {\ctxlua{parseSGF(Game)}}
  362. \fi}
  363. \def\labels#1#2%
  364. {\ctxlua{setLabelBoundaries(#1, #2)}}
  365. \starttext
  366. \newboard
  367. \position[40]
  368. \drawboard
  369. \labels{41}{999}
  370. \position[100]
  371. \drawboard[small]
  372. \labels{101}{999}
  373. \position[999]
  374. \drawboard[big]
  375. \labels{999}{999}
  376. \position{999}
  377. \drawboard
  378. 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.
  379. 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.
  380. % \newboard
  381. % \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]
  382. % ;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]
  383. % ;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]
  384. % ;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]
  385. % ;B[gd];W[fd];B[da];W[fg]}
  386. % \drawboard
  387. % \clearnumbers
  388. % \parse{;B[em];W[dl];B[qe];W[fm];B[fn];W[el];B[gm];W[en]}
  389. % \drawboard
  390. % \clearnumbers
  391. % \parse{;B[eo];W[ok]
  392. % ;B[oj];W[nj];B[pj];W[nk];B[ni];W[mi];B[mh];W[li];B[pm];W[qc];B[em]}
  393. % \drawboard
  394. % \clearnumbers
  395. % \parse{;W[re];B[rd];W[qd]
  396. % ;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]
  397. % ;B[og];W[oh];B[oe]}
  398. % \drawboard
  399. % \clearnumbers
  400. % \parse{;W[qi];B[ng];W[rk];B[rl];W[rj];B[ql];W[rh];B[fl];W[jd]}
  401. % \drawboard
  402. % \clearnumbers
  403. % \parse{;B[lh];W[kh]
  404. % ;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]
  405. % ;B[jb];W[mb];B[ka];W[mc];B[ob];W[ig]}
  406. % \drawboard
  407. % \clearnumbers
  408. % \parse{;B[ej];W[dj];B[fk];W[ek];B[lr];W[mr];B[iq];W[ip]
  409. % ;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]
  410. % ;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]
  411. % ;B[gi];W[md];B[mf];W[hj];B[ei];W[nm];B[jl];W[hl];B[lm];W[kl]}
  412. % \drawboard
  413. % \clearnumbers
  414. % \parse{;B[km];W[jm];B[kk];W[ll]
  415. % ;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]
  416. % ;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]
  417. % ;B[hn];W[kn]}
  418. % \drawboard
  419. % \clearnumbers
  420. % \parse{;B[hi];W[pn];B[qn];W[op];B[oq];W[pp];B[qp];W[ii]}
  421. % \drawboard
  422. % \clearnumbers
  423. % \parse{;B[ih];W[gj];B[fj];W[ji]
  424. % ;B[sd];W[se];B[hg];W[ff];B[jo];W[kq];B[io];W[nl]}
  425. % \drawboard
  426. % \clearnumbers
  427. % \parse{;B[hd];W[id];B[gb];W[na];B[la];W[oa]
  428. % ;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]
  429. % ;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]
  430. % ;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])}
  431. % \drawboard
  432. %
  433. 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.
  434. \stoptext
  435. % ;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]