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