yuki8634
@yuki8634 (yuki kawakita)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

もっといいコードを教えてください

解決したいこと

現在プログラミングを勉強しており、rubyのカリキュラムを終えたので、
誕生日から星座を調べるプログラムを作成しました。
-仕様-
 - 誕生日を入れると星座が出力される
 - 存在しない日(2/31など)を選択すると値が正しくありませんと出る

自分で製作したプログラム

def jan
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 19 then
    puts "あなたは山羊座です"
  elsif input <=31 then
    puts "あなたは水瓶座です"
  else
    puts "値が正しくありません"
  end
end
def feb
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 18 then
    puts "あなたは水瓶座です"
  elsif input <=29 then
    puts "あなたは魚座です"
  else
    puts "値が正しくありません"
  end
end
def mar
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 20 then
    puts "あなたは魚座です"
  elsif input <=31 then
    puts "あなたは牡羊座です"
  else
    puts "値が正しくありません"
  end
end
def apr
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 19 then
    puts "あなたは牡羊座です"
  elsif input <=30 then
    puts "あなたは牡牛座です"
  else
    puts "値が正しくありません"
  end
end
def may
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 22 then
    puts "あなたは牡牛座です"
  elsif input <=31 then
    puts "あなたは双子座です"
  else
    puts "値が正しくありません"
  end
end
def jun
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 21 then
    puts "あなたは双子座です"
  elsif input <= 30 then
    puts "あなたは蟹座です"
  else
    puts "値が正しくありません"
  end
end
def jul
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 22 then
    puts "あなたは蟹座です"
  elsif input <=31 then
    puts "あなたは獅子座です"
  else
    puts "値が正しくありません"
  end
end
def aug
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 22 then
    puts "あなたは獅子座です"
  elsif input <=31 then
    puts "あなたは乙女座です"
  else
    puts "値が正しくありません"
  end
end
def sep
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 22 then
    puts "あなたは乙女座です"
  elsif input <=30 then
    puts "あなたは天秤座です"
  else
    puts "値が正しくありません"
  end
end
def oct
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 23 then
    puts "あなたは天秤座です"
  elsif input <=31 then
    puts "あなたは蠍座です"
  else
    puts "値が正しくありません"
  end
end
def nov
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 22 then
    puts "あなたは蠍座です"
  elsif input <=30 then
    puts "あなたは射手座です"
  else
    puts "値が正しくありません"
  end
end
def dec
  puts "あなたの誕生日を教えてください"
  input = gets.to_i
  if input <= 21 then
    puts "あなたは射手座です"
  elsif input <=31 then
    puts "あなたは山羊座です"
  else
    puts "値が正しくありません"
  end
end

puts "あなたの誕生月を入れてください"
input = gets.to_i
case input
when 1 then
  jan
when 2 then
  feb
when 3 then
  mar
when 4 then
  apr
when 5 then
  may
when 6 then
  jun
when 7 then
  jul
when 8 then
  aug
when 9 then
  sep
when 10 then
  oct
when 11 then
  nov
when 12 then
  dec
else 
  puts "値が正しくありません"
end

1月から12月までの12個のアクションを定義しており、同じ内容を繰り返しているので、もっとシンプルにしたいです。現在アクションの中に
puts "あなたの誕生日を教えてください" input = gets.to_iを入れていますが、
puts "あなたの誕生月を入れてください" input1 = gets.to_i puts "あなたの誕生日を教えてください" input2 = gets.to_iと最初に月と日を2つの変数に代入したいです。
どんなプログラムにしたら良いか教えていただけると大変嬉しく存じます。

0

色々改善したほうが良さそうな部分はありますが、一先ず回答します。

やり方は色々ありますが、今のコード体系を崩さないよう加味すると、
単純に入力部分を関数で切り分けるのが良いのではないでしょうか。

    # 誕生日の(mm/dd)を格納する変数を定義し、関数を呼び出す
    month_of_birth, day_of_birth = input_birthday
    
    # 誕生日の(mm/dd)を入力する関数
    def input_birthday()
      puts "あなたの誕生月を入力してください"
      month_of_birth = gets.to_i
      puts "あなたの誕生日を入力してください"
      day_of_birth = gets.to_i
      return  month_of_birth, day_of_birth
    end
1Like

星座情報は配列などでデータ化して、ループ処理するといいですよ。
Dateを使うと大小比較ができるので楽です。

require 'date'

YEAR = 2004  # 2月29日生れをエラーにしないように閏年を選ぶ
sign = [
  ['山羊座', Date.new(YEAR, 1, 19)],
  ['水瓶座', Date.new(YEAR, 2, 18)],
  ['魚座',   Date.new(YEAR, 3, 20)],
  ['牡羊座', Date.new(YEAR, 4, 20)],
  ['牡牛座', Date.new(YEAR, 5, 22)],
  ['双子座', Date.new(YEAR, 6, 21)],
  ['蟹座',   Date.new(YEAR, 7, 22)],
  ['獅子座', Date.new(YEAR, 8, 22)],
  ['乙女座', Date.new(YEAR, 9, 22)],
  ['蠍座',   Date.new(YEAR, 10, 23)],
  ['天秤座', Date.new(YEAR, 11, 22)],
  ['射手座', Date.new(YEAR, 12, 21)],
  ['山羊座', Date.new(YEAR, 12, 31)],
]

