動物将棋 (13)
ひと区切りがついたと思っていた動物将棋ですが、正月には早いですが休みに子供と遊んでみました。それで、修正点がみつかったので書きたいと思います。
「待った」が2手戻るのは、やりにくく、1手だけ戻るように変更しました。また、遊んでいる途中で電話が掛かってきて、Luaridaが終了してしまい、将棋が途中で終わってしまいました。電話が終わった後、子供に続きがしたいと言われたのですが、「そんな機能は無い」と言うと、不満が出たので、これも追加しました。
棋譜の保存用変数
途中でソフトが終了しても、途中から始められるように、ゲーム中は常に棋譜を保存するようにプログラムを変更しました。まずは、そのために、棋譜の保存と読み込むプログラムを追加しました。
下記のグローバル変数を追加しました。棋譜を再現するとき、手順もグローバルで持っていた方が便利なので、グローバルにしました。
Tejun = 1 --先手:1, 後手:2 KifuFp = -1 --棋譜保存ファイル番号 KifuFilename = "dobutsusyogi.dat" --棋譜保存データファイル名
途中終了のチェック
動物将棋のプログラムが走ったときに、途中終了したか動かをチェックするプログラムを追加しました。dobutsusyogi.datに棋譜データが存在すれば、途中終了したと判断します。
------------------------------------------ -- 途中終了のチェック ------------------------------------------ function chkRireki() local fp,msg local ret = 0 --ファイルを開きます fp,msg = io.open( LuaridaPath.."/"..KifuFilename, "r") if( not(fp) )then return 0 end --データを読み込みます local str = fp:read("*l") --1行読み込み if( str==nil )then ret = 0 --データが無かった else ret = 1 --データがあった end io.close(fp) return ret end
途中終了のチェックは、メインループで動物将棋開始前に、下記のような判断をします。
--途中終了のチェック ret = 0 if( chkRireki()==1 )then --途中から始めるかどうかをセットする ret = restart() end if( ret==0 )then fwriteWork( 0, 0 ) --棋譜データ保存ファイルを新規オープンする else fwriteWork( 1, 0 ) --棋譜データ保存ファイルを追記オープンする end --どうぶつしょうぎスタート winner = doTouchAction()
棋譜データを読み込んで再開する
restart()は、再開するかどうか選択させて、再開が選ばれたら、棋譜データを読み込んでセットするプログラムです。chkSenNichiTe()の戻り値に次の指し手番号も追加しました。
------------------------------------------ -- 前回の途中から始める処理 -- 0:初めから, 1:途中から ------------------------------------------ function restart() local a local ret = 0 item.clear() item.add( "はじめから", 0 ) item.add( "つづきをする", 0 ) a = item.list("とちゅうでおわっています") if( a==2 )then --棋譜データを読み込む readKifuData() --棋譜データを盤面に展開します ret, Ban, Mochi, Tejun = chkSenNichiTe( KifuN-1 ) sortMochiKoma( 1 ) sortMochiKoma( 2 ) drawAll() ret = 1 end return ret end
棋譜データを読み込むプログラムは下記です。0x0Aを改行にして、終了直前までのデータが保存されているはずなので、それを読み込みます。
------------------------------------------ -- 棋譜データを読み込む ------------------------------------------ function readKifuData() local fp,msg local ret = 0 --ファイルを開きます fp,msg = io.open( LuaridaPath.."/"..KifuFilename, "r") --データを読み込みます KifuN = 1 while(true)do local str = fp:read("*l") --1行読み込み if( str==nil )then break end --読込むデータが無ければ終了 str = string.gsub( str,"\r","" ) --改行コードを外す if( str=="" )then break end Kifu[KifuN] = tonumber(str) KifuN = KifuN + 1 end io.close(fp) end
棋譜の保存
棋譜のファイル書き込みは、1つの関数にまとめました。
- 0: ファイル新規オープン
- 1: ファイル追記オープン
- 2: ファイルクローズ
- 3: ファイルデータクリア
- 4: データ書き込み
- 5: Kifu[]を保存しなおしてfclose()しない
fwriteWork()は、これら5つの処理をします。0は新規にゲームを始めるときにオープンします。1は途中からゲームを再開するときに、追記オープンします。2はファイルを閉じるときに使います。今は未使用です。3は勝負が終了したときに、ファイルをクリアします。4は1手を書き込む処理を行います。5は「待った」が入ったときに、棋譜保存データを1手戻すための処理をします。
------------------------------------------ -- 棋譜データ保存の処理を行う -- 0:ファイル新規オープン, 1:ファイル追記オープン -- 2:ファイルクローズ, 3:ファイルデータクリア, 4:データ書き込み -- 5:Kifu[]を保存しなおしてfclose()しない ------------------------------------------ function fwriteWork( flg, kdata ) if( flg==0 or flg==1)then if( KifuFp~=-1 )then io.close(KifuFp) end if( flg==0 )then --ファイル新規オープン KifuFp = io.open(LuaridaPath.."/"..KifuFilename,"w+") KifuFp:write( tostring(Kifu[1]).."\n" ) io.flush() else KifuFp = io.open(LuaridaPath.."/"..KifuFilename,"a+") end if( not(KifuFp) )then --ファイル追記オープン dialog( LuaridaPath.."/"..KifuFilename.."がオープンできません","プログラムを終了して下さい", 0 ) end elseif( flg==2 )then --ファイルクローズ if( KifuFp~=-1 )then io.close(KifuFp) end KifuFp = -1 elseif( flg==3 )then --ファイルデータクリア if( KifuFp~=-1 )then io.close(KifuFp) end KifuFp = io.open(LuaridaPath.."/"..KifuFilename,"w+") if( not(KifuFp) )then dialog( LuaridaPath.."/"..KifuFilename.."がオープンできません","プログラムを終了して下さい", 0 ) else io.close(KifuFp) KifuFp = -1 end elseif( flg==4 )then --一手保存する KifuFp:write( tostring(kdata).."\n" ) io.flush() elseif( flg==5 )then --棋譜データをまとめて保存する if( KifuFp~=-1 )then io.close(KifuFp) end KifuFp = io.open(LuaridaPath.."/"..KifuFilename,"w+") if( not(KifuFp) )then dialog( LuaridaPath.."/"..KifuFilename.."がオープンできません","プログラムを終了して下さい", 0 ) else local i for i=1,KifuN-1 do KifuFp:write( tostring(Kifu[i]).."\n" ) end io.flush() end end end
変更箇所
待ったの処理にfwriteWork( 5 )を追加しました。さらに、chkSenNichiTe()がTejunも返すようにしたので、戻り値にTejunを追加しました。そして、いままで2手戻していたのを1手に変更しました。
--まったの処理 if( KifuN>2 )then n = KifuN - 2 ret, Ban, Mochi, Tejun = chkSenNichiTe( n ) sortMochiKoma( 1 ) sortMochiKoma( 2 ) KifuN = KifuN - 1 --棋譜データの処理 fwriteWork( 5 ) drawAll() msgDisp( "まった・・・" ) end
持ち駒を打つプログラムに、棋譜を保存するfwriteWork( 4, Kifu[KifuN] )を追加しました。
--持ち駒を打った if(koma1==0)then --空マスに打った soundNaruUtu = 2 --打てたので、持ち駒を削除します delMochiKoma( Tejun, hx ) Ban[hx1][hy1] = koma --棋譜の保存 Kifu[KifuN] = (koma+50)*100 + hx1*10 + hy1 fwriteWork( 4, Kifu[KifuN] ) --ファイルへのデータ書き込み KifuN = KifuN + 1 KifuText( Tejun, hx1, hy1, koma ) Tejun = 3 - Tejun --手順を入れ替える end
盤上の駒を動かした処理にも、fwriteWork( 4, Kifu[KifuN] )を追加しました。
--盤上の駒を動かした if( koma==11 and hy1==1 )then --ひよこの場合 --最前列ではにわとりになる koma = 12 soundNaruUtu = 1 elseif( koma==21 and hy1==4 )then --ひよこの場合 --最前列ではにわとりになる koma = 22 soundNaruUtu = 1 else soundNaruUtu = 3 end --Ban[hx1][hy1]に駒がある場合は、自分の持ち駒となる if( Ban[hx1][hy1]~=0 )then --持ち駒に追加します addMochiKoma( Tejun, Ban[hx1][hy1] ) end Ban[hx][hy] = 0 Ban[hx1][hy1] = koma --棋譜の保存 Kifu[KifuN] = hx*1000 + hy*100 + hx1*10 + hy1 fwriteWork( 4, Kifu[KifuN] ) --ファイルへのデータ書き込み KifuN = KifuN + 1 KifuText( Tejun, hx1, hy1, koma ) Tejun = 3 - Tejun --手順を入れ替える
また、Tejunは全てグローバル変数に書き換えています。