配列変数が、0以外消えてしまいます
雷光 2013/6/10(Mon) 22:41:12|NO.54812
sdim save,2000//セーブデータ用
dim item,7//アイテム用
money=500
*back//アイテムの変数が1個目以外0になる
repeat 7
item(cnt)=str(item(cnt))
loop
svd=""+item(0)+","+item(1)+","+item(2)+","+item(3)+","+item(4)+","+item(5)+","+item(6)+""//アイテム数を入力
notesel save
noteadd svd,7,1
money=str(money)
noteadd money,1,1
notesave"save.txt"
money=int(money)
repeat 7
item(cnt)=int(item(cnt))//数値に戻す
loop
goto*main
スクリプトの一部だけ出したので分かりにくいかもしれません。
画面移動時にセーブする、というのをやろうとしていたのですが、ここを実行時に配列変数が、0番以外は中身がなくなってしまうようです。
デバッガを使ってみたところ、item変数を文字列型にしているところでなくなっているようです。
分かりにくい質問で申し訳ありませんが、分かる方がいらっしゃればお答えください。
YSR 2013/6/10(Mon) 23:11:42|NO.54815
とりあえずループとかではちゃんとインデントしような?
指摘するところとしては、
>repeat 7
>item(cnt)=str(item(cnt))
>loop
この存在意義が謎。itemは整数型(dimで宣言しているから)なのに、
いちいちstr関数で文字列にしてまた代入する意味がない。
>svd=""+item(0)+","+item(1)+","+item(2)+","+item(3)+","+item(4)+","+item(5)+","+item(6)+""//アイテム数を入力
変数名をいちいちコピペしてずらずら並べていたら面倒にもほどがあるのでfor文を使うべき。
>notesel save
>noteadd svd,7,1
>money=str(money)
>noteadd money,1,1
この辺がガチで意味不明。意図としては、
--------------------
01 money
02 item(0)
03 item(1)
04 item(2)
05 item(3)
06 item(4)
07 item(5)
08 item(6)
--------------------
といった感じで(先頭の2桁数字は行番号)、note系命令で書き込み&読み出し
したかったのだろうと思う。ただ、そっちが書いたコードだと、こういった
ことにはならない。と言うか、noteadd命令の第3引数が「1」(上書き)だから、
noteselで選択された変数saveにあらかじめ(複数行の)文字データが書かれていないと
noteaddしてもまるで意味が無い(上書きできないから)。
こういったカオスなコードになってしまったのは、
・「データをテキスト形式で保存するのには一旦文字列の形式に変数を変換しなければならない」
という誤解
・note系命令にまだ慣れていない(あまり自分で実験したことがないorサンプル読んでないから?)
というのが根底にあると思う。ちなみに、そちらが意図するように適切に書き直したのが次の通り。
(コメントは私の主観で追加させてもらった。別に無視してくれても構わない)
item_num = 7 ;アイテム数(将来の設定変更に備える)
dim item,item_num ;アイテムの情報を保存するための配列
;(何の数値データかは私には分からないが)
money = 500 ;所持金情報……かな?
;「*back」が何を意図するラベルかが分からない‥…まあそこは個人の自由だが
*back
;ファイルにセーブするルーチン
notesel save ;noteselで指定する変数は、別にsdimしなくても問題ない(HSPの仕様)
save += "" + money + "\n" ;""を足し算で先行させると、以降は文字列に変換される(HSPの仕様)
;note系命令で扱うのは要するに改行付き文字列なので、
;noteaddを使わなくても中のデータは普通に作れるのだ
repeat item_num ;別にforeach文でもいい。その場合、「foreach item」となる
save += "" + item(cnt) + "\n" ;配列を1つづつ文字列として変数saveに書き込む
loop
notesave"save.txt" ;save.txtというファイルにテキスト形式で保存
;メインルーチンに戻る……という意味でいいよね?
goto *main
なお、↑のコードに対する「ファイルからロードするルーチン」はこんな感じ。
;ファイルからロードするルーチン
notesel buf ;読み込むためのバッファ(自動で領域が確保されるため、sdimで用意する必要はない)
noteload "save.txt" ;読み込み(この段階で、bufは改行付き文字列としてデータが用意される)
noteget getline, 0 ;「0」(1行目)をgetlineに文字列として読み込む。
;ここでも「sdim getline, 200」などのように、領域を確保する必要はない
money = int(getline) ;int型に文字列を変換
repeat item_num ;配列に順に読み込んでいく
noteget getline, cnt + 1 ;「1」(2行目)から順に読み込む
item(cnt) = int(getline)
loop
test 2013/6/11(Tue) 02:06:05|NO.54819
スクリプトの改善案などはYSRさんに任せるとして、結局なぜ配列変数が0以外消えたのかをお答えします。
雷光さんがデバッガで調べたとおり、、item変数を文字列型にしているところで消えています。
実は、変数の型は決まっていて、異なる型の値を代入しようとした場合は変数が作りなおされます。
ふつうの変数の場合は
a=3 ;数値を代入
a="foo" ;文字列を代入
a=5 ;また数値を代入
のように異なる値を代入できているように見えますが、これは違う型の値を代入するたびに変数を作り直していると考えられます。
配列変数でないただの変数なら、上記のようになるので大した問題にはなりませんが、配列変数の場合は問題になります。
repeat 7
item(cnt)=str(item(cnt))
loop
というコードでは、まずcntが0のときはitem(0)=str(item(0))
が実行されます。実はitem(0)はただのitemと同じ意味なので、このコードはitem=str(item(0))
と同じです。つまり、変数itemに文字列型の値を代入しているのです。
もともとitemは数値型の配列だったので、型が違うから新しく作りなおされます。
ただ文字列を代入しただけなので、配列変数ではなくなります。そのためitem(1)以降は消えてしまうのです。
恐らく雷光さんが期待した動作は「まずitem(0)が文字列になって、次にitem(1)が文字列になって、…」という動作だと思いますが、HSPではそのように、配列の一部が文字列型で残りが数値型というように型が混在することはできません。
ちなみに、その後ループが進むとcntが1〜6になりますが、item(1)以降が存在しないのにエラーが起きない理由は、代入文によって配列の自動拡張が起きているからです。
雷光 2013/6/14(Fri) 22:21:51|NO.54894
解決しました! YSRさん、testさん、ありがとうございました。