コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

動物将棋 (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は全てグローバル変数に書き換えています。