質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

7回答

409閲覧

診断結果は適当でよいが、組み合わせが同じ場合、何度やっても同じ相性となるプログラムを作成したい

Eston

総合スコア67

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

1クリップ

投稿2018/02/19 09:38

編集2018/02/19 09:45

いつもお世話になっています。

現在rubyで、2つの名前を入力すると、相性を10段階(10、20、・・・、100)で表示するプログラムを作成したいと考えています。

例えば)
・入力値
あなたの名前を入力してください
K
相手の名前を入力してください
M

・出力
相性は60%です

そして、診断結果自体はランダムで生成されるとイメージしていて、それでいて、全く同じ組み合わせを入力すると同じ相性になるということです。

<コード>
puts "あなたの名前を入力してください"
name1 = gets.chomp
puts "相手の名前を入力してください"
name2 = gets.chomp
print "二人の相性は"
p "#{rand(10)}" + "%"#ここの数字はそれほど問題ではありません。

これが現在のコードですが、診断結果はランダムなので、再度同じ名前を入力しても、診断結果は同じになりません。
ご存知の方がいれば、教えていただけると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答7

0

その用途でよく用いられるのはハッシュです。
任意の文字列をハッシュに変換かける事を「ハッシュ化」と呼びます。
ハッシュには様々な用途があり、それに伴い様々な規約が存在します。

今回の質問には要件として「同じ名前を入力すると同じ結果になって欲しい」があります。
これがハッシュの仕様とピタリ一致するのです。

今回紹介するのは、ハッシュの規約の一つであるMD5です。
有名なのでRubyにもライブラリが用意されているようですね。(標準で使えるかな?)
https://docs.ruby-lang.org/ja/latest/class/Digest=3a=3aBase.html

以下はMD5の仕様です

  • 16進数で表現されている
  • 常に32文字に変換される
  • 同じ文字列を変換すると、同じ文字列が登場する
  • 暗号化の仕組みとしては弱いが、仕組みが単純な分速度が出る

例えばabcをMD5に変換すると、必ず'900150983cd24fb0d6963f7d28e17f72'という文字列になります。

Ruby

1require 'digest/md5' 2 3p Digest::MD5.hexdigest('abc') #=> '900150983cd24fb0d6963f7d28e17f72' 4p Digest::MD5.file('ruby-1.8.5.tar.gz').to_s #=> '3fbb02294a8ca33d4684055adba5ed6f'

MD5にハッシュ化された文字列は「16進数」です。
Rubyでは16進数の文字列をhexメソッドを使って簡単に数値に変換できます。

10通りの結果が欲しいのですよね?
結果の数値を% 10で余りを求めれば10パターンの結果になります!


【おまけ】

Twitterでよくある診断は結果が日替わりですよね。
中身を見たわけではないですが、十中八九このテクニックの応用です。

abcという文字列の上に日付データを足してハッシュ値として取り出しているのです。
2018/03/12 - abcみたいな文字列作ってMD5形式に変換…という手法にすれば簡単に日替わりの結果が作れますね。


【追記】コードにしてみた

ちょっとしたコードを書いてみました。

JavaScript

1require 'digest/md5' 2 3a = Digest::MD5.hexdigest('太郎').slice(0, 3).hex 4b = Digest::MD5.hexdigest('花子').slice(0, 3).hex 5result = (a + b) % 11

0%〜100%が出てほしいなら11パターンじゃないですかね?
というわけで% 10ではなく、% 11にしました。

MD5で16進数の文字列にして、一部の文字列だけをsclieで切り出し、hexで数値に変換。

相性診断なので一度足してから% 10で10の余りを求めています。
つまりresultには0 〜 9の数値が格納されています。

投稿2018/02/19 10:06

編集2018/02/19 10:42
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Eston

2018/02/19 10:09

とても詳しい回答ありがとうございます。 私のスキルでは理解するのにもう少し時間がかかりそうですが、とても勉強になります。ありがとうございます。
miyabi-sun

