CodeIQ:じゃんけん「グアバ・チョコレート・パイナップル」ゲーム

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「じゃんけん「グアバ・チョコレート・パイナップル」ゲーム」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
【じゃんけん「グアバ・チョコレート・パイナップル」ゲームルール】
  • じゃんけんをして勝った時の手に応じて任意の歩数進みます
  • グーで勝ったら3歩進みます。グ・ア・バ
  • チョキで勝ったら6歩進みます。チ・ヨ・コ・レ・イ・ト
  • パーで勝ったら6歩進みます。パ・イ・ナ・ツ・プ・ル
  • あいこの場合、どちらかが歩数リードしていれば、負けている側が7歩進みます。ア・イ・ス・ク・リ・イ・ム
  • あいこの場合、歩数に差がなければお互い進みません

【入出力サンプル】
標準入力でAさんとBさんのじゃんけんの手がカンマ区切りで5行入力されます
 グーはG, チョキは C, パーは P として入力されます
 (末尾の改行を入れると6行)
G,G
C,C
P,P
G,G
C,P

すべてのじゃんけんの結果, Aさんが勝っている場合は A,差分の歩数 を出力してください
A,9

私のプログラム

Rubyで解答しています。

#!/usr/bin/ruby

JANKEN = {
	"G" => {"G" => 0, "C" => 3, "P" => -6},
	"C" => {"G" => -3, "C" => 0, "P" => 6},
	"P" => {"G" => 6, "C" => -6, "P" => 0},
}

def janken(a, b, cnt)
	ret = JANKEN[a][b]
	if (ret == 0) && (cnt > 0) then
		ret = -7
	elsif (ret == 0) && (cnt > 0) then
		ret = 7
	end
	return cnt + ret
end

def printResult(cnt)
	if cnt > 0 then puts "A," + cnt.to_s
	elsif cnt < 0 then puts "B," + cnt.abs.to_s
	else puts "even"
	end
end

# main
cnt = 0
while line = gets
	line.strip!
	if line.empty? then next end

	a,b = line.split(",")
	cnt = janken(a, b, cnt)
end

printResult(cnt)

解説

特に悩むようなところはありません。素直にプログラムを書けばできます。

ちょっとした工夫

大した工夫ではありませんが、Aの歩数を正の整数、Bの歩数を負の整数で表しています。こうすると0がeven状態なので処理が少し簡潔になります。

JANKEN

この定数がプログラムの本体と言えます。連想配列の連想配列になっていてJANKEN[Aの手][Bの手]とすれば何歩進むのかを返します。あいこの時はとりあえず0を返しておきます。

janken()

この関数で1回分のじゃんけんの結果の移動距離を返します。基本的にJANKEN[Aの手][Bの手]で得た値を返せば良いのですが、あいこの時双方の距離の差が0の場合は7を返す必要があるのでその判断を行うための関数です。

main

標準入力を1行読み込むごとにjanken()を呼び、結果をcntに加算します。標準入力の読み込みが終わったらprintResult()で結果を表示します。

printResult()

引数が正の値ならAの勝ちとして、負の値ならBの勝ちとして結果を出力します。引数が0の時は"even"を出力します。

雑感

ポイントとしては結果を表引きにしておくことでしょうか。if文やswitchでごちゃごちゃ書くよりもわかりやすいので実用的なテクニックと思います。C言語のように連想配列がない場合でも入力値を数値に変換してやれば二次元配列で表現できます。