右の画像は、私が自作したブループ番号を表示するSGFファイル形式の棋譜データを再生するソフトを実行している様子だ。
画像では見にくいかもしれないが、実際には石を打つ時に点滅したり、グループになる時に若干の間があり、見やすくなっている。
ただ、勝敗は計算していないので、棋譜データの中にあるRE[ ]を見て、以下で判断するか、別の棋譜再生ソフトを利用する必要がある。ただ、日本ルールと中国ルールなどの違いがあり、勝敗は違っている場合がある。
持碁の時→"0" (zero)
黒勝ちの時→"B+何目かの数値"
白勝ちの時→"W+何目かの数値"
黒 : 林 有美
白 : 本因坊 秀策
黒: 65
白: 25
結果: 黒 40目勝ち
以下はHSP言語(http://hsp.tv/)で作成したグループ番号
表示の棋譜再生ソフトのソースコードだ。
HSP言語はBASIC言語に近いプログラム言語で、最新の
バージョンではC言語への変換やスマホでも利用できるソフトが
作成できるらしい。
私の使っているバージョンは3.32だが、標準的な命令しか
使っていないので、どのバージョンでもコンパイル、実行できる
はずだ。(古いバージョンHSP2.61では、MacOS及び、
Linux版もあるらしい)
実行ファイル(EXE形式のファイル)も作成できるのだが、
ダウンロードするようにしなければいけないのは面倒なので、ソー
スコードでの公開にした。
コンパイル、実行すると、いきなりファイルダイアログが表示
されるので、SGFファイルを選択して読み込めば、再生を開始
する。(SGFファイルはネットで検索すればいくらでも見つか
る)
なお、囲碁のハンデキャップがある場合、最初に黒石を連続で
打っていくので誤動作と間違えないように。
ストップはないのでウィンドウの「×」をクリックして終了す
るか、再生がすべて終了するとダイアログが表示されるので、そ
こでボタンを選択する。
;グループ番号表示の棋譜再生ソフト(HSP言語)
;
*soki
screen 0,600,600,0
objmode 2
font "", 15, 1
randomize
sdim buf,65000 ; テキストのバッファを確保
buf="" ; バッファをクリア
sdim handbuf,1000 ; ハンデキャップ用のバッファを確保
sdim results,32,1000
sdim zx0,2,1000
sdim zy0,2,1000
sdim zx1,2,1000
sdim zy1,2,1000
dim szx0,1000
dim szy0,1000
dim szx1,1000
dim szy1,1000
dim isi,1000
dim ax,20,20
dim ay,20,20
dim sta,20,20
dim grup0,20,20
dim grup1,20,20
gp0=1
gp1=1
color 0,0,0
repeat 19 ;碁盤の作成と座標設定、石の有無の状態を初期化
tt=cnt ;縦の座標
y=tt*30+30
repeat 19
yk=cnt ;横の座標
x=yk*30+30
ax(yk,tt)=x
ay(yk,tt)=y
sta(yk,tt)=10
if yk < 18 and tt < 18{
line x,y,x+30,y
line x+30,y,x+30,y+30
line x+30,y+30,x,y+30
line x,y+30,x,y
}
loop
loop
color 0,0,0 ;星の位置
circle ax(3,3)-5,ay(3,3)-5,ax(3,3)+5,ay(3,3)+5,1 ;[dd]
circle ax(9,3)-5,ay(9,3)-5,ax(9,3)+5,ay(9,3)+5,1 ;[jd]
circle ax(15,3)-5,ay(15,3)-5,ax(15,3)+5,ay(15,3)+5,1 ;[pd]
circle ax(3,9)-5,ay(3,9)-5,ax(3,9)+5,ay(3,9)+5,1 ;[dj]
circle ax(9,9)-5,ay(9,9)-5,ax(9,9)+5,ay(9,9)+5,1 ;[jj]
circle ax(15,9)-5,ay(15,9)-5,ax(15,9)+5,ay(15,9)+5,1 ;[pj]
circle ax(3,15)-5,ay(3,15)-5,ax(3,15)+5,ay(3,15)+5,1 ;[dp]
circle ax(9,15)-5,ay(9,15)-5,ax(9,15)+5,ay(9,15)+5,1 ;[jp]
circle ax(15,15)-5,ay(15,15)-5,ax(15,15)+5,ay(15,15)+5,1 ;[pp]
gosub *file_load ;SGFファイルのロードへ
*main
yk=0
tt=0
cng=0
sgfa=strtrim(buf,3)
handa=""
handc=""
handb=0
gocnt=0
sgfc=instr(sgfa,0,"HA[")+3 ; ハンデキャップのデータの場所を調べる
handa=strmid(sgfa,sgfc,1)
sgfc=instr(sgfa,0,"Handicap/:")+10 ; 同じくハンデキャップのデータの場所を調べる
handc=strmid(sgfa,sgfc,1)
if (handa != "") or (handc != "") {
if handa != "" {
handb=int(handa)
}
if handc != "" {
handb=int(handc)
}
handbuf=""
gosub *hanchk ; ハンデキャップの処理へ
}
if handbuf != "" {
sgfc=instr(sgfa,0,";W[") ;白石のデータの場所を調べる
size=strlen(buf)
sgfb=strmid(sgfa,sgfc,size)
sgfb=handbuf+sgfb
} else {
sgfc=instr(sgfa,0,";B[") ;黒石のデータの場所を調べる
size=strlen(buf)
sgfb=strmid(sgfa,sgfc,size)
}
split sgfb, ";", results ;区切り文字「;」を見つけ配列にする
repeat stat ;黒石と白石を別々に管理する
za=strmid(results(cnt),0,2)
if za == "B[" {
zx0(gocnt)=strmid(results(cnt),2,1)
if zx0(gocnt) != "t" {
suhen=zx0(gocnt)
gosub *suhenkan
szx0(gocnt)=int(suhen)
zy0(gocnt)=strmid(results(cnt),3,1)
suhen=zy0(gocnt)
gosub *suhenkan
szy0(gocnt)=int(suhen)
isi(gocnt)=0
gocnt++
}
}
if za == "W[" {
zx1(gocnt)=strmid(results(cnt),2,1)
if zx1(gocnt) != "t" {
suhen=zx1(gocnt)
gosub *suhenkan
szx1(gocnt)=int(suhen)
zy1(gocnt)=strmid(results(cnt),3,1)
suhen=zy1(gocnt)
gosub *suhenkan
szy1(gocnt)=int(suhen)
isi(gocnt)=1
gocnt++
}
}
loop
repeat gocnt ;棋譜データのすべてが表示されるまで繰り返す
cng=isi(cnt) ;石の判別 0;黒 1;白
redraw 0 ;画面を一旦非表示にして、ちらつき防止
*modl
if cng == 0 {
yk=szx0(cnt)-1
tt=szy0(cnt)-1
} else {
yk=szx1(cnt)-1
tt=szy1(cnt)-1
}
redraw 1 ;画面を一旦表示して石を置く時に点滅する
repeat 9
if cng == 0 {
color 0,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
}
if cng == 1 {
color 255,255,255
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
color 0,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,0
}
await 100
color 0,255,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
await 100
loop
redraw 0
if cng == 0 { ;黒石を打つ場合の表示処理
sta(yk,tt)=0
grup0(yk,tt)=gp0
color 0,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
color 255,255,255
if grup0(yk,tt) < 10 : pos ax(yk,tt)-5,ay(yk,tt)-9
if (grup0(yk,tt) > 9) and (grup0(yk,tt) < 100) : pos ax(yk,tt)-9,ay(yk,tt)-9
if grup0(yk,tt) > 99 : pos ax(yk,tt)-12,ay(yk,tt)-9
mes grup0(yk,tt)
gp0++
}else{ ;白石を打つ場合の表示処理
sta(yk,tt)=1
grup1(yk,tt)=gp1
color 255,255,255
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
color 0,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,0
if grup1(yk,tt) < 10 : pos ax(yk,tt)-5,ay(yk,tt)-9
if (grup1(yk,tt) > 9) and (grup1(yk,tt) < 100) : pos ax(yk,tt)-9,ay(yk,tt)-9
if grup1(yk,tt) > 99 : pos ax(yk,tt)-12,ay(yk,tt)-9
mes grup1(yk,tt)
gp1++
}
gosub *ana ;石が囲まれているかの判断処理
redraw 1 ;画面を表示する
await 1000 ; 全体のスピード調節
loop
dialog "棋譜再生終了"+"\n終わりますか?",2
if stat == 6 : end
if stat == 7 {
mref sokika,64
sokika=0
goto *soki
}
end
*ana ;石が囲まれているかの判断処理
repeat 19
tt=cnt
repeat 19
yk=cnt
if sta(yk,tt) == 0 { ;黒石の上下左右をチェックする
if (yk+1) <= 18 {
if sta(yk+1,tt) == 0 {
if grup0(yk,tt) < grup0(yk+1,tt) {
gra=grup0(yk,tt)
grb=grup0(yk+1,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0 ;同じ色の石があればグループ番号統一処理
yk=oldyk
tt=oldtt
}
if grup0(yk,tt) > grup0(yk+1,tt) {
gra=grup0(yk+1,tt)
grb=grup0(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
}
}
if (tt+1) <= 18 {
if sta(yk,tt+1) == 0 {
if grup0(yk,tt) < grup0(yk,tt+1) {
gra=grup0(yk,tt)
grb=grup0(yk,tt+1)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
if grup0(yk,tt) > grup0(yk,tt+1) {
gra=grup0(yk,tt+1)
grb=grup0(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
}
}
if (yk-1) >= 0 {
if sta(yk-1,tt) == 0 {
if grup0(yk,tt) < grup0(yk-1,tt) {
gra=grup0(yk,tt)
grb=grup0(yk-1,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
if grup0(yk,tt) > grup0(yk-1,tt) {
gra=grup0(yk-1,tt)
grb=grup0(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
}
}
if (tt-1) >= 0 {
if sta(yk,tt-1) == 0 {
if grup0(yk,tt) < grup0(yk,tt-1) {
gra=grup0(yk,tt)
grb=grup0(yk,tt-1)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
if grup0(yk,tt) > grup0(yk,tt-1) {
gra=grup0(yk,tt-1)
grb=grup0(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp0
yk=oldyk
tt=oldtt
}
}
}
}
if sta(yk,tt) == 1 { ;白石の上下左右をチェックする
if (yk+1) <= 18 {
if sta(yk+1,tt) == 1 {
if grup1(yk,tt) < grup1(yk+1,tt) {
gra=grup1(yk,tt)
grb=grup1(yk+1,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1 ;同じ色の石があればグループ番号統一処理
yk=oldyk
tt=oldtt
}
if grup1(yk,tt) > grup1(yk+1,tt) {
gra=grup1(yk+1,tt)
grb=grup1(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
}
}
if (tt+1) <= 18 {
if sta(yk,tt+1) == 1 {
if grup1(yk,tt) < grup1(yk,tt+1) {
gra=grup1(yk,tt)
grb=grup1(yk,tt+1)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
if grup1(yk,tt) > grup1(yk,tt+1) {
gra=grup1(yk,tt+1)
grb=grup1(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
}
}
if (yk-1) >= 0 {
if sta(yk-1,tt) == 1 {
if grup1(yk,tt) < grup1(yk-1,tt) {
gra=grup1(yk,tt)
grb=grup1(yk-1,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
if grup1(yk,tt) > grup1(yk-1,tt) {
gra=grup1(yk-1,tt)
grb=grup1(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
}
}
if (tt-1) >= 0 {
if sta(yk,tt-1) == 1 {
if grup1(yk,tt) < grup1(yk,tt-1) {
gra=grup1(yk,tt)
grb=grup1(yk,tt-1)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
if grup1(yk,tt) > grup1(yk,tt-1) {
gra=grup1(yk,tt-1)
grb=grup1(yk,tt)
oldyk=yk
oldtt=tt
gosub *anagrp1
yk=oldyk
tt=oldtt
}
}
}
}
loop
loop
if cng == 1 { ;囲んだ石を消す時の優先順位
gosub *anachk0
gosub *anachk1
} else {
gosub *anachk1
gosub *anachk0
}
return
*anachk0 ;黒石が囲まれているかのチェック
;上下左右に一つでも空きがあれば消さない
repeat gp0 ;黒石のグループを一つずつ調べる
grc0=cnt
anaflg0=0
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup0(yk,tt) == grc0 {
if (yk-1) >= 0 {
if (sta(yk-1,tt) == 10) or (sta(yk-1,tt) == 2) : anaflg0=1
}
if (yk+1) <= 18 {
if (sta(yk+1,tt) == 10) or (sta(yk+1,tt) == 2) : anaflg0=2
}
if (tt-1) >= 0 {
if (sta(yk,tt-1) == 10) or (sta(yk,tt-1) == 2) : anaflg0=3
}
if (tt+1) <= 18 {
if (sta(yk,tt+1) == 10) or (sta(yk,tt+1) == 2) : anaflg0=4
}
}
loop
loop
if (anaflg0 == 0) {
oldyk=yk
oldtt=tt
gosub *sakgrp0 ;空きがなければ削除へ
yk=oldyk
tt=oldtt
}
loop
return
*anachk1 ;白石が囲まれているかのチェック
;上下左右に一つでも空きがあれば消さない
repeat gp1 ;白石のグループを一つずつ調べる
grc1=cnt
anaflg1=0
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup1(yk,tt) == grc1 {
if (yk-1) >= 0 {
if (sta(yk-1,tt) == 10) or (sta(yk-1,tt) == 2) : anaflg1=1
}
if (yk+1) <= 18 {
if (sta(yk+1,tt) == 10) or (sta(yk+1,tt) == 2) : anaflg1=2
}
if (tt-1) >= 0 {
if (sta(yk,tt-1) == 10) or (sta(yk,tt-1) == 2) : anaflg1=3
}
if (tt+1) <= 18 {
if (sta(yk,tt+1) == 10) or (sta(yk,tt+1) == 2) : anaflg1=4
}
}
loop
loop
if (anaflg1 == 0) {
oldyk=yk
oldtt=tt
gosub *sakgrp1 ;空きがなければ削除へ
yk=oldyk
tt=oldtt
}
loop
return
*anagrp0 ;黒石のグループ番号を統一する処理
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup0(yk,tt) == grb {
grup0(yk,tt)=gra
color 150,150,150
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
color 255,255,255
if grup0(yk,tt) < 10 : pos ax(yk,tt)-5,ay(yk,tt)-9
;グループ番号の表示位置を桁数で変えている
if (grup0(yk,tt) > 9) and (grup0(yk,tt) < 100) : pos ax(yk,tt)-9,ay(yk,tt)-9
if grup0(yk,tt) > 99 : pos ax(yk,tt)-12,ay(yk,tt)-9
mes grup0(yk,tt)
}
loop
loop
return
*anagrp1 ;白石のグループ番号を統一する処理
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup1(yk,tt) == grb {
grup1(yk,tt)=gra
color 230,230,230
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
color 0,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,0
if grup1(yk,tt) < 10 : pos ax(yk,tt)-5,ay(yk,tt)-9
;グループ番号の表示位置を桁数で変えている
if (grup1(yk,tt) > 9) and (grup1(yk,tt) < 100) : pos ax(yk,tt)-9,ay(yk,tt)-9
if grup1(yk,tt) > 99 : pos ax(yk,tt)-12,ay(yk,tt)-9
mes grup1(yk,tt)
}
loop
loop
return
*sakgrp0 ;黒石の削除処理
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup0(yk,tt) == grc0 {
sta(yk,tt)=10
grup0(yk,tt)=0
color 255,0,0
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
}
loop
loop
return
*sakgrp1 ;白石の削除処理
repeat 19
tt=cnt
repeat 19
yk=cnt
if grup1(yk,tt) == grc1 {
sta(yk,tt)=10
grup1(yk,tt)=0
color 0,0,255
circle ax(yk,tt)-15,ay(yk,tt)-15,ax(yk,tt)+15,ay(yk,tt)+15,1
}
loop
loop
return
*file_load ;SGFファイルのロード処理
dialog "sgf",16,"テキストファイル"
if stat=0 : goto *dlcan2
notesel buf
noteload refstr ; テキストファイル読み込み
screen 1,700,500,0
objmode 2
font msmincho, 18, 0
mesbox buf,700,500,1,0 ; 最大サイズ編集許可
objprm 0,buf
gsel 0,1
return
*dlcan2
stop
*suhenkan ;SGFファイル形式の石の位置の文字を数値にする
strrep suhen,"a","1"
strrep suhen,"b","2"
strrep suhen,"c","3"
strrep suhen,"d","4"
strrep suhen,"e","5"
strrep suhen,"f","6"
strrep suhen,"g","7"
strrep suhen,"h","8"
strrep suhen,"i","9"
strrep suhen,"j","10"
strrep suhen,"k","11"
strrep suhen,"l","12"
strrep suhen,"m","13"
strrep suhen,"n","14"
strrep suhen,"o","15"
strrep suhen,"p","16"
strrep suhen,"q","17"
strrep suhen,"r","18"
strrep suhen,"s","19"
return
*hanchk ;ハンデキャップの黒石を置く数を追加する処理
if handb == 2 {
handbuf=";B[pd];B[dp]"
}
if handb == 3 {
handbuf=";B[pd];B[dp];B[pp]"
}
if handb == 4 {
handbuf=";B[pd];B[dp];B[pp];B[dd]"
}
if handb == 5 {
handbuf=";B[pd];B[dp];B[pp];B[dd];B[jj]"
}
if handb == 6 {
handbuf=";B[pd];B[dp];B[pp];B[dd];B[pj];B[dj]"
}
if handb == 7 {
handbuf=";B[pd];B[dp];B[pp];B[dd];B[pj];B[dj];B[jj]"
}
if handb == 8 {
handbuf=";B[pd];B[dp];B[pp];B[dd];B[pj];B[dj];B[jd];B[jp]"
}
if handb == 9 {
handbuf=";B[pd];B[dp];B[pp];B[dd];B[pj];B[dj];B[jd];B[jp];B[jj]"
}
return
0 件のコメント:
コメントを投稿