puts "あなたの誕生月を入力してください"
month = gets.to_i
puts "あなたの誕生日を入力してください"
day = gets.to_i

if Date.valid_date?(YEAR, month, day)
  birthday = Date.new(YEAR, month, day)
  puts "あなたは#{sign.find{|name, date| birthday <= date}[0]}です"
else
  puts "誕生日が正しくありません"
end
3Like
p "貴方の誕生日を入力して下さい 例:3月3日 → 0303"
input = gets
birthday = Date.parse("2000#{input}") #パース出来ない日時だとココでエラーが起きる。うるう年をベースにすることで、2月29日に対応
date_set = [
	{sign: '山羊座', start_date: Date.parse('20000101'), end_date: Date.parse('20000119')},
	{sign: '水瓶座', start_date: Date.parse('20000120'), end_date: Date.parse('20000218')},
	{sign: '魚座', start_date: Date.parse('20000219'), end_date: Date.parse('20000320')},
	{sign: '山羊座', start_date: Date.parse('20001222'), end_date: Date.parse('20001231')},
] #長いのでデータは省略しています
result = date_set.find{|d| d[:start_date] <= birthday && d[:end_date] >= birthday }
p result ? "貴方は#{result[:sign]}です" : '何かしらのエラーが起きました'

追記。上記だと入力が330とかでも普通にパースが通ってしまうので、

p "貴方の誕生月を入力して下さい 例:2月→2"
input_month = gets.to_i
p "貴方の誕生日を入力して下さい 例:10日→10"
input_date = gets.to_i
birthday = Date.parse("2000-#{input_month}-#{input_date}")

とかの方が予期せぬ入力を防げる可能性がたかいかもです。

1Like

個人的には Range を使うのが好きですね。

require 'date'

data = [
  {name: '山羊座', dates: Date.new(2000, 1, 1) .. Date.new(2000, 1, 19)},
  # 略
]

puts 'あなたの誕生月を教えてください'
month = gets.to_i
puts 'あなたの誕生日を教えてください'
day = gets.to_i

birthday = Date.new(2000, month, day) rescue nil
result = data.find {|x| x[:dates].include? birthday}
puts result&.then {|x| "あなたは#{x[:name]}です"} || '値が正しくありません'
3Like

いろんな回答をいただきありがとうございます!
まだ勉強していないアクションなどたくさんあり、まだ完全に理解できていませんが、
こういう考え方があったのか!とすごく参考になりました。
1つの目的を持つプログラムを作るのに、いろんな方法があること学べてよかったです。

0Like
require "date"
puts "あなたの誕生月を入れてください"
m = gets.to_i
puts "あなたの誕生日を教えてください"
d = gets.to_i
if !Date.valid_date?(2000, m, d)
	puts "値が正しくありません"
else
	date = [20,19,21,20,21,22,23,23,23,24,23,22] # 開始日(index = 月-1)
	sign = ["水瓶座", "魚座", "牡羊座", "牡牛座", "双子座", "蟹座", "獅子座", "乙女座", "天秤座", "蠍座", "射手座", "山羊座"]
	puts "あなたは#{sign[date[m-1]<=d ? m-1 : m-2]}です"
end
2Like

require "date"

DATA = %w[
  おひつじ座(牡羊座)
  Aries
  03-21 04-19

  おうし座(牡牛座)
  Taurus
  04-20 05-20

  ふたご座(双子座)
  Gemini
  05-21 06-21

  かに座(蟹座)
  Cancer
  06-22 07-22

  しし座(獅子座)
  Leo
  07-23 08-22

  おとめ座(乙女座)
  Virgo
  08-23 09-22

  てんびん座(天秤座)
  Libra
  09-23 10-23

  さそり座(蠍座)
  Scorpio
  10-24 11-22

  いて座(射手座)
  Sagittarius
  11-23 12-21

  やぎ座(山羊座)
  Capricorn
  12-22 01-19

  みずがめ座(水瓶座)
  Aquarius
  01-20 02-18

  うお座(魚座)
  Pisces
  02-19 03-20
]


loop do 
  puts "あなたの誕生年を入れてください"
  year = gets.to_i
  puts "あなたの誕生月を入れてください"
  month = gets.to_i
  puts "あなたの誕生日を入れてください"
  day = gets.to_i
  birthday = Date.parse([year, month, day].join("-")) rescue nil
  
  if birthday
    name_ja, name_en, * = DATA.each_slice(4).find do |slice|
      from, to = slice.last(2)
      from = Date.parse("#{birthday.year}-#{from}")
      to = Date.parse("#{birthday.year}-#{to}")
    
      (from..to).cover?(birthday)
    end
    puts "あなたは#{name_ja}[#{name_en}] です"
    break
  else
    puts "日付が正しくありません"
  end
end
0Like

@yulianess23 さん、すごくわかりやすくて簡潔なプログラムだったので、早速コピペしてターミナルで動かしてみました!開始日を配列に入れるという方法がとてもスマートだなと思いました:clap:

0Like

Your answer might help someone💌