※この記事は7年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。
どうも、だいぶごぶさたです。
最近は、Swiftに挑戦しております。
(ゲーム作れるようになりたい)
ってわけで、表記の件だが、
今までどのプログラムでもやったことなかったから、
どんなアルゴリズムでやればいいかわからんかった。
なんで、いろいろ調べて、確立抽選の方法はあったが、
同確立のものを含むものはなかった。
応用してなんとかできたので、方法を公開しようかと。
下記手順でやる。
- 1、商品名と、確立の数値の列挙型を作り、関連付ける。
- 2、列挙型を、case単体が入った配列にし、確立数値がkeyの辞書にする。
- 3、抽選ボックスを作る
まず商品名と確立の列挙型、その関連付け
// 出現率基本 enum BaseRatioList: Float { case Empty = 0.0, ratio0250 = 25.0, ratio0200 = 20.0, ratio0100 = 10.0, ratio0050 = 5.0, ratio0010 = 1.0, ratio0005 = 0.5, ratio0001 = 0.1; } // 商品名リスト enum PrizeList: String { case Empty = "はずれ", HinokiShield = "ひのきのたて", HinokiRod = "ひのきのぼう", HinokiBath = "ひのきのふろ", MithrilSword = "ミスリルソード", MithrilGauntlet = "ミスリルのこて", GenjiGauntlet = "源氏の籠手", MastorSword = "マスターソード"; // 商品によって確立を返すメソッド func prizeByRatio() -> Float { switch self { case .Empty: return BaseRatioList.ratio0050.rawValue; case .HinokiShield: return BaseRatioList.ratio0200.rawValue; case .HinokiRod: return BaseRatioList.ratio0200.rawValue; case .HinokiBath: return BaseRatioList.ratio0200.rawValue; case .MithrilSword: return BaseRatioList.ratio0050.rawValue + BaseRatioList.ratio0100.rawValue; case .MithrilGauntlet: return BaseRatioList.ratio0050.rawValue + BaseRatioList.ratio0100.rawValue; case .GenjiGauntlet: return BaseRatioList.ratio0010.rawValue * 4; case .MastorSword: return BaseRatioList.ratio0010.rawValue; } } }
これで、商品と、その確立を定義できた。
続いて、列挙型を配列にして、辞書にする方法。
デフォルトではできないので、
下記エントリのものを使い、下記のようにする
●Swift3.0版、Enumのcaseを配列で返すProtocol Extension - Qiita
public protocol EnumEnumerable { associatedtype Case = Self } public extension EnumEnumerable where Case: Hashable { private static var iterator: AnyIterator<Case> { var n = 0 return AnyIterator { defer { n += 1 } let next = withUnsafePointer(to: &n) { UnsafeRawPointer($0).assumingMemoryBound(to: Case.self).pointee } return next.hashValue == n ? next : nil } } public static func enumerate() -> EnumeratedSequence<AnySequence<Case>> { return AnySequence(self.iterator).enumerated() } public static var cases: [Case] { return Array(self.iterator) } public static var count: Int { return self.cases.count } } ~ 中略 ~ // 商品名リスト // 列挙型名に、extentionを追加している enum PrizeList: String, EnumEnumerable { case Empty = 0, ~ 中略 ~ // 確立の数値をkeyにして、caseを引き出せる辞書を返すメソッド func prizeByRatioList() -> Dictionary<Int, Array<PrizeList>> { let casesOnly = PrizeList.cases; var ratios = Dictionary<Int, Array<PrizeList>>(); for caseSingle in casesOnly { var inList = Array<PrizeList>(); if let inDic = ratios[Int(caseSingle.prizeByRatio() * 100)] { // 同確立がすでにある場合、配列を取り出す inList = inDic; } // 確立数値をkeyに、配列を突っ込む inList.append(caseSingle); ratios[Int(caseSingle.prizeByRatio() * 100)] = inList; } // 同確立のものを、key値を合算して、辞書に入れなおす。 for (key, value) in ratios { if value.count > 1 { // 配列要素が、1個のときは、やる必要ないので、2個以上の時 ratios[key * value.count] = value; ratios[key] = nil; } } return ratios; } }
これで、確立の数値をkeyにした、case型配列の辞書ができるようになった。
では、実際に使ってみようと。
class GameViewController: UIViewController { // 確立辞書の変数を用意 let prizeRatioList = PrizeList.Empty.prizeByRatioList(); override func viewDidLoad() { super.viewDidLoad() // 商品名を定義 var prize: PrizeList = PrizeList.Empty; // 1万を最大値にとる乱数 let prizeNo = arc4random_uniform(10000) var k = 0; for (key, prizeList) in self.prizeRatioList { // kを使ってるのは、重なり分を解消するため k = k + key; if Int(prizeNo) < k { // 確立で取得できたので、同確立内でどれがあたるかを取得 let innerNo = arc4random_uniform(UInt32(prizeList.count)); prize = prizeList[Int(innerNo)]; break; } } if prize == PrizeList.Empty { print("残念!\(prize.rawValue)"); } else { print("おめでとう!\(prize.rawValue)が当たりました!"); } } }
こんな感じで使う。
ちなみに確立の部分は、下記エントリを参考にさせていただきました。
●Swiftで抽選マシン(ガチャ)を作ってみる その1 - Qiita
今回はけっこう勉強になったばい。
Swiftはなんというか、スクリプト言語に近い感覚で書けるので、
本当に、Webデベロッパ向け言語だなと痛感してます。
わかりやすい。
やっぱオブジェクト指向言語、敷居高いからね・・・。(C#ですら断念したという)
ちょっと、がんばって作ってみます。
しかし、まだゲームの根幹部分を作ってる段階で、
実装まで険しい道のり・・・。
でもやるぜ。
目指せセミプロプログラマー!!(セミかよ)
コメントする