投稿
僕もみんなに感化されて、ちょっと問題を考えてみました。 問題 次のプログラムは、BGに大きな木を表示するサブルーチンを作り、それを呼び出して3本の木を出そうと思いましたがなぜか1本しか表示されません。原因と対策を答えなさい。 ※プログラムリストはコメントに張ります。 答えが分かった方は「ネタバレ」で答えを書いて欲しいです。 正解した方にはそうだねで返します。 (僕以外でも誰か分かる方がそうだねを押して頂けると助かります) ※正解のパターンはいくつか考えられますが動作をしたものは全て正解にします。ただしコード修正量よりも、より良い方法に改善できた方がベストです。
7そうだね
プレイ済み
返信[1]
親投稿
これが問題のソースです!
0そうだね
プレイ済み
返信[2]
親投稿
ヒロ Mahiro0720
FORループ用の変数に、Iを2回使っていることが原因。メインルーチンでもサブルーチンでも代入されるからうまくいかない。 よって、このどちらかのIを別の変数にすればいい。ここでは、修正する数の少ないメインルーチンのIをKにしている。 でいいのだろうか
1そうだね
プレイ済み
返信[3]
親投稿
けい kei0baisoku
リソースの扱いについてはしょしんしゃなので、回答側で参加………(震え声)(´ω`) ん?命令表も見たけどなかなか分かりませんでした。結構難しいのでは? 【原因】 サブルーチン内部と呼び出し側でIの変数が被っているため。1回目のサブルーチン呼び出しで「I==3」で帰ってきて、nextで4に増えてすぐにループを抜ける。 【対策】 (1)サブルーチン内のJとIを、MY,MXなど被らない名前に変える (2)サブルーチンをユーザ定義命令に変更した上で、グローバルなIと衝突する問題を避けるために定義をプログラムの最初に持ってくる (3)2の問題をスマイルブームさんが対応するのを待ってから、サブルーチンをユーザ定義命令に変更する(´ω`)
1そうだね
プレイ済み
返信[4]
親投稿
けい kei0baisoku
>でんぺんさん スミマセン!1ヵ所誤字があったので消して投稿しなおしました!(><) 共感押してくださったのは確認しました! ・サブルーチン抜けた時点で2→3
1そうだね
プレイ済み
返信[5]
親投稿
ヒロさん、けいさん、ふたりとも正解です! 命令が多いので難しくなってしまいましたかね…。実はこの問題には色々意図があって答えも3パターン用意してましたがふたりの答えで全て出てしまいました(^^; 出先だったのでチェックが甘く誤字に気づかず共感押しちゃいました。まあ意味は合ってるので正解でいいんですが〜>けいさん あとで自分の意図を含めた解説をしますので、どんどん投稿してください!(って難しくてまた人来ない?)
0そうだね
プレイ済み
返信[6]
親投稿
KU kerorinU
メインルーチン、サブルーチンでFORのインデックスに同じ変数を使っているからですかね。
1そうだね
プレイ済み
返信[7]
親投稿
>KUさん 原因は正解です! 出来れば解決方法も書いてもらえるとさらにいい感じですー。リストじゃなくてもいいのでこれをこうしたら解決出来るみたいな。
0そうだね
プレイ済み
返信[8]
親投稿
KU kerorinU
しまった対策を書いていなかった。3つか、、、 1・メインFORループのインデックスを違う変数に変える 2・サブFORループのインデックスを違う変数に変える 3・サブルーチンの代わりにユーザー定義関数を使う でしょうか。3は試してないのでわからないが、1・2は動作確認したので合ってると思います
0そうだね
プレイ済み
返信[9]
親投稿
正解3つ書かなくてもいいんですよ〜。とりあえず僕が回答候補として3つ考えていたというだけで。回答者がどれを選ぶかなと思ったところもあったのでー。 でも全部正解ですね〜。さすがです! 実は3はバグの関係でちょっとだけ面倒なんですが大正解です。
0そうだね
プレイ済み
返信[10]
親投稿
KU kerorinU
有り難う御座います。ユーザー定義関数のバグは初めて知りました。重大度・高のバグばっかり見てて気付きませんでした。このバグは重大度高いと思うがどうなんでしょう
0そうだね
プレイ済み
返信[11]
親投稿
スー thanks_0u0
ぱっと見よくわからなかったので、考えてみました!サブルーチン内でなにをしてるのかな、って思ったら、複数チップの配置だったんですね(´ω`) ここから回答です。 不具合の原因は、ループ条件にしているIが被ってしまっていること。サブの処理のせいで、メインのNEXTで戻る際にI=4になり条件を外れてしまい、1本目しか描画されないのだと思います。 解決策は、1つ目は被っている変数名のどちらかを変更。 2つ目は木の描画のユーザ命令化。命令を手前に置けばローカル変数扱いになると思います。 3つ目はメインの条件を4など帰って来ても続く数値にし、DATA末尾に-1,-1など終了データを追加、メインループ内に IF X<0 THEN BREAK など、ループ脱出処理を入れる。 答えが3つある、って見て、無理矢理考えましたが、3つ目はなんだか酷いのでネタってことで!(´=ω=`)
1そうだね
プレイ済み
返信[12]
親投稿
>KUさん バグは結構ひどいと思うんですけどね〜。回避方法がある(面倒だけど)から重要度・高じゃないのかもしれないですが、個人的には高ですよね。 >スーさん 正解です〜。てかKUさんから正解3つの流れが…(^^; 解決策もOK! 3つめのやつは想定している回答ではありませんが確かにそれも方法としてはありますね。ただロジックも変わるので今回は想定外かな…。 それともう一つもほとんど1つめと同じというか、どっち側で対応するかで2パターンあるだけなので、ほぼ3つ正解ですね。
0そうだね
プレイ済み
返信[13]
親投稿
くろちく FoliageLamp
1つだけこれでいいのでは?というのを思い付いたので。 まず、よくわからんのでプリント文を入れてみたら 3回、読みこまれるはずの、DATAが表示され無かったです。 で、変数だと思うのですがIが2重定義?みたくなってたので。 それを解消したらとりあえず表示されました… 合ってるのかわかりませんが。
1そうだね
プレイ済み
返信[14]
親投稿
>LAMPさん 回答としては正解ですよ〜。PRINTデバッグを活用してますね〜。 詳しい解説や意図は一通り終わってから説明する予定ですが、とりあえずおめでとうございます!
1そうだね
プレイ済み
返信[15]
親投稿
pinfu ANNAININ
でんぺんさん、難しいっす! 最初の FOR TO でBGを描き始める位置を読んで、 I J がゼロなら強制的に次に行って、 また、IとJでBG表示位置をずらし、 キャラ番号を変えて・・・ エラーは出ない。 3,2から始まる分のBGはある。 Iを変えれば、表示には成功したのですが、原因は・・・?? Iが最初の GOSUB 時に、 @SPTREE内の FOR I=0 TO 2 で 2回加算され、3になった?? 故に、END??? うーん。この理解でいいのでしょうか?
0そうだね
プレイ済み
返信[16]
親投稿
けい kei0baisoku
>でんぺんさん てっきりマップ関係の仕様が原因だと思っていたので、気付くのに結構時間がかかりました(´ω`;) 皆さん、結構すんなり分かったみたいで凄いです。 変数スコープの概念が必要だから難しいかなと思っていたのですが、よく考えたらそれは関数定義した時だけの話ですね。 解答三つ………もしかして私の「スマイルブームさんの対応を待つ」案g(
0そうだね
プレイ済み
返信[17]
親投稿
>pinfuさん 対処法は正解ですー。ただ原因というか理解がちょっと間違っているかな…。まあ主だった原因はあってるんですけど、ちょっとだけ勘違いしてそうな感じがありますね。ほぼ合ってますが…。 >けいさん そもそもとして初心者にはスコープの概念がほとんどないと思うんですよね。今回はそれを意識させるという狙いも…。 具体的には解説時に色々書きます〜(^^)
0そうだね
プレイ済み
返信[18]
親投稿
けい kei0baisoku
>スーさん 三つ目の方法、今回は問題文とロジックも変わるので修正というにはちょっと大きいですが、ゲームを作る時の方法としては真面目に主流のうちの1つです。 FOR文で決まった数のループを流すと、ループ数とデータ数が一致していないとバグになるので問題が起きやすいですが、その方法ならデータの定義だけを修正すれば、読み込むプログラムは手を加えないでも正しく動きます。 何か変えたい時の修正箇所は1ヵ所で済むようにしておくと、何かと良いことが多いです(^O^)
0そうだね
プレイ済み
返信[19]
親投稿
けい kei0baisoku
なるほど、解説時にその辺も触れるのですね。 期待してます(^^) くれぐれも長くなり過ぎないようにお気をつけ下さい←
0そうだね
プレイ済み
返信[20]
親投稿
>けいさん スーさんの方法は実用的には一番利用すると思う形ですね。今回は問題の意図が違うのでそういうやり方ではないですが…。 スコープについてを直接解説するわけではないですー。ただ意識しないと今回のようなミスが発生するので、そういう面で少し…。まあそういう意味ではそんなに詳細な解説予定はないですが長さは気をつけたいですね〜
1そうだね
プレイ済み
返信[21]
親投稿
pinfu ANNAININ
モヤモヤ感に耐えきれず、 皆様の解答を見ました。 なるほどです! ・・・うん。もっと丁寧に考えねば・・・ でんぺんさん、 問題作成ありがとうございます!! 解説も楽しみです!
0そうだね
プレイ済み
返信[22]
親投稿
スー thanks_0u0
>>けいさん なるほど!3番目の方法にすれば、DATAを増やすだけで好きなだけ木が描ける、ってことですね( `・ω・´ ) それならきっとループはWHILE 1にした方が見た目綺麗ですよね。 良さそうなことを教えてくださってありがとうございます♪( ´▽`)
1そうだね
プレイ済み
返信[23]
親投稿
めがね tatsugu
入れ子になっているFORの中で最初の変数Iが上書きされてるからでしょうか?  1行目の変数を I以外の別の文字にしたらいいような……? 他の解法は分かりませんでした。
1そうだね
プレイ済み
返信[24]
親投稿
>めがねさん 正解です〜。バグを解消するという意味では一番手っ取り早いので問題ないですよ。他の方法はもうちょっと突っ込んで改良しようって感じなので改修量はその分増えます。
0そうだね
プレイ済み
返信[25]
親投稿
めがね tatsugu
>でんぺんさん 変数を手動で追いかけて最終的な挙動は大体分かったのですが、分からない事が1つありましたので、本題とはあまり関係の無い質問を1つさせてください。 そもそもこの連結するBG番号を指定する式、595+I+J×32は、どのように求められたのでしょうか?
0そうだね
プレイ済み
返信[26]
親投稿
>めがねさん BGはGRP5に画像として存在するんですが、それはBGチップが32×32の数並んだ正方形になっています。(並んだ画像などはスマイルブームのホームページからも確認出来ます) それで見ると、大きな木はサイズが横3×縦7(ただし一番左上だけは除く)で構成されていました。なので、木の左上のBG番号(595)だけスマイルツールなどで調べて、あとはそれから計算して実際の位置のBG番号を求めてる感じです。Y位置であるJを32倍しているのもBGチップが横に32個並んでいるので、それに対して計算しているからです。 ちょっと駆け足になりましたが、この説明でわかりますか?
1そうだね
プレイ済み
返信[27]
親投稿
めがね tatsugu
>でんぺんさん ありがとうございます! チップの並びと番号の対応、それに計算式は多分(ふんわりと)理解できました(^^;) 最初、ペイントではBG番号出ないし、バラバラのBG番号一覧からどうやって探せばいいのかな?と思っていたのですが、 MAPエディタでチップを選択した時に出る"BG#:H◎◎◎◎が16進数のBG番号だということにも先ほど気が付きました(汗)
0そうだね
プレイ済み
返信[28]
親投稿
>めがねさん 確かにそうですね〜。あまりわかりやすくはないですよね(^^; 僕はスマイルツールのマップエディタの形式を解析したり、それ以外でもBGの使い方を調べたりもしてたんで、それで余計にちょっと詳しい感じだったかもです。 でもとりあえずわかったようで良かったです!
1そうだね
プレイ済み
返信[29]
親投稿
日も変わったし総評を。 てか思ったよりたくさんの書き込みがあって良かったです。閑古鳥が鳴いてたらどうしようかと…(^^; 難易度は高いような低いようなという感じで気づけばすぐみたいな感じでみんな正解でしたね〜。さすがです。このぐらいもう敵じゃないですね〜。
0そうだね
プレイ済み
返信[30]
親投稿
今回のケースはGOSUBを使ってるとありえる事じゃないかと思って問題にしてみました。今回はシンプルな問題なので見つけやすいですが飛び先が複雑な感じだと見落としてわからない、なんてケースもあるかなぁ、とか。 それで今回のケースの回答で来ると思われるパターンを3パターン考えていました。 A: 呼び出し側のFORループのカウンタ変数を変更する。 B: サブルーチン側のFORループのカウンタ変数を変更する。 C: サブルーチンをDEF(ユーザー定義命令)に変更する。 です。 この中で一番多いと思っていたのがAで修正も1箇所です。他、B,Cとなる毎に修正箇所が多くなってきます。 ただし理想的な変更としてはC>B>Aとなります。 って書いてて長くなりそうな気がしてきた…。どう端折ろうかな…
0そうだね
プレイ済み
返信[31]
親投稿
とりあえず理由だけ簡潔に…。あとは質問があったら対応にしようかな…。以下、理由です。 パターンA: サブルーチン側のIという変数はループカウンタとしてよく使う変数なので今回呼び出し側のIを変更してもまたどこかで同じミスをしてしまうかもしれないので危険度は高い。ただし一箇所の修正で済むので今後改修の予定などがなければアリかも。 パターンB: サブルーチン側の変数をあまり使われない名前にして衝突が起こらないようにする。この名前を適切にすれば呼び出し側が変わる危険度はだいぶ減るでしょう。ただ危険度が0になったわけではないのがちょっと問題。(GOSUBの範囲での修正ならベストかな?)
1そうだね
プレイ済み
返信[32]
親投稿
けい kei0baisoku
1.要点のみに絞る 2.要点に加え、大事なところだけ補足 3.気合いと根性でメーラに長文を書き上げたのち一気に貼り付ける
0そうだね
プレイ済み
返信[33]
親投稿
パターンC: サブルーチンをDEFに変更すると上記の問題は発生しなくなる。なぜならサブルーチンないの変数はその中専用のローカル変数になるので、呼び出し側の変数(グローバル)を書き換える可能性がゼロになるのだ! でもでもプチコンにはバグがあって変数の二重定義のエラーが出ることが…。これはバージョンアップで直る(はず)です…。 ということでCが一番理想的なわけです。 あれ。そもそも不具合の原因書いてなかったかも…。 まあみんな正解なので、解説は他の人の書き込みを見てください! とくにけいさんの書き込みは細かいので参考になると思います! ということで終わり…。なんか言いたいことがうまく書けなかった…。
1そうだね
プレイ済み
返信[34]
親投稿
ちなみにオマケですが、DATA文で僕のリストは数字が2つ毎にスペースが入ってるのに気づきましたか? これは読み出し側のX,Yに合わせて区切った感じで、こうすることでデータが見やすくなるというちょっとした工夫です。 あまり長文を書いても読むのが嫌になると思ったのでこのぐらいにしておきます! 質問疑問等があったら続きで語りましょう! では、あでゅ〜
2そうだね
プレイ済み
返信[35]
親投稿
けい kei0baisoku
特に言いたかったことは「ユーザ定義命令や関数をうまく使うと、プログラムをパーツ化出来るから大きいプログラムを作る時に便利だよ!」というあたりでしょうか? 出題や解説から何となくそんな印象を受けました。 そう言えば書き忘れてましたが、もう一つ直し方でこれも考えてました。 (4)呼び出し元もサブルーチンも両方ユーザ定義命令化する 全部関数に押し込まないと気が済まない病とも言いますね………(^^; 自分のプログラムだったら多分こうしてると思います。
0そうだね
プレイ済み
返信[36]
親投稿
そうですね〜。というかなんでユーザー定義命令や関数が必要なのか。あった方がいいのか。みたいな感じですかねー。本当はもうちょっとちゃんと伝えたかったのですが、どんどん本来の趣旨の問題と解答というところから外れそうな気もして余計なお世話泣きもしたんでやめました(^^; 4は確かにそうすれば例のバグでも衝突は起きないので便利かもしれないですねー。一つの例としてはアリですね! 僕の場合は、どちらかというと「らしさ」というのを重視してるところもあるんで、プチコンとかBASICらしさみたいなのはあっても良いと思うので、GOSUBやGOTOを禁止にするとか、そういうことはしなくてもいいと思ってたりもします。ただその危険性や問題点をわかったうえでならいいんですが、そうじゃないと無駄にバグに見舞われたり、スパゲティーなソースになったりとあると思うので、良い方法は知っておいては欲しいですね。
0そうだね
プレイ済み
返信[37]
親投稿
けい kei0baisoku
どうも、3を選んでしまった人です(´ω`) 関数は重要で便利なのにイマイチ利点が伝わりづらいみたいなので、出題かミニ講座みたいなのをしようかなーと少し思ってました。問題は被っちゃったので、やるなら簡単に講座みたいなのかな。 プログラムは最初分からない注意点とか落とし穴とかたくさんありますから、経験通して覚えていくのは大切ですね。
3そうだね
プレイ済み
返信[38]
親投稿
最後に今回のプログラムをDEF命令に変更したリストをアップします。 同じ名前の変数が重複しているのに問題が起こってないことがわかると思います。
3そうだね
プレイ済み