HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
0101
YSR9パズルを解かせてみたいんだが・・・4未解決


YSR

リンク

2011/1/1(Sat) 11:45:47|NO.36476

9パズルを入手したので、試しにHSPに解かせようとしたら、
「スタック領域のオーバーフローです」と表示される。・・・何で?
一応ソースコードを。

;HSPで9パズルを解く ;初期状態(0は空白): ;120 ;345 ;678 ;→"120345678" ;314 ;207 ;658 ;→"314207658" ; size=3 lastanswer="120345678" #module #defcfunc solve str a,str b sdim tmp,9 sdim move,1024 dim num,size@*size@ board=a move=b if board!lastanswer@ { for k,0,size@*size@ num(k)=int(strmid(board,k,1)) next for k,0,size@*size@ if num(k)=0 { ;空白を上に if k>2 { w=num(k-3) num(k-3)=0 num(k)=w tmp="" for j,0,size@*size@ tmp+=str(num(j)) next move+="0" move=solve(tmp,move) w=num(k) num(k)=0 num(k-3)=w } ;空白を右に if k\3!2 { w=num(k+1) num(k+1)=0 num(k)=w tmp="" for j,0,size@*size@ tmp+=str(num(j)) next move+="1" move=solve(tmp,move) w=num(k) num(k)=0 num(k+1)=w } ;空白を下に if k<6 { w=num(k+3) num(k+3)=0 num(k)=w tmp="" for j,0,size@*size@ tmp+=str(num(j)) next move+="2" move=solve(tmp,move) w=num(k) num(k)=0 num(k+3)=w } ;空白を左に if k\3!0 { w=num(k-1) num(k-1)=0 num(k)=w tmp="" for j,0,size@*size@ tmp+=str(num(j)) next move+="3" move=solve(tmp,move) w=num(k) num(k)=0 num(k-1)=w } } next } return move #global sdim answer,1024 answer=solve("314207658","") mes answer stop



この記事に返信する


info

リンク

2011/1/1(Sat) 23:43:51|NO.36495


#module #deffunc func i++ title "現在のネスト"+i func return #global func
ネストを処理するためのスタック領域の限界を超えています。
hsp ではメモリの確保のしすぎによる、
クラッシュを防ぐために、スタック領域の限界を定めているみたいです。

おかげで上の様な無謀なスクリプトも実害が無く実行することが出来ます。

もし、スクリプトのどこが悪いかを聞いているのなら、
自分はお手上げですので、誰か他の人に聞いてください。



とおりすがりA

リンク

2011/1/2(Sun) 09:29:46|NO.36499

上の回答に補足をば。
デバッグに関してはエラー時のダイアログだけでなくDebug Windowの利用をお勧めします。
YSRさんのプログラムリストを実行してみると"sublev"の項が128と表示されますが、HSPではネストレベルが128を超えるとエラーになってしまいます。
じっくりと見ていないのに憶測でものを言うのもなんですが、余計なfor文によって必要以上に再帰呼び出しが行われている気がします。

再帰処理に関しては実装する前に紙と鉛筆で設計し、全体像をしっかり把握しておくと良いでしょう。



たんす

リンク

2011/1/4(Tue) 11:16:28|NO.36523

空白の位置を特定したら再帰呼び出しをするようなので、関数が終了せず
「ネストレベルが128を超えました」というエラーになっているのでは無いでしょうか。

再帰呼び出しをしない処理フローの検討が必要かと思います。



玄冬

リンク

2011/1/5(Wed) 12:46:37|NO.36532

これはそれ以前に条件分岐がおかしいです。
[;空白を上に]以下のif節で「0が2段目にあったら0を1段目に移す」
[;空白を下に]以下のif節で「0が1段目にあったら0を2段目に移す」
という処理をしているので、結果

347
210
658



340
217
658

を永久的に繰り返しています。(実際デバッグwindowでモジュール変数moveを見れば途中から02020…となっています)
このままでは、再帰しないようにしても無限ループになるので、
条件分岐の再考が必要です。(むしろ再帰だとオーバーフローで自動で止まる分、再帰にしてて正解だったかも。)

wikipediaによれば3*3のこの手のパズルは31手以内に必ず解けるそうなので、
無駄な動きをしないアルゴリズムを組めば再帰でもオーバーフローしないかも…

move=bの次行に
mes strmid(board,0,3)+"\n"+strmid(board,3,3)+"\n"+strmid(board,6,3)
wait 200 cls
の3行を追加してみてはいかがでしょう?
プログラムがパズルを解く途中経過が見えるので、
無駄な動きがあればすぐにわかります。



ONION software Copyright 1997-2023(c) All rights reserved.