2018/02/19 10:35

ハッシュの説明書きが難解だったので全体的に見直しました。 また、ちょっとしたコードを用意しましたのでそちらを御覧ください。
Eston

2018/02/19 10:40

はい、お気遣いありがとうございます。一つ一つ見直して、勉強したいと思います。 今回は私の説明不足もあり、お手数おかけしました。
退会済みユーザー

退会済みユーザー

2018/02/19 15:13

桁数ちゃんと考えないと、若干偏りませんか?
miyabi-sun

2018/02/19 23:47 編集

> te2jiさん 仰るように1桁は0 - 15なので流石にまずいですね。 2桁で255、3桁になると4095になります。 SFCのソフトの多くは乱数を255個しか用意していませんので意外と2桁で大丈夫でしょう。 3桁以上ならば統計取っても誤差で片付けられる分布になりますので人間にはほぼ知覚出来ないと思います。
退会済みユーザー

退会済みユーザー

2018/02/20 00:13

コメントありがとうございます! *SFC ってなんですか?
miyabi-sun

2018/02/20 00:57

スーパーファミコンです><
退会済みユーザー

退会済みユーザー

2018/02/20 01:03

知りませんでした。256 ってことは結構偏ってたんでしょうね。 全然知覚できませんでしたw ありがとうございました。
guest

0

ruby

1names = %w[あなた 相手].map{|s| 2 puts "#{s}の名前を入力してください" 3 name = gets.chomp 4} 5# あなた + 相手 と 相手 + あなた が同一の結果の場合 6namehash = names.sort.join(',').hash 7# あなた + 相手 と 相手 + あなた が同一の結果とは限らない場合 8# namehash = names.join(',').hash 9 10print '二人の相性は' 11# p 1 + (namehash.to_s.chars.map(&:to_i).sum % 10) 12puts "#{1 + (namehash.to_s.chars.map(&:to_i).reduce(0,:+) % 10)}0%"

投稿2018/02/19 09:50

編集2018/02/19 10:15
asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Eston

2018/02/19 10:10

