配列奮闘記

投稿者:           mini naoki4019 投稿日:2017/02/19 01:40

※個人で頑張って奮闘してるだけの日記なので生暖かい目で見てあげてください
※ついでにRmake記法を試してみたかったんです許してください何でもしますから

課題:ジョーカー含む計53枚のトランプからランダムに5枚を引く手段の模索

配列0~52に入れた数字をランダムに入れ替えると解釈

目次----------------------------------------------
----------------------------------------------------





1.とりあえず配列0~52に0~52の数字をそれぞれ入れていくよ

r = 0                                    #whileで繰り返す(repetitionの頭文字)のに使用
deck = createArray()            #deckという変数に配列を用意する魔法の言葉、createArray()
 while r < 53
  deck[r] = r
  r = r + 1
 end

これにより
変数名[0][1][2][3][4][5][6][7]...[52]
deck01234567...52
とすることに成功した
この数字をランダムに入れ替える、つまり
変数名[0][1][2][3][4][5][6][7]...[52]
deck_s(所謂コピー)40194019750...27
というようにしたい、なのでrand関数は使えない(多分)

▲ページの先頭へ▲




2.でもrand関数使えそうじゃない?

使えないって決め付けるのは三流のやることです、考え次第ではどうにかなるでしょう(適当)

使う変数
r ...whileで繰り返すのに使う変数
deck ...[0]~[52]に0~52を順番通りにセットした配列
deck_s ...deck内をランダムに入れ替えた(shuffleの頭文字)配列、言わば今回の目標
r_s ...whileでdeck_sをランダムに入れ替えるのに使う変数

(r,r_s共に0を代入しておく)
rand(53)を使って0~52の数字をランダムに変数a(仮)にセット
↓
while
┃deck[r]の中身がaと同じかどうか検証
┃↓
┃・同じならdeck[r]の中身を-1(0~52ではない数字)に変更、deck_s[r_s]にrを代入、r_sを+1
┃・違うなら特に何も
┃↓
┗rを+1

・・・う~んと?適当に組んだけどこれいろいろおかしいな(´・ω・`)

・rand関数でランダムに数字を呼び出す
・deck[0]~[52]のどこにその数字があるかをwhileで見つけ出し、そのdeckを使い物にならなくする

これを53回繰り返すことで「シャッフルしたあとのデッキ」が完成する、はず・・・


あ、見つけたらrandからやり直しにすればいいのか・・・いきなりスクリプトに起こした方が早そうね

r = 0
deck = createArray()
 while r < 53
  deck[r] = r
  r = r + 1
 end

#-------------------------↓追加↓----------------------------
r_s = 0                            #deck_sに使う配列の変数
a = 0                                        #rand関数で出たものを入れる変数
deck_s = createArray()                    #シャッフル後のデッキの配列 

while r_s < 53                     #deck_sの配列が52を越える、それは[0]~[52]が入った証
r = 0                                          #また繰り返しに使う変数
a = rand(53)

    while r < 53
       if deck[r] == a               #もしランダムに取り出した数aがdeck[0](初回)に入っている0だった場合
         deck[r] = -1                 #deck[0]の中身を-1にして今後検知されないようにする
         deck_s[r_s] = a         #deck_s[0]にランダムに取り出した数a(=0)を代入する
         r_s = r_s + 1           #deck_sの配列の数字が次の段階へ
         r = 53                    #めんどくさいのでもうaの数字探すループ抜けようぜ
      end
     r = r + 1                    #見つかろうか見つからなかろうがとりあえず+1はしようや
    end

end

speak("上から順番に",deck_s[0],"、",deck_s[1],"、",deck_s[2],"、",deck_s[3],"、",deck_s[4],"でした")

なーんで私のスクリプトはこんな複雑に見えるんだ
これで全配列を探し回ってランダムに並び替えることに成功した、これで目標は達成したと思いきや・・・

▲ページの先頭へ▲




3.時間かかり過ぎ問題

speak("はじめるよ")                  #---------------追加--------------
time1 = getLocalCurrentTimeMillisecond()                      #---------------追加--------------
r = 0
deck = createArray()
 while r < 53
  deck[r] = r
  r = r + 1
 end

r_s = 0
a = 0
deck_s = createArray()

while r_s < 53
r = 0
a = rand(53)

    while r < 53
       if deck[r] == a
         deck[r] = -1
         deck_s[r_s] = a
         r_s = r_s + 1
         a = -1
         r = 53
      end
     r = r + 1
    end

end

time2 = getLocalCurrentTimeMillisecond()   #---------------追加--------------
time3 = time2 - time1                  #---------------追加--------------
speak("上から順番に",deck_s[0],"、",deck_s[1],"、",deck_s[2],"、",deck_s[3],"、",deck_s[4],"でした\nこの処理にかかった時間は",time3,"ミリ秒でした")#---------------変更--------------

スクリプトをこのように変更し、処理にかかる時間を計測しました
計測した結果、この処理にかかる時間は900~1200ミリ秒、
秒にして0.9~1.2秒の処理が必要となってしまうのです(´・ω・`)

当然ですね、aに8が入って8が処理されたあと、
もう一度aに8が入ったら全部探した挙句ありませんでした状態ですので(´・ω・`)


さて・・・どうしたものか・・・

































そもそもwhileで探す必要なくない?
まさかの今までの考え全否定である
deck[7]には最初7が入っているとわかってるのになぜ全部探しているんだ・・・?(´・ω・`)

