某サイトとは....
みなさんが一度は使用したことがあるのではと思います(偏見w
名前を入れると、勝手に診断結果をくれる便利(?)なものです
今回使ってみた診断は、文字からランダムに文章(?)を作ってくれます
診断したい名前:hmhm
診断結果:マジギレ一目惚れ女がお前家庭的な大貧民負けて大貧民負けて俺大貧民負けて作った
なんとなくの推測アルゴリズム
おいしいパスタ
作った
お前
家庭的な
女が
タイプの
俺
一目惚れ
大貧民負けて
マジギレ
の10個の文字列をランダムに出しているだけじゃないかと....
Coding
必要な変数定義
let array = ["おいしいパスタ", "作った", "お前", "家庭的な", "女が", "タイプの", "俺", "一目惚れ", "大貧民負けて", "マジギレ"]
var result: [String] = []
let output = 10
- 使う文字を入れた配列
array
を用意 - 結果を入れる配列
result
を用意 - 本家ではおそらく10個の単語を出力してそうだったので、出力する数
output
を10として用意
乱数で文字列を選択
for _ in 0..<output {
let random = Int(arc4random_uniform(UInt32(array.count)))
result.append(array[random])
}
print(result.reduce("", +))
- ループを出力する数だけ実行
- swiftで乱数を生成するとなると
arc4random_uniform()
が良さげなので使用 - 乱数の範囲は、0から使う文字を入れた配列
array
の個数までに設定 - 生成された乱数の場所の文字列を
result
に格納 -
reduce
で配列内の文字を合成
実行結果
func sindanmaker() {
let array = ["おいしいパスタ", "作った", "お前", "家庭的な", "女が", "タイプの", "俺", "一目惚れ", "大貧民負けて", "マジギレ"]
var result: [String] = []
let output = 10
for _ in 0..<output {
let random = Int(arc4random_uniform(UInt32(array.count)))
result.append(array[random])
}
print(result.reduce("", +))
}
sindanmaker()
// result print
お前マジギレマジギレマジギレ一目惚れお前お前マジギレ作ったタイプの
ふむふむ
とりあえず成功!
成功したので、これで終わりま....せん!w
問題点
arc4random()
が毎回違う乱数を生成します
そのため実行するたびに結果が変わります
sindanmaker()
sindanmaker()
// result print
マジギレおいしいパスタ俺家庭的なおいしいパスタお前家庭的なおいしいパスタ一目惚れ大貧民負けて
おいしいパスタ作った家庭的な大貧民負けておいしいパスタ家庭的なおいしいパスタタイプのタイプの一目惚れ
普通はいいことなのですが、本家サイトでは、同じ名前を入れると同じ結果が返って来ます
本家に合わせるためにそこまでやってみます
Fixed coding
入力された値からhash値をとる
いろいろ考えた末、入力された文字列からhash値を得て、それを元に診断結果を作ろうかなと
let str: String // 入力値
var hash = str.hashValue
swiftに元からあるメソッドを使っていきます
これでString型をInt型にすることができました
let str: String = "hmhm"
var hash = str.hashValue // 4799450094189775535
このように入力された文字によって固有の値が出て来ます
hash値の変換
let num = Int(log10(Double(hash)) + 1)
if num < 10 {
return
}
hash値の桁数を取得します
-
log10()
メソッドで10の何乗かを取得 - 桁数はそれに+1した数になります
- それをIntで整数化します(少数第一位のくり上がりを気にする場合は、ここで
floor
などでで切り捨てすべきでしたね...)
let round = Int(powf(10, Float(num - 10)))
let prefix = hash / round
let suffix = hash - prefix * round
var value = prefix + suffix
ここが一番悩みました...
本家サイトがどうやっているのかわからないのですが、自分流でw
- hash値の桁数から出力分の10桁を引いた数分、10をべき乗
powf
していきます - hash値の桁数を上から10桁分の数値におとします
prefix
- hash値の上から10桁を抜いた数を取得します
suffix
- それを足します(ここは自己流ですw簡単に10桁にするためにこれでよいかなと....)
let str: String = "hmhm"
var hash = str.hashValue // 4799450094189775535
let round = Int(powf(10, Float(num - 10))) // 1000000000
let prefix = hash / round // 4799450094
let suffix = hash - prefix * round // 189775535
var value = prefix + suffix // 4989225629
とりあえず、10桁の数値ができました
変数定義
let array = ["おいしいパスタ", "作った", "お前", "家庭的な", "女が", "タイプの", "俺", "一目惚れ", "大貧民負けて", "マジギレ"]
var result: [String] = []
let output = 10
先ほどと同じです
文字列を選択
for _ in 0..<output {
let random = value % 10
value = value / 10
result.append(array[random])
}
print(result.reduce("", +))
先ほどhash値から求めた10桁の数字を使います
- 10桁の数字を10で割った余りを計算(1の位の値を取得)
- 10桁の数字を10で割る(10の位の数値を1の位にするため)
- 結果の配列に足していく
var value = prefix + suffix // 4989225629
for _ in 0..<output {
let random = value % 10
print("random: \(random)")
value = value / 10
print("value: \(value)")
result.append(array[random])
}
// print
random: 9
value: 498922562
random: 2
value: 49892256
random: 6
value: 4989225
random: 5
value: 498922
random: 2
value: 49892
random: 2
value: 4989
random: 9
value: 498
random: 8
value: 49
random: 9
value: 4
random: 4
value: 0
10桁だった数字が減っていくのと、random
に1の位が代入されているのがわかると思います
random
に入った数値の場所を、文字列の配列array
から取り出していきます
実行結果
func sindanmaker_fixed(str: String) {
var hash = str.hashValue
let num = Int(log10(Double(hash)) + 1)
if num < 10 {
return
}
let round = Int(powf(10, Float(num - 10)))
let prefix = hash / round
let suffix = hash - prefix * round
var value = prefix + suffix
let array = ["おいしいパスタ", "作った", "お前", "家庭的な", "女が", "タイプの", "俺", "一目惚れ", "大貧民負けて", "マジギレ"]
var result: [String] = []
let output = 10
for _ in 0..<output {
let random = value % 10
value = value / 10
result.append(array[random])
}
print(result.reduce("", +))
}
sindanmaker_fixed(str: "hmhm")
// result print
マジギレお前俺タイプのお前お前マジギレ大貧民負けてマジギレ女が
とりあえず診断結果は出てる!
肝心なのはもう一度同じ名前でやって同じ結果になるか...
sindanmaker_fixed(str: "hmhm")
sindanmaker_fixed(str: "hmhm")
// result print
マジギレお前俺タイプのお前お前マジギレ大貧民負けてマジギレ女が
マジギレお前俺タイプのお前お前マジギレ大貧民負けてマジギレ女が
やったー!
違うのもやってみよう
sindanmaker_fixed(str: "hmhmsh")
// result print
一目惚れ大貧民負けて作った大貧民負けてお前大貧民負けて作った俺大貧民負けて女が
大丈夫そう!
ということでこれで終われる!
最後に
ながながと書いてしまいましたが、読んでいただきありがとうございます
書いてる途中で、「ここは判定が足りなかったorz」などとなりましたが...
とりあえず、(自己流ですが)某サイトのようなアルゴリズムを作れたのではないかなと