回答ありがとうございます。 実行結果として undefined method `sum' for [0, 3, 0, 6, 2, 6, 1, 6, 8, 2, 8, 8, 8, 7, 6, 4, 5, 1, 0, 8]:Array (NoMethodError) というエラーが出るので、その原因を解決しようとしているところです。
asm

2018/02/19 10:12

sumは2.4で追加されたメソッドなんですが古いRubyをご利用でしょうか?
Eston

2018/02/19 10:15 編集

失礼しました。Rubyのバージョンを伝えていませんでした。 現在のRubyのバージョンは2.3.0を使用しています。 2.3.0で実行するにはsumではない方法が必要ということですね。
Eston

2018/02/19 10:25

回答の編集ありがとうございます。バージョンまで合わせてくださって、申し訳ないです。 しかし、出る%の値が再び実行すると変わってしまうようです。
Eston

2018/02/19 10:35

かなり詳しいサイトの紹介ありがとうございます。 私がteratailsを始めた当初から、丁寧な回答にいつも感謝しています。 今回は私の説明不足もあり、解決までお手数おかけしました。 ありがとうございました。
guest

0

次のようになるプログラムを書いてみました。
名前の入力を逆にしても同じ相性値になる事、
名前1 と 名前2 の結合結果が同じことでも、異なる名前の組み合わせなら異なる愛称値になる事、
特定の名前の組み合わせの相性値を 100 にすること (ここでは "太朗", "花子" の相性値を 100 にするようにした)

ruby

1equire 'digest/md5' 2 3BASE_TABLE = (0..100).to_a 4 5def my_table 6 table = BASE_TABLE 7 # "太朗", "花子" の相性は 51 だが、それを 100 に調整する 8 table[51] = 100 9 table[100] = 51 10 table 11end 12 13def val(name) 14 Digest::MD5.hexdigest(name).hex % 101 15end 16 17def match(one, two) 18 my_table[(val(one) + val(two)) % 101] 19end 20 21 22while true 23 puts "あなたの名前を入力してください (空入力すると終了します)" 24 name1 = gets.chomp 25 break if name1 == '' 26 puts "相手の名前を入力してください" 27 name2 = gets.chomp 28 puts "二人の相性は#{match(name1, name2)}\n" 29end

イメージ説明

投稿2018/02/19 14:53

編集2018/02/20 11:56
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

randRubyでランダムな数値を得る方法を参考にしました。

文字を整数に変換するために、hashだと実行のたびに変わってしまったので、
ordで変換してみました。

puts "あなたの名前を入力してください" name1 = gets.chomp puts "相手の名前を入力してください" name2 = gets.chomp seed = (name1 + name2).chars.map(&:ord).inject(:+) random_int = Random.new(seed).rand(1..10) puts "二人の相性は#{random_int * 10}%です"

投稿2018/02/19 10:29

編集2018/02/19 10:57
y-doi

総合スコア322

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Eston

2018/02/19 10:39 編集

シンプルな回答ありがとうございます。自分の中で100%の理解にできるよう精進します。
guest

0

(私の読解力が足りないのか)ちょっとよくわからないです。

特に

そして、診断結果自体はランダムで生成されるとイメージしていて、それでいて、全く同じ組み合わせを入力すると同じ相性になるということです。

の部分。

数字はでたらめだけど

(K,M) なら毎回 60% って出るように仕向けること?

場合によってものすごく変わります。

もし、ある条件式があり、それで割り出す...っていうことをしないためにランダムって言っているのか、

完全にランダムでいいのか...

条件式に頼らないっていう意味なら

方法1: 配列( リストでもいいが。 )を用意し、それに適当に決め打ちして定義。 それを使う。

例えば Rubyはわからないのであくまで大雑把ですが、

{ 30, 10, 40, 100, 90 } の要素数5の配列を用意。

で、乱数発行して 乱数 r の位置のデータを表示する。

例えば r = 4 なら 4番目のデータ ( 4 - 1 = 要素数3 ) の 40 を出力する。

っていう風に。

方法2: テキストファイルを定義ファイルとみなして、それに記述されているデータを使う

例えば、

// definition.txt 内として 30 20 10 100 50

とあったら、

乱数 r が 3のとき、3行目の10 を出力...

これは方法1 の定義場所をテキストファイルにしただけ。

毎回同じ条件なら同じ値にする ( 例: (K,M)なら常に100% とする ) なら計算方法を考えたほうがいいかも。

例えば、男側の名前の長さ + 女側の名前の長さ / 2 で割り出すとか。

投稿2018/02/19 10:02

BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Eston

2018/02/19 10:06

私の方こそ書き方が不自然ですみません。 方法1の解釈が一番イメージしているものと近いので、その方面でもう一度書き直してみます。
guest

0

コードは以上ですか?
理由は単純に組み合わせデータを保存していないからです。

現在の処理ですと、Aさん(name1)Bさん(name2)の名前を入力して、その結果をランダムで出力するだけです。
コードを全て読んでいないので、どこからどこまでやっているのかわからないので、判断しかねますが、Aさん、Bさん、結果を保存する配列を作成し、そこにデータを格納します。
そして、再度入力したとき、入力された値が配列通りのものであれば、既に保存してあるデータを出力するようにする形になるかと思います。

コードを記述するにしてもいろいろと対応しなければならないものが多すぎるので、僕には無理です。配列とIF文を組み合わせればできるようになりますので、そちらを調べてみるとよいかもしれません。

投稿2018/02/19 10:01

zigutabi

総合スコア57

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もっと仕様をしっかりしないと回答が難しい気がしますが。。。
均一な分布でなくてよいのであれば、足した文字列を数値化し、10 で割り、余りで分類するのが単純かと。

投稿2018/02/19 09:55

編集2018/02/19 09:55
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問