|
|
|
2013/6/25(Tue) 10:14:14|NO.55206
始めまして。
そうでない方はこんにちは。
さて、現在ビンゴゲームを作ろうと考えております。
「ビンゴゲーム」は2つのフェイズにわけで製作します。
「1:ビンゴシート」「2:玉を引く」
まずは、「1:ビンゴシート」を作ることから初めております。
しかしどうも「シャッフル」する方法がわからないので質問させていただきます。
「仕様」
・数字がダブってはだめ (1,5,4,3,1→NG)
・数字は毎回ランダム
最初は、乱数を変数に代入する方法を考えてたのですが、
それだと「1,5,4,3,1」とかになって「数字がダブ」ってしまいます。
そこで思いついたのが、こちらのソースになります。
screen 0,640,480
hai_ti(0) = 0
hai_ti(1) = 1
hai_ti(2) = 2
pos 10,10 : mes hai_ti(0)
pos 10,30 : mes hai_ti(1)
pos 10,50 : mes hai_ti(2)
予め配列に数字を入れる方法です。
配列に入れる数字は固定ですが、数字の代入が終わったあとに配列をシャッフルして、
上から順番に表示されせば毎回違う結果になると考えております。
しかしその「シャッフル」する方法がどうも思い浮かばなかったので、
検索して調べてみました。調べて見つけたソースがこれ。
dim card, 40
randomize ;乱数発生の初期化
gosub *シャッフル
;結果表示
repeat 25 ;\ = 左側の数値に対して余り(12 \ 5 = 2) , / = 割り算
pos (cnt \ 5) * 24, cnt / 5 * 16
mes card(cnt)
// pos 100,100 : mes "card(0) " + card(0)
// pos 100,120 : mes "card(1) " + card(1)
// pos 200,100 : mes "card(r1) " + card(r1)
// pos 200,120 : mes "card(r2) " + card(r2)
// pos 100,150 : mes "wk " + wk
loop
stop
*シャッフル
card(0) = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
card(20) = 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
;カードをシャッフル
repeat 200
r1 = rnd(40) ;乱数を代入
wk = card(r1)
// pos 320.0 : mes "r1 " + r1
// pos 320.0 : mes "wk " + wk
// pos 320.0 : mes "(r1) " + card(r1)
// pos 320.0 : mes "(r2) " + card(r2)
card(r1) = card(r2)
card = wk
// pos 320.0 : mes "card(0) " + card(0)
loop
return
ちなみにコメントアウトしているところは、自分が理解する用です。
このソースを理解しよとしたのですが、どうしてもわからないところがございました。
;カードをシャッフル
r1 = rnd(40) →乱数で入った数字が39としたら、39代入
pos 320.0 : mes "r1 " + r1 →39表示
wk = card(r1) →39の配列は40なので、40代入
card = wk →wkは40なので、40代入
pos 320.0 : mes "card(0) " + card(0) →40が入っているので、40表示
;結果表示
mes card(cnt)
pos 100,100 : mes "card(0) " + card(0)
card(0)には40が入っているはずなのに、結果は8でした。
何故こんな動作になるんか全然わかりませんでした・・・orz
やはり他人のソースだから理解できないのか・・・
それとも、何か勘違いをおこしているのか・・・
こんな感じで、他のソースの解析できておりません。
最初のソース「予め配列に数字を入れる方法です。」に手を加えるか
それとも「他人のシャッフル方法」を理解するのか、悩んでます。
もし私の「他人のシャッフル方法」の解釈の仕方が悪かったら
「予め配列に数字を入れる方法です。」に手を加えようかと思っております。
アドバイスや間違っているところございましたら、指摘お願いいたします!
| |
|
2013/6/25(Tue) 10:35:03|NO.55207
こんなのはどうでしょうか?
#module
#deffunc rnd_array int max,array arr,int count
dim arr,count
foreach arr
arr(cnt) = rnd(max)
index = cnt
repeat cnt
if arr(cnt) == arr(index):continue index
loop
loop
return
#global
randomize
rnd_array 100,a,10
foreach a
mes""+a(cnt)
loop
|
|
2013/6/25(Tue) 10:48:53|NO.55208
card = wk
card(r2)じゃなくてcard?
|
|
2013/6/25(Tue) 12:51:24|NO.55209
repeat 200
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入
card(r1) = card(r2);card配列のr1番目に、card配列の0番目を代入
card = wk ;card配列の0番目に、変数のwkを代入
loop
;纏めると
;39までの乱数を一つ取り出し(r1)
;配列のr1番目の数を一時的に保存(wk)
;配列のr1番目を、配列の0番目の数値で上書き
;配列の0番目に、保存した値を上書き
;
;r2は定義されていないので常に0
;cardの配列を指定していない場合は0番目と見なされる
|
|
2013/6/25(Tue) 13:05:30|NO.55210
>>r1 = rnd(40) →乱数で入った数字が39としたら、39代入
>>pos 320.0 : mes "r1 " + r1 →39表示
>>wk = card(r1) →39の配列は40なので、40代入
39の配列は39、0〜40の配列なら要素は41個
>>card = wk →wkは40なので、40代入
>>pos 320.0 : mes "card(0) " + card(0) →40が入っているので、40表示
------------------------------
r1 = 39
39 = card(39)
card(39) = card(0)
card(0) = 39
ループの1回目で、配列の39番と0番が入れ替わる。
以下、ランダムの配列位置と配列0番が入れ替わるだけ。
それを200回繰り返している。
|
|
2013/6/25(Tue) 14:54:55|NO.55211
菊岡万次郎さん
ソースありがとうございます。
実は「モジュール」「deffunc」を使ったことがないため、のちに解析しときます!
晩御飯さん
>card = wk
>>card(r2)じゃなくてcard?
あ・・・「card(r2) = wk」ですね。
元ソースどこに行ったのかわからなくなって、編集しているうちに消しちゃったかも・・・orz
なんとか見つけることができたので載せてみる(元ソースなので無編集です)
dim card, 40 ;カード用
randomize
gosub *shuffle ;カードシャッフル
;結果表示
repeat 40
pos (cnt \ 10) * 24, cnt / 10 * 16
mes card(cnt)
loop
stop
;カードシャッフル -----
*shuffle
;配列初期化
card(0) = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
card(20) = 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48
;シャッフル
repeat 200 ;200回
r1 = rnd(40)
r2 = rnd(40)
wk = card(r1)
card(r1) = card(r2)
card(r2) = wk
loop
return
|
|
2013/6/25(Tue) 15:58:01|NO.55212
|
|
2013/6/25(Tue) 17:38:09|NO.55214
KAさん
repeat 200
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入
card(r1) = card(r2);card配列のr1番目に、card配列の0番目を代入
card = wk ;card配列の0番目に、変数のwkを代入
loop
>>;39までの乱数を一つ取り出し(r1)
>>;配列のr1番目の数を一時的に保存(wk)
>>;配列のr1番目を、配列の0番目の数値で上書き
>>;配列の0番目に、保存した値を上書き
>>;
>>;r2は定義されていないので常に0
>>;cardの配列を指定していない場合は0番目と見なされる
詳しい解説ありがとうございます。理解出来たかもしれません。
晩御飯さんのほうで、回答したソースで自分なりに解説してみます。
;シャッフル
repeat 200 ;200回
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (30)
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (10)
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入 (30)
card(r1) = card(r2) ;card配列のr1番目に、card配列の0番目を代入 (0)
card(r2) = wk ;card配列のr2番目に、変数のwkを代入 (30)
/*/
2週目
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (20)
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (30)
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入 (20)
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
card(r2) = wk ;card配列のr2番目に、変数のwkを代入 (20)
3週目
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (20)
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (5)
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入 (20)
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
card(r2) = wk ;card配列のr2番目に、変数のwkを代入 (20)
/*/
これだと200回もループしちゃうし、乱数の値が被ってしまうのではないのか?
っと疑問に思ったけど
>>;配列のr1番目を、配列の0番目の数値で上書き
この「上書き」っていう書きかたがすごくよかった!
2週目
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (30)
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
配列に30という数値入ってたとしても、
3週目
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
だとしても、最後の値が反映されるのが、プログラムの仕様だったはずなので、
もしかぶったとしても、「上書き」されるので問題ない。
こんな感じで200回繰り返せば、数が大体ばらばらに表示されるっていう仕組みかな?
しかし、質問のソースの「pos 320.0 : mes "(r2) " + card(r2)」が何故数値が変化してたんだろう・・・
「card(0)」の1個前のループの数値が入っていることは、メッセージで表示させてわかったんだけど、
何故「card(r2)」数値が変化しているんだろう・・・
謎だけど、2個目のソースを使って、自分なりに改造したほうがよさそうですね・・・
| |
|
2013/6/25(Tue) 17:45:22|NO.55215
GrapeColor(DION)さん
リンクありがとうございます。
実はこのリンク何回か見てました。
最初「シャッフル、削除」の2パターンを考えてました。
1・配列に乱数の数値を入れる
2・数字がかぶっているものがあったら削除
3・数値を表示させる
というのを考えてたのですが、「削除」というのは少し遠まわしすぎるかなーっと思ったのと、
「削除」すると不具合が出る恐れがあるのでは?という懸念がありました。
リンク先の「力ずく法」は、なんか手を出しちゃいけない予感がしたのでやめて
やさしそうな「シャッフル」を選択したって感じですね。
|
|
2013/6/25(Tue) 20:05:13|NO.55222
まぁ、もぅ方が付ぃてぃると思ぅんですが、ちょっと気になったので
”シャッフル”ですが、要は「配列の中身をぐちゃぐちゃに並び替える」ことがしたい訳ですね
で、この”シャッフル”は何とかプログラムで実現しようと考えた時、
「配列の任意の2要素を交換する」操作を任意回数繰り返す
とそれっぽくなりそうですし、実装も簡単そうですね
それを念頭に入れつつ、今回提示されているスクリプトを眺めていくと概念的に理解しやすいかなと思います
私が気になったのは
> これだと200回もループしちゃうし、乱数の値が被ってしまうのではないのか?
> っと疑問に思ったけど
>>> ;配列のr1番目を、配列の0番目の数値で上書き
>この「上書き」っていう書きかたがすごくよかった!
の部分でして、どちらかというと上書きというよりは、その前の行も踏まえて「配列の2要素を交換している」と考えた方がまとまった単位で見られると思います
HSPで任意の2変数leftとrightの中身を交換したい時、一時変数tmpを用いて
tmp = left// 一時変数にleftの中身を代入(コピー)
left = right// leftにrightを代入
right = tmp// tmp(保存しておいたleftの中身)をrightに代入
と、簡単には書けます
元のスクリプトでは
repeat 200 ;200回
// 配列内の任意の2要素を乱数で決める
r1 = rnd(40)
r2 = rnd(40)
// 添字r1と添字r2の要素を交換
wk = card(r1)
card(r1) = card(r2)
card(r2) = wk
loop
と見ると直観的でしょう
さて、ここからはちょっと蛇足になるかもしれませんが…
この「配列の任意の2要素を交換する」操作ですが、果たして何回くらい繰り返せば全要素がバラバラになりそうでしょうか?
元のスクリプトでは交換する2要素いずれも乱数で選んでいるので、もし「一度も乱数で選ばれない要素」があったらその要素はシャッフルされず、元の位置のままです
「元の位置のままである」ことも”シャッフル”に含まれますが、あえて”シャッフル”という操作をしているのでそれが望まれる状況であることは稀だと考えられますよね
なので、「全ての要素がランダムに配置される(なるべく元の位置でない)」ようにするには、上記のスクリプトの場合は配列長よりもいくらか大きい回数だけ繰り返す必要がありそうに思えます
ところで、「少なくとも全要素が最低一回は交換の対象になる」ようにしようと最初から考えると、そんなにたくさん繰り返さなくても何とかうまく”シャッフル”できそうですよね
「全要素が最低一回」なので、配列内の各要素についてループすればいい訳ですから
そして、”シャッフル”したいので交換対象の要素はランダムに定めればよさそうです
そう考えると
repeat length(card)
// 交換対象の要素を乱数で決める
r = rnd(length(card))
// 自分(cnt)と交換対象を交換
wk = card(cnt)
card(cnt) = card(r)
card(r) = wk
loop
というようなスクリプトになります
ちなみにこれ、「HSP開発Wikiの巡回乱数/src」に載ってるスクリプトと同じになります
HSP開発Wikiの巡回乱数/src
http://hspdev-wiki.net/?%BD%E4%B2%F3%CD%F0%BF%F4%2Fsrc#fa25fb6b
シャッフルはあんまり工夫するところがないような気がしますが、それでもこんな考え方でこういうスクリプトを考えている人も居るよ、という補足でした
| |
|
2013/6/25(Tue) 22:33:41|NO.55241
3kさん
補足等ありがとうございます。
>>その前の行も踏まえて「配列の2要素を交換している」と考えた方がまとまった単位で見られると思います
ふむふむ「交換」ですか。
先入観のせいかどうかわからないけど、
「数字がかぶったらどうしよう」というのを頭の中でぐるぐる考えてました。
表示させるとき全部表示されちゅよね・・・削除?とか考えたのもそのせいです。
どうしても「交換」っていうイメージが沸かないんですよね・・・
む、ちょっと待って。
NO.55214の解説はちょっとおかしい。
自分自身の回答に突っ込むと、
解説しているのは「数字がカブっても大丈夫」という部分だけ。
プログラムの動作について理解出来てなかったようだ。危ない危ない。
>>配列長よりもいくらか大きい回数だけ繰り返す必要がありそうに思えます
もちろん、200回という回数は、まぜまぜするための回数と理解しています。
もしこれが、極端ですが40回とかだと全然混ざらなくって、2000回とかにすればすごい混ざります。
>>ところで、「少なくとも全要素が最低一回は交換の対象になる」ようにしようと最初から考えると、
>>そんなにたくさん繰り返さなくても何とかうまく”シャッフル”できそうですよね
確かに今のソースだと1000までの数字をシャッフルさせたいときとか、すごい回数のループになってしまいますね。
>>「length」
配列の1次元要素数を返す。
これも使ったことがない命令ですね・・・
>>巡回乱数
実は質問する前からちょびっと見てたのですが、
なんだか情報が多すぎて、自分が必要とする情報が落とせる自身がなかったので、手をつけてませんでした。
>> card(r1) = card(r2) ;card配列のr1番目に、card配列の0番目を代入 (0)
の動作について、ちゃんと理解してなかったようなので、
再度考えて、皆さんの回答を見て、どんな動作なのか把握しときます。
明日ねっとりじっくりやりたいと思います。
|
|
2013/6/25(Tue) 22:53:39|NO.55243
単純な一回の走査で完全にバラバラにできます。
rnd_max = 20
dim rnd_table, rnd_max
repeat rnd_max : rnd_table(cnt) = cnt : loop // 連番で初期化
repeat rnd_max
// 前から順番にどこかの要素と入れ替える
temp = rnd_table(cnt)
r = rnd(rnd_max)
rnd_table(cnt) = rnd_table(r)
rnd_table(r) = temp
loop
// 完了
repeat rnd_max
mes rnd_table(cnt)
loop
|
|
2013/6/26(Wed) 00:51:05|NO.55250
>どうしても「交換」っていうイメージが沸かないんですよね・・・
カップシャッフルをイメージしてくれるといいかな
|
|
2013/6/26(Wed) 02:28:55|NO.55252
a = b
っていうのはaという入れ物の中身をbと同じ物に置きかえるってことだから
グラスAにジュース2ℓが入っていて
グラスBにジュース5ℓが入っているとしたら
グラスAに入ってるジュースを捨てて
グラスBに入ってるジュースと同じ物を入れるってこと
Bの中身をAに入れてるわけじゃなく
あくまでもAの中身をBと一緒の物にしているってことで
a = b
aはbと一緒 というふうにaの状態を置き換え定めたもの
よって
Aと同じものをCに入れておく
いわゆるAの状態をCに保管しておく
C = A
AにBと同じ物を入れてAの状態を変える
A = B
その後、BをCと同じ状態にすれば
Bの中身が最初のAの状態と同じになる
B = C
これが結果的にAとBを交換した状態になるってことです
間違ってたら誰か補足&訂正おねです(ぉぃ
|
|
2013/6/26(Wed) 11:22:00|NO.55256
ht.さん
ソースありがとうございます。
こんなに短くできるのか・・・
ソースの方は解析しときます!
朝一番からずっと
card(r1) = card(r2) ;card配列の「r1」番目に、card配列の「r2」番目を代入 (10)
の処理がどうしてもつっかかってしまう・・・なんでだー!
|
|
2013/6/26(Wed) 11:26:16|NO.55257
晩御飯さん
>>カップシャッフルをイメージしてくれるといいかな
例えば、
r1 = rnd(40) ;変数「r1」に、39までの乱数を一つ代入 (30)
r2 = rnd(40) ;変数「r2」に、39までの乱数を一つ代入 (10)
wk = card(r1) ;変数「wk」に、「card」配列の「r1」番目の数を代入 (30)
card(r1) = card(r2) ;card配列の「r1」番目に、card配列の「r2」番目を代入 (10)
card(r2) = wk ;card配列の「r2」番目に、変数の「wk」を代入 (30)
の処理で、
r1 = 30
r2 = 10
wk = card(30)
card(30) = card(10)
card(10) = card(30)
乱数の数値が上記のようになってたとしたら、このようになりますよね。
最後の二行で配列を入れ替えてますね。
あれ?これでいいのかな?
|
|
2013/6/26(Wed) 11:53:53|NO.55258
二十円玉さん
>>a = b
>>っていうのはaという入れ物の中身をbと同じ物に置きかえるってことだから
同じ物・・・なるほど。今までそんな風にとらえたことがありませんでした。
代入代入代入・・・
>>Bの中身をAに入れてるわけじゃなく
>>あくまでもAの中身をBと一緒の物にしているってことで
今までさりげなく代入とかをおこなってたけど、こういうことだよねっという意味ですね。
>>Aと同じものをCに入れておく
〜
>>Bの中身が最初のAの状態と同じになる
なるほどこれで入れ変えているのですね。
しかしなんでだろ?今一もやっとしている部分が・・・
入れ替えていることはわかっているはずなのに・・・なんだろうなぁ・・・このもやっとしたものは。
2つめのソースを改造して、自分風にしあげれば納得するかも?
それか、STG風に仕上げれば納得いくかも?
(今までSTGゲームしか作ったことがない、今まで作ったソースと比べるのもありかも)
ちょっと色々いじくってみます。解決までもうちょっと。なんかごめんなさいorz
|
|
2013/6/26(Wed) 14:04:59|NO.55259
どこら辺がもやっとしているのかがこちらには分からないが(STG風とは?)、
取り敢えず自分なりの説明をしようと思う。
前のレス群とほぼ同じ説明になるであろうが。
randomize
#module
// ある別の変数を用意して入れ替える方法
#deffunc swap var p1, var p2
tmp = p1
p1 = p2
p2 = tmp
return
// XOR演算を利用して入れ替える方法
#deffunc swap2 var p1, var p2
p1 ^= p2
p2 ^= p1
p1 ^= p2
return
// 配列の要素をランダムに並べ替える(シャッフルする)
// p1 : シャッフルを行いたい配列変数
#deffunc random_shuffle array p1
repeat length(p1)
r = rnd(length(p1))
swap2 p1(cnt), p1(r)
loop
return
#global
// 1〜20までの数が入った配列変数を作成
dim ary, 20
repeat length(ary)
ary(cnt) = cnt+1
loop
// 要素をシャッフル
random_shuffle ary
// 表示
repeat length(ary)
mes "ary(" + cnt + ") = " + ary(cnt)
loop
swapとswap2の違いは、前者は一時変数を使用してあたいを入れ替えているのに対し、
後者はXOR交換アルゴリズムというものを使用している。
(XOR交換アルゴリズムについてはWikipediaにこの名前の通りのページがあるのでそちらを参照してくれ。)
一般的には後者のほうが速いはずだが、インタープリタ言語のHSPではあまり差は出ないと思う。
いまいちよくわからないというのであれば、簡単な例を用いて考えてみるとよい。
例えば、赤、青、黄、黒、白の5つのカップ(カップシャッフルで用いられるカップ)があるとしよう。
そこから、まずは1番目のカップと、それ以外のカップを選んで、位置を交換するとする。
結果、黄、青、赤、黒、白となったとする(この時は3番目の黄色のカップが選ばれた)
そして、次は2番目のカップ、その次は3番目のカップ……とカップの数だけ交換を繰り返せば、
だいたいバラけるはず、ということはなんとなく想像がつくと思う。
上記のrandom_shuffle命令では、同じ要素が選ばれた時も交換を行っている。
もちろん、値は変わらない。
なので、厳密には完全にシャッフルするわけではないが、
ゲームに使うプログラムであれば、このようなシャッフル方法でも十分なはず。
理解していただけたであろうか?
| |
|
2013/6/26(Wed) 19:09:22|NO.55264
checkさん
ソースありがとうございます。
のちに解析したいです・・・!
>>例えば、赤、青、黄、黒、白の5つのカップ(カップシャッフルで用いられるカップ)があるとしよう。
なるほど、あそこの処理はやはり交換している処理なんですね。
ちょっと難しく考えすぎたようです。
後はソースを改造していき、自分の物にしてしまえばいけそうですね。
アドバイスくれたかた、ソースくれた方ありがとうございます。
ビンゴゲーム1つで、色んな考えかたがありおどろきました。
|
|
2013/6/27(Thu) 08:17:46|NO.55278
前に投稿したスクリプトにバグがあることに気がついたので修正。
random_shuffleの中身を以下のように書き換えてくれ。
#deffunc random_shuffle array p1
repeat length(p1)
r = rnd(length(p1))
if (r == cnt) : continue // 入れ替える要素が同じだった場合、無視する
swap2 p1(cnt), p1(r)
loop
return
おそらくこれで直ったはず。
|
|
2013/6/27(Thu) 14:37:07|NO.55279
checkさん
>>前に投稿したスクリプトにバグがあることに気がついたので修正。
おぉ・・・すごい。
自分の回答というものは、自分でなかなか間違いを探せない事が多いです(´・ω・`)
余談ですが・・・
例えば、NO.55214
/*/
2週目
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (20)
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (30)
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入 (20)
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
card(r2) = wk ;card配列のr2番目に、変数のwkを代入 (20)
3週目
r1 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (20)
r2 = rnd(40) ;変数r1に、39までの乱数を一つ代入 (5)
wk = card(r1) ;変数wkに、card配列のr1番目の数を代入 (20)
card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
card(r2) = wk ;card配列のr2番目に、変数のwkを代入 (20)
/*/
>>card(r1) = card(r2) ;変数r1に、前ループのcard(r2)の数値を代入(30)
「前ループ」ってなんだよ!すぱーん!!っていうツッコミがくる可能性があったのです。
>>む、ちょっと待って。
>>NO.55214の解説はちょっとおかしい。
って言ってたのはこれも原因の1つ。
せっかくなので画像を使わないビンゴシートもどきのソース(改造中だよ!)
------------------------------------------------------
dim card, 40
randomize ;乱数発生の初期化
gosub *シャッフル
;ビンゴシートの縦線
tate_y(0) = 20,45,70,95,120,145
color 255
repeat 6
line tate_y.cnt,20,tate_y.cnt,100
loop
;ビンゴシートの横線
tate_x(0) = 20,37,52,67,82,100
repeat 6
line 20,tate_x.cnt,145,tate_x.cnt
loop
;結果表示
repeat 25 ;\ 余り , / 割り算
color ,,255
pos 25+(cnt \ 5) * 24, 20+cnt / 5 * 16
mes card(cnt)
color 255,,255 : pos 75,50 : mes "■"
loop
stop
*シャッフル
card(0) = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
card(20) = 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
;シャッフル
repeat 200
r1 = rnd(40) ;変数「r1」に、39までの乱数を一つ代入
r2 = rnd(40) ;変数「r2」に、39までの乱数を一つ代入
wk = card(r1) ;変数「wk」に、「card」配列の「r1」番目の数を代入
card(r1) = card(r2) ;card配列の「r1」番目に、card配列の「r2」番目を代入
card(r2) = wk ;card配列の「r2」番目に、変数の「wk」を代入
loop
return
| |
|
2013/6/27(Thu) 15:44:01|NO.55280
前にも書いたけど dim card, 40 は40個の要素です。
>>card(0) = 0,---20
>>card(20) = 21,---40
「数字の20は絶対に出てこない」と思うのは私だけかな。
|
|
2013/6/27(Thu) 15:55:25|NO.55281
とおもったら、10を飛ばしているから問題ないんだね。失礼。
|
|
2013/6/28(Fri) 00:03:38|NO.55286
これ系のコードで前から思っていたのですが、
「配列の先頭から他要素のどれかと交換する」というアルゴリズムですと、
全部で「(要素数-1)の要素数乗」通りになって、
本来の組み合わせ数(要素数の階乗)とは異なったものになってしまいます。
つまり、各パターンの出現確率が均等にならないということです。
たった3要素をシャッフルするときにすら、分かりやすく偏ってくれます(以下、ソース)。
randomize
dim count,6
dim a,3
for c,0,10000
a.0=1,2,3
for k,0,3
p=rnd(3)
if p=k :_continue
tmp=a.k
a.k=a.p
a.p=tmp
next
if (a.0=1)&(a.1=2)&(a.2=3) :count(0)++
if (a.0=1)&(a.1=3)&(a.2=2) :count(1)++
if (a.0=2)&(a.1=1)&(a.2=3) :count(2)++
if (a.0=2)&(a.1=3)&(a.2=1) :count(3)++
if (a.0=3)&(a.1=1)&(a.2=2) :count(4)++
if (a.0=3)&(a.1=2)&(a.2=1) :count(5)++
next
for k,0,6
mes count(k)
next
stop
そこで、「配列の先頭から、その要素か以降の要素のどれかと交換する」
というアルゴリズムにすることをおすすめします。
これだと、とりうる可能性がちょうど要素数の階乗になって、
確率的にもきちんとバラけてくれます。
randomize
n=3
n_2=6 ;nの階乗
dim count,n_2
dim a,n
for c,0,10000
a.0=1,2,3
for k,0,n-1
p=rnd(n-k)+k
tmp=a.k
a.k=a.p
a.p=tmp
next
if (a.0=1)&(a.1=2)&(a.2=3) :count(0)++
if (a.0=1)&(a.1=3)&(a.2=2) :count(1)++
if (a.0=2)&(a.1=1)&(a.2=3) :count(2)++
if (a.0=2)&(a.1=3)&(a.2=1) :count(3)++
if (a.0=3)&(a.1=1)&(a.2=2) :count(4)++
if (a.0=3)&(a.1=2)&(a.2=1) :count(5)++
next
for k,0,n_2
mes count(k)
next
stop
あと、件のビンゴカードを、自己流なコードで書いてみるとこうなりました。
ご自由にお使いください。
;ビンゴカード自動作成
;数字の範囲が1からCARD_NUM_MAXまで、
;一辺のサイズがCARD_SIZEな
;ビンゴカードの盤面をCARD_SHEETS枚分生成する。
;数字はタブ区切りにして、Excel等で貼りつけて印刷しやすいようにした。
;なお、盤面出力結果をいちいちmesboxで表示するよりも、
;コマンドプロンプト上でコピペ出来る方が楽だと判断した。
#runtime "hsp3cl" ;コマンドプロンプト表示にする
#const CARD_NUM_MAX 40 ;ビンゴカード最大の数字
#const CARD_SIZE 5 ;(正方形な)ビンゴカードの一辺の数字数
#const CARD_SHEETS 10 ;ビンゴカードの枚数
randomize
;変数初期化
if(CARD_NUM_MAX < CARD_SIZE * CARD_SIZE){
mes "盤面が大きすぎます!"
stop
}
dim card_num, CARD_NUM_MAX
repeat CARD_NUM_MAX
card_num(cnt) = cnt + 1
loop
;シャッフルして出力
sdim output, 32000
repeat CARD_SHEETS, 1
;シャッフル
for k, 0, CARD_NUM_MAX - 1
p = rnd(CARD_NUM_MAX - k) + k
;入れ替え処理
tmp = card_num(k) :card_num(k) = card_num(p) :card_num(p) = tmp
next
;出力
output = ""
for k, 0, CARD_SIZE * CARD_SIZE
if(k \ CARD_SIZE = CARD_SIZE - 1){
output += strf("%2d", card_num(k))+"\n"
}else{
output += strf("%2d", card_num(k))+" "
}
next
mes output
loop
stop
| |
|
2013/6/28(Fri) 08:18:45|NO.55289
KAさん
>>とおもったら、10を飛ばしているから問題ないんだね。失礼。
ぎゃああああ「10」ない!
ってなわけで修正してきました!
|
|
2013/6/28(Fri) 08:36:52|NO.55291
YSRさん
ソースと補足ありがとうございます!
>>つまり、各パターンの出現確率が均等にならないということです。
やっている最中に思いましたね・・・
どんだけループしようが「出現確率が均等」になることはないですねぇ・・・うむ〜。
>>そこで、「配列の先頭から、その要素か以降の要素のどれかと交換する」
お恥ずかしながら「階乗」初めて聞いた・・・
自分が作っているプログラムが落ち着いたらとりかかってみたいと思います。
>>あと、件のビンゴカードを、自己流なコードで書いてみるとこうなりました。
>>「#runtime」;ランタイムファイルの設定
>>「#const」;マクロ名の定数定義
おほ・・・見たことがない命令だ。
(複数シート作りたいことが何故バレたし!・・・←現在ここ作っている)
「マクロ」「モジュール」とかそろそろ使おうか?って思ってはいるんですけど、
今やっている基本的な部分が安定してから手を出そうかと思います。
まだまだヒヨッコレベルだと思うので、じっくりやりたいと思います。
今すぐ出来るわけじゃないけど、そのうち皆さんのソースも解析しますよー。
解決づみなのに色々ありがとうございます。
|
|
2013/6/28(Fri) 10:02:32|NO.55295
>今すぐ出来るわけじゃないけど、そのうち皆さんのソースも解析しますよー。
>解決づみなのに色々ありがとうございます。
やる気に満ち溢れていてなにより。
>(複数シート作りたいことが何故バレたし!・・・←現在ここ作っている)
これは、要するに元の数字が入った配列をまたシャフルするだけでOK(ソース参照)
>#runtime "hsp3cl"
>#const CARD_NUM_MAX 40
この辺は、ぶっちゃけ自分が書きやすいように書いてるから、
今すぐ覚えなければというほどでもない。
モジュールはまあ確かに(HSPとしては)便利だけど、よくあるC言語とかの関数とは
明確に違うってことだけは忘れないでほしいな。まだ言うには早いけど。
(参考: http://ysrken.blog.fc2.com/blog-entry-50.html)
|
|
2013/6/28(Fri) 19:29:20|NO.55308
YSRさん
>>今すぐ覚えなければというほどでもない。
>>モジュールはまあ確かに(HSPとしては)便利だけど、よくあるC言語とかの関数とは
>>明確に違うってことだけは忘れないでほしいな。まだ言うには早いけど。
おぉー・・・
リンクは思い出した頃にでも見てみようかと思います。
なるほど、やはり無理せず自分のペースで覚えることが大事そうですね(と言いつつ、3年もたっている・・orz)
まぁ、とりあえず年数なんて関係ないんです。理解しようとする力と、継続力の方が自分は大事だと思っているので(誤魔化した)
〜本当に本当の超余談〜
問題解決して気がついたのですがビンゴゲームって罠あったんですね。
(例)
Aさんのシート
123
456
789
Bさんのシート
987
654
321
これで「1〜9」までしかでない玉でビンゴやったら、全員番号がヒットしてしまうので、
どこかしら穴が空いてしまい「はらはら」や「ドキドキ」が無くなってしまいますね・・・w
これでは「ビンゴシート」「玉を引く」が出来ても面白くないですね。
ここに書かれているソース全部、そういう心配はないですが気をつけないといけませんね。
(例えば)
・縦横*3の全9マスの「ビンゴシート」の数を「1〜20」にする。
・ビンゴ玉の数字を「1〜20」まで出るようにする。
とかで回避するなど、考える必要がある (もちろん今のソースは大丈夫)
(この余談は、次にビンゴゲームを作りたいと思った人向けに残しときます)
|
|
2013/6/28(Fri) 20:31:54|NO.55309
>問題解決して気がついたのですがビンゴゲームって罠あったんですね。
ビンゴって
一列目が1〜15
二列目が16〜30
三列目が31〜45
四列目が46〜60
五列目が61〜75
じゃなかったでしたっけ?
うる覚えなので違ったらごめんんさい
独自ルールのビンゴなのかもしれないですが
>#const CARD_NUM_MAX 40
定数はマクロじゃないので
マジックナンバーを書かずに定数にしましょう。とはよく書いているので
使った方がいいかもしれませんね 計算式展開したりしますが 考えなきゃずっとシンプルです
40って書くよりCARD_NUM_MAXって書く方がわかりやすいでしょ
更に最大値を変更するなら一箇所だけ変更すればOKなので
って僕もよくマジックナンバー書きますが^^;
常連さんのミントさんらしいわかりやすい文章とか
常連で上級者さんぽいYSRさんの基礎がしっかりしてるとことか
好感持ってるスレだったりします
確かコンテストの番組で
円周率を表示されるソフトが紹介されてて
その作者様かもしれないかんじですね
HSPに不慣れな人が頑張って作成したと思いきや
熟練さ。が詰まったシンプルな作品だった。と
あやかりたいものです
ちょっとカードを配列で管理してるとこが怖いんですけど
モジュール変数を使わないなら
ノートパッドで管理とかどうでしょうか?
名前とかも一緒に管理できるし
クックブックのかんじでは
複数の要素はノートパッドで管理は
定石の一つな気がします
と、考えて楽しそうな部分なのであやふやに書いてみる
|
|
2013/6/29(Sat) 02:33:49|NO.55314
>全員番号がヒットしてしまう
Wikipediaにもありましたが、変則ルールの場合、読み上げる数字を少なく取る
(1〜40なら20個までしか取らないとか)のがよくとられる方法らしいです。
>独自ルールのビンゴなのかもしれないですが
えーっと、本家ビンゴカード(と言うかその辺にある普通の奴)の場合、左列から、
"B" 「 1〜15までのうち5つ(順番はソートされていなくてもいい)」
"I" 「16〜30までのうち5つ(順番はソートされていなくてもいい)」
"N" 「31〜45までのうち4つ(順番はソートされていなくてもいい)」←真ん中に穴があるため「4つ」
"G" 「46〜60までのうち5つ(順番はソートされていなくてもいい)」
"O" 「61〜75までのうち5つ(順番はソートされていなくてもいい)」
となっていますね。
先に上げたコードを改良すればこちらも簡単に作ることが出来るはずです。
>円周率を表示されるソフト
ひょっとして「高速電子式計算機」のことですか?
(ソース: http://blog.livedoor.jp/toropippi/archives/692774.html)
あれは私ではありませんよ。ChudnovskyとかGPGPUとかを使いこなしているような
方なので、色々と見習いたいところです。
>ちょっとカードを配列で管理してるとこが怖い
怖い、とは?
良くわからないのですが、ノートパッド文字列の場合、
追加や挿入・一行読み込みのコストが馬鹿にならないのでお勧めはしませんね。
ちなみに、文字列の配列ならsdim命令で作ることができます。
|
|
2013/6/29(Sat) 09:02:55|NO.55317
>>ちょっとカードを配列で管理してるとこが怖い
> 怖い、とは?
例えば
カードを配列で管理していて
キャラの名前を配列で管理して
HITしたcheckも配列で管理したりすると
複数の配列で管理しなきゃいけないのでは?と思いました
データを複数の配列で管理するのはちょっと怖いですね
怖い。とは僕なら躊躇するな。という意味です
とか言って3つは僕もやったことあるような
でも読み込みだけでした
それでも更に3種類変数に書き出してから使っていました
それくらいのデータをノートパッドで管理してもそんなに遅くならないと思います
あと、無知なことが多々ありまして 申し訳ないです
|
|
2013/6/29(Sat) 12:53:52|NO.55325
RPGでいえばキャラクターの情報に使うHP・名前など、パラメータ毎に
複数の配列を用意して同期させるテクニックはことHSPでは常用される手段だと思います。
これはHSPに構造体のような複数の型を混合して扱う手段が乏しいことからの苦肉の策とも言えるのかもしれませんが…。
他言語のクラスに慣れた立場からするとHSPのモジュール変数は奇異に映るのでやや敬遠したくなりますが、
その手の先入観を持たない初心者なら案外すんなり使いこなせるようになるかもしれないですね。
|
|
2013/6/29(Sat) 13:00:08|NO.55326
解決スレで勝手に盛り上がるのはいかがなものかと思います。
|
|
2013/7/1(Mon) 21:06:12|NO.55418
何も言わずに置けばいいかなーっと思ってたけど、
「無言」ていうのはなんか悪いので書かせてもらいます!(蛇足だけど)
y.tackさん
>>独自ルールのビンゴなのかもしれないですが
えっとですね。多分私だけかもしれませんが・・・
1.数字がシャッフルできるソースを作ろう
2.ビンゴシートの数字があまり数字が大きいとわかりにくから、1〜9までにしよう!
3.玉を引くソースを作ろう
4.玉の数字があまり数字が大きいとわかりにくから、1〜9までにしよう!
5.完成した!ビンゴ大会開こう!
ってなったときに、単純にソースを作ってしまった結果
1〜9まで全部ヒットしちゃうから、つまらない物になってしまうという意味です。
「ソースとして間違ってはいない」んだけど、「ゲーム性として間違っている」とことなので
作る際はこういったことに気をつけないといけないんだな〜ということを言いたかったわけです。
KAさん
>>解決スレで勝手に盛り上がるのはいかがなものかと思います。
書こうかどうか、迷ったけど、やっぱり書いちゃうのが私。
皆が「あれはどう?」「これはどうなの?」という意見が飛び交うのは珍しいと思ってたのでいいことだと思いました。
けれど、ビンゴゲームから離れすぎてしまうと、
ビンゴゲームを知りたいと思った人とかのパニックの原因になるかもです。
とりあえず立てた本人が何か言わないとあかんと思うので言います!
【ビンゴゲームは大丈夫です!】のでレスはもう大丈夫です(これ事態のレスも必要ないよ)
|
|