The Angles of a Triangle (Scientific Expedition) - 三角形の3辺から角度を計算
どんな問題?
The Angles of a Triangle
http://www.checkio.org/mission/triangle-angles/
三角形の3辺の長さから3つの角度を求めよ。
引数は、3辺の長さ。
戻り値は、3つの角度(単位は度)を整数値に丸めて、小さい順にソートしてリストで返す。
計算できない場合は、[0,0,0] を返す。
例題:
checkio(4, 4, 4) == [60, 60, 60] checkio(3, 4, 5) == [37, 53, 90] checkio(2, 2, 5) == [0, 0, 0]
どうやって解く?
いや、だからこれはPythonじゃなくて数学の問題じゃねーか。
なんかこういう定理があった気がするなぁ。またもWikipedia先生の登場だ。
式が分かれば、あとは簡単。
import math def get_angle(a, b, c): return round(math.degrees(math.acos((a ** 2 + b ** 2 - c ** 2) / (2 * a * b)))) def checkio(a, b, c): return sorted(get_angle(*abc) for abc in ((a, b, c), (b, c, a), (c, a, b)))
これで実行。
ValueError: math domain error
あれ、エラー。そうか、計算できない場合は[0,0,0]を返すって書いてあったな。
get_angle()に例外処理を追加。
def get_angle(a, b, c): try: return round(math.degrees(math.acos((a ** 2 + b ** 2 - c ** 2) / (2 * a * b)))) except ValueError: return 0
これでよし。Run&Check!
Your result: [0,0,180] Right result: [0,0,0] Fail: checkio(10,20,30)
あれ、またエラー。3辺の長さが10,20,30ということは、1直線上にある場合か。この場合はValueError例外は出ないのか。
じゃあ、角度に0が含まれているかチェックするようにしよう。
def checkio(a, b, c): result = sorted(get_angle(*abc) for abc in ((a, b, c), (b, c, a), (c, a, b))) return [0, 0, 0] if 0 in result else result
これでOK
でも、なんか、全体に汚いなぁ。degreeに直すとか、数字を丸めるのは、get_angle()の中でやることではないよな。get_angle()の汎用性を損なっている。
全体に書き直してみた。
まとめ
import math def get_angle_from_sides(a, b, c): return math.acos((a ** 2 + b ** 2 - c ** 2) / (2 * a * b)) def checkio(a, b, c): try: angles = [get_angle_from_sides(*abc) for abc in ((a, b, c), (b, c, a), (c, a, b))] result = sorted(round(math.degrees(a)) for a in angles) return [0, 0, 0] if 0 in result else result except ValueError: return [0, 0, 0]
これで公開しておいた。
http://www.checkio.org/mission/triangle-angles/publications/natsuki/python-3/first/
他の人の答え
最初に辺の長さをチェックして、三角形にならない場合は[0,0,0]を返すようにしている人も多かった。
if (a + b <= c) or (a + c <= b) or (b + c <= a): return [0, 0, 0]
最初にチェックしておけば、例外処理は不要になるわけか。