コンテンツへスキップ

【Ruby基礎】AtCoder Beginner Contest 056 A – HonestOrDishonest

  • by

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。
基本的にはAtCoderというプログラミングコンテスト(競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針)
メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

■問題

●出典

AtCoder Beginner Contest 056のA問題
https://atcoder.jp/contests/abc056/tasks/abc056_a

●問題文

シカのAtCoDeerくんとTopCoDeerくんが「正直者か嘘つきか」ゲームをしています。 このゲームでは、正直者は常にほんとうのことを言い、嘘つきは常に嘘を言います。 文字 a と b が入力として与えられます。これらはそれぞれ HD のどちらかです。

a=H のとき、AtCoDeerくんは正直者です。 a=D のとき、AtCoDeerくんは嘘つきです。 b=H のとき、AtCoDeerくんは「TopCoDeerくんは正直者だ」と発言しています。 b=D のとき、AtCoDeerくんは「TopCoDeerくんは嘘つきだ」と発言しています。

これらから判断して、TopCoDeerくんが正直者かどうか判定してください。

●制約

  • a=H または D
  • b=H または D

●入力

入力は以下の形式で標準入力から与えられる。

a b

●出力

TopCoDeerくんが正直者なら H を、嘘つきなら D を出力せよ。

■回答

●愚直に書く

愚直に考えると、条件分岐を素直に書いていけば良いかな…?
まずa=Hの場合はbをそのまま出力すれば良い。
そしてa=Dの場合には条件分岐がもう一個出てきて、b=HならDと表示、b=DならHと表示すれば良い、はず。

a, b = gets.split
if a == "H"
  puts b
else
  if b == "H"
    puts "D"
  else
    puts "H"
  end
end

通った!

今日は別アプローチを先に思いついたので、メソッド化の前に別アプローチを書く。

●リファクタリング/別アプローチ

Hを1、Dを-1とすると、積の結果がそのまま回答になるのでは。

a, b = gets.split
a == "H" ? a = 1 : a = -1
b == "H" ? b = 1 : b = -1
puts a * b == 1 ? "H" : "D"

通った!
面白い考え方で解けたけど、なんかもうちょっとスマートな書き方にできそうな気はする…。

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

2つ目の方の考え方をメソッド化してみる。

def main
  a, b = read_str
  puts conversion(a, b)
end

def is_honest?(a)
  a == "H" ? 1 : -1
end

def is_truth?(b)
  b == "H" ? 1 : -1
end

def conversion(a, b)
  is_honest?(a) * is_truth?(b) == 1 ? "H" : "D"
end

def read_str
  gets.split
end

main

通った!

●他の方の回答例

激短い書き方があった…。
そもそも今回は入力が4パターンしかないので、全パターンから逆算して想定するべきだった。
HHDDならHで、HDDHならDなので、例えば下記で済む。

a, b = gets.split
puts a == b ? "H" : "D"

あと面白いなと思った考え方は、
入力のパターンはHHDDHDDHなので、uniqして要素が1つになれば(すなわち元がHHDDであれば)H、ならなければ(要素が2つ、すなわち元がHDDHであれば)D、というもの。
つまりこう。

a = gets.split
puts a.uniq.size == 1 ? "H" : "D"

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

自分の頭の固さに参ったけど、他の回答を見てものすごく勉強になった。