わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

出力から入力を答える問題

いきなりですが問題です.

以下のコードは,3点(a,b),(c,d),(0,0)を結んでできる三角形の面積が|ad-bc|/2であることに基づいて,2点を固定,1点をコマンドライン引数から獲得して,三角形の面積を求めるプログラムである.
出力が「0.5」となるような,実行コマンドを一つ挙げなさい.

#!/usr/bin/env ruby

x = (ARGV.shift || 2).to_i
y = (ARGV.shift || 4).to_i
t = [[4, 2], [0, 3], [x, y]]

t.map! {|p| [p[0].to_f, p[1].to_f]}

t[0][0] -= t[2][0]
t[0][1] -= t[2][1]
t[1][0] -= t[2][0]
t[1][1] -= t[2][1]
t[2][0] = t[2][1] = 0.0

s = ((t[0][0] * t[1][1] - t[1][0] * t[0][1]) / 2).abs
puts s

私がここの日記で「いきなりですが問題です」と書いたら,すぐ答えを書くという変な慣習を設けていますが,本日も,すぐ答えです.
ソースのファイル名をtriangle.rbとすると,「ruby triangle.rb 3 2」が答えです.
そもそもこの問題は,先週月曜に実施したCプログラミングに関する試験の改題です.試験では当然Cのコードで,コマンドライン引数の与え方と,文字列をint型整数値に変換するatoiの利用,そして出力から入力を推定するのを組み合わせた問題でした*1
解説ですが,「ruby triangle.rb」を実行したらどうなるかを確認することから始めます.デフォルトは2と4ですから,結局,(4,2),(0,3),(2,4)の3点を結んでできる三角形の面積を求めることになり,結果は「3」です.座標は以下の通り.

|ad-bc|/2という公式に気付かなくても,三角形の面積であることを踏まえていれば,(4,2),(0,3),(x,y)の3点を結んでできる三角形の面積が,0.5になるものを求めればいいわけです.代数的にも求められそうですが(絶対値の取り扱いには要注意ですが),図で考えれば一発です.底辺と高さがともに1となるような三角形を見つければいいのです.以下の図で4か所ある「×」ならどこでも同じ面積,0.5です.

これでめでたしめでたしと思って,採点をしていくと,引数が「7 1」や「11 0」というのが出てきました.
こういうときは,実際に引数を与えて動かし,確かにその結果になれば丸にします.そして,実際,0.5と出ました.
全部の採点を終え,解説を書きながら,x座標の値がなぜそんなに大きくても面積が0.5なのか,図を見直してみました.ほどなく,補助線が見えてきました.

この青の斜線と,格子点(x座標,y座標とも整数の座標)との交点なら,いずれも正解なのです.(4,2)と(0,3)を底辺として固定し,残りの頂点が(3,2)でできる三角形の面積は0.5.下の青い斜線上ならどこの点でも,それを残りの頂点と選べば,三角形は0.5です.(7,1)でも,(11,0)でも,満たしています.上側の青い斜線も同様です.
ただし,Rubyの場合はBignumのおかげでいくらでも大きい整数を指定できますが,試験で与えたCのソースは,atoiで変換しているので,int型の範囲内という制約がつきます.

*1:今,見直してみて,そしてここ最近読んだ日記・ブログと合わせて考えると,実行コマンドだけでなく,なぜそれで題意通りになるかを,コードに即して例えば「〜行目で…が代入され」などを書き,答えさせるのがよさそうに思えてきました.来年度の試験のときに,思い出すことにします.