CodeIQ:夢世界からの挑戦状 上級ステージ~キミトツナガルパズル『18』コラボ問題~

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「夢世界からの挑戦状 上級ステージ~キミトツナガルパズル『18』コラボ問題~」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
『18』では、同種のジェムをたくさんつなぐことで敵に与えるダメージがアップします。
また、ジェムの属性と敵の属性の相性によっても与えるダメージが変化します。
攻撃力と属性のバランスを考慮して、もっとも有効な属性を見つけてください。

【属性の相性】
属性による相性は次の通りです。
●敵の属性が『火』の場合
『火』属性で攻撃→攻撃力の値と同じダメージ
『水』属性で攻撃→攻撃力の値の2倍のダメージ
『木』属性で攻撃→攻撃力の値の半分のダメージ

●敵の属性が『水』の場合
『火』属性で攻撃→攻撃力の値の半分のダメージ
『水』属性で攻撃→攻撃力の値と同じダメージ
『木』属性で攻撃→攻撃力の値の2倍のダメージ

●敵の属性が『木』の場合
『火』属性で攻撃→攻撃力の値の2倍のダメージ
『水』属性で攻撃→攻撃力の値の半分のダメージ
『木』属性で攻撃→攻撃力の値と同じダメージ

☆注意☆
●攻撃力の値を半分にする際、小数点以下は切り捨ててください。
 たとえば、攻撃力が1001の場合、半分にすると500.5ではなく、切り捨てて500としてください。
●最も有効な属性が複数ある場合、出力の優先順位は『火』・『水』・『木』としてください。
 『火』→『F』、『水』→『W』、『木』→『T』とすると、たとえば『火』と『木』が有効な場合は『FT』と出力してください。
 『TF』という出力は不正解とします。

私のプログラム

Pythonで解答しています。

#!/usr/local/bin/python3

import fileinput
from math import floor

Types = ["F", "W", "T"]

Effect = {
	#敵   火   水   木
	Types[0]: (1.0, 2.0, 0.5),
	Types[1]: (0.5, 1.0, 2.0),
	Types[2]: (2.0, 0.5, 1.0),
}

def selAttack(en, bd):
	ef = Effect[en]
	dm = [floor(ef[i]*bd[i]) for i in range(len(bd))]

	mx = max(dm)

	ret = ""
	for i,d in enumerate(dm):
		if d == mx:
			ret += Types[i]
	return ret

if __name__ == "__main__":
	for i,line in enumerate(fileinput.input()):
		line = line.strip()
		if not line:
			continue

		if i == 0:
			enemy = line
		elif i == 1:
			bd = list(map(int, line.split(" ")))
		else:
			break

	ret = selAttack(enemy, bd)
	print(ret)

解説

普通にやれば解ける問題です。

selAttack()

プログラムの本体です。引数に敵の属性とダメージのリストを受け取って、最大の効率となる攻撃属性を返します。

ダメージの効率はEffectテーブルで定数定義しています。これはキーが敵の属性F、W、Tでそれぞれの攻撃が敵の属性F、W、Tに対して何倍になるかを値に取ります。引数の敵の属性を与えることでダメージ効率を取得します。
次に取得したダメージ効率と入力値のダメージを掛け合わせて実際のダメージを算出し、仕様通り端数を切り捨てます。
ダメージが決定したら最大ダメージを取得し、F、W、Tのダメージで最大ダメージと同じものを結果のリストに挿入して返します。

雑感

実は私はこの問題をPython、Haskell、Fortran95、Rubyで解いています。
ちょっと思い立ってHaskellをやってみようと思い、手ごろだったのでこの問題を実装してみたのですが非常に苦労しました。仕事で最初に覚えたCは別としてC++もJavaもPHPもPythonもJavaScriptもC#もこんなに苦労しなかったよなぁと思い、それを確認するためにFortoran95とRubyでもやってみたというわけです。
実際、Rubyは全然苦労せずにできましたし、Fortran95も30分かそこらでできました。結局の所Haskellは投げ出してこれ以降Rubyに手をつけたという状態になっています。
Pythonでもmap()、filter()、reduce()に代表される関数型操作はあって普通に使っていたので結構いけるかと思っていたのですが……。