2014年5月13日火曜日

グループ番号表示の棋譜再生

 右の画像は、私が自作したブループ番号を表示する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 件のコメント:

コメントを投稿