つまりaにランダムで数字を入れたらdeck[a]がaと同じかどうかを検証したいだけだ・・・あれすっごい単純
speak("はじめるよ")
time1 = getLocalCurrentTimeMillisecond()
r = 0
deck = createArray()
 while r < 53
  deck[r] = r
  r = r + 1
 end

#-------------------------↓変更↓----------------------------
r = 0
a = 0
deck_s = createArray()

while r < 53
a = rand(53)
   if deck[a] == a            #もしdeck[a]がa(要約するとまだ選ばれていない)なら
      deck[a] = -1            #deck[a]を-1(言わば使用済み)にする
      deck_s[r] = a         #そしてdeck_s[(初回なら0)]にaを代入する
      r = r + 1           #そしてdeck_sの配列は次のステージへ・・・
   end
end

time2 = getLocalCurrentTimeMillisecond()
time3 = time2 - time1
speak("上から順番に",deck_s[0],"、",deck_s[1],"、",deck_s[2],"、",deck_s[3],"、",deck_s[4],"でした\nこの処理にかかった時間は",time3,"ミリ秒でした")

これで計測した結果、なんと15~50ミリ秒!全く気にならないレベルの高速化に成功!
N(長く)K(苦しい)T(戦いだった)・・・

▲ページの先頭へ▲




まとめ

speak("はじめるよ")
time1 = getLocalCurrentTimeMillisecond()
r = 0
deck = createArray()
 while r < 53
  deck[r] = r
  r = r + 1
 end
r = 0
a = 0
deck_s = createArray()
while r < 53
a = rand(53)
   if deck[a] == a
      deck[a] = -1
      deck_s[r] = a
      r = r + 1
   end
end
time2 = getLocalCurrentTimeMillisecond()
time3 = time2 - time1
speak("上から順番に",deck_s[0],"、",deck_s[1],"、",deck_s[2],"、",deck_s[3],"、",deck_s[4],"でした\nこの処理にかかった時間は",time3,"ミリ秒でした")

今はspeak文で上から5枚を使っているだけですがあとはdeck_sの配列の数字を+1ずつしていくだけで
4人のプレイヤーに均等に配る互いに1枚ずつ引いていく、など
いろんなことが可能になります(´・ω・`)

また、deck[1][0]=1,deck[1][1]="スペードの1" のように更に配列を仕込むことで
speakに表示する際は「スペードの1」と表示するということもできるはずです(`・ω・´)
↑を応用したものは後日じわじわと仕上げて行きます

本格的なトランプゲームもこれなら作れますねぇ・・・

▲ページの先頭へ▲

【追記】
a = "53万"
speak("私の戦闘力数は" + a + "です") ・・・①
speak("私の戦闘力数は" , a , "です") ・・・②
この①と②、同じ処理なんですね(´・ω・`)
なんか見た目がすっきりするので下の方が好きです(´・ω・`)

それでは、ここまで閲覧ありがとうございました三 ヾ(⌒(厂 ˙ω˙ )厂 ウェーイ

コメントする

コメントするには、ログインする必要があります。

コメント一覧

            mini mosmoss(投稿日:2017/02/19 12:16, 履歴)
cfm_さんのシャッフルの関数
https://rmake.jp/wikis/391/
Cdv30200 aoi icon mini aoihikawa(投稿日:2017/02/19 12:18, 履歴)
同じ発想の関数が
既にあったのですね(w
            mini mosmoss(投稿日:2017/02/19 12:22, 履歴)
さすがお二人です!!
           mini naoki4019(投稿日:2017/02/19 12:56, 履歴)
既にシャッフルの関数あったんですかぁぁぁぁぁぁぁぁぁ_(:3 」∠)_
なぜ先に調べておかなかったんだ・・・(´;ω;`)

お二人ともわざわざありがとうございます_(:3 」∠)_
            mini mosmoss(投稿日:2017/02/19 13:00, 履歴)
一生懸命頑張った人に、ニヤニヤしながら関数教えるの楽しいでゲス(^ω^)
ちなみに追記のやつ、私①派です、なぜなら…
時々カンマにピリオドが混じってくるからです(´;ω;`)
           mini naoki4019(投稿日:2017/02/19 14:00, 履歴)
なんて悪魔的な行為だ・・・!
ピリオドと見分けがつかないというのはつらいですね・・・
+がなかなかにでかくてごちゃごちゃしちゃうのでやっぱり②派です(`・ω・´)
            mini mosmoss(投稿日:2017/02/19 15:00, 履歴)
ナイスな反応でゲス(^ω^)
みなさんのスクリプト見てるとほとんど②派のようですね('ω'っ)3
Cdv30200 aoi icon mini aoihikawa(投稿日:2017/02/19 12:12, 履歴)
純粋にシャッフルして
上から引く、でも早くできそう

time1 = getLocalCurrentTimeMillisecond()

#下準備
deck = createArray()

i = 0; ilen = 53
while i < ilen
  deck[i] = i
  i = i + 1
end

#シャッフル
r = 0; n = 0

i = 0; ilen = 53
while i < ilen
  r = rand(ilen - i) + i
  n = deck[i]
  deck[i] = deck[r]
  deck[r] = n
  i = i + 1
end

#必要な枚数取り出す
deck_s = createArray()

i = 0; ilen = 5
while i < ilen
  deck_s[i] = deck[i]
  i = i + 1
end

#結果表示
time2 = getLocalCurrentTimeMillisecond()
time3 = time2 - time1

speak(deck_s[0] + ":" + deck_s[1] + ":"  + deck_s[2] + ":"  + deck_s[3] + ":"  + deck_s[4] + "\n time" + time3)