どうも、だいぶごぶさたです。
最近は、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#ですら断念したという)
ちょっと、がんばって作ってみます。
しかし、まだゲームの根幹部分を作ってる段階で、
実装まで険しい道のり・・・。
でもやるぜ。
目指せセミプロプログラマー!!(セミかよ)
コメントする