JavaScript(ES6)、316 323 347
p=>[1,2,4].some(x=>(d=D(Q=[[x&1,x&2,x&4,0,0,0],...p.map(([x,y])=>[x*x,x*y,y*y,x,y,1])]))?[a,b,c]=Q.map((v,i)=>D(Q.map((r,j)=>(r=[...r],r[i]=x*!j,r)))/d):0,D=m=>m[1]?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0):m)&&(d=b*b-4*a*c)?d<0?!b&c==a?'Circle':'Ellipse':'Hyperbola':'Parabola'
マトリックスと行列式の処理に適した言語は、スコアが向上するはずです(APL、J、CJAM、Jelly)
参考文献:円錐の一般的な形式は、5点は円錐決定、線形方程式のシステム、決定基
デカルト平面では、円錐の一般方程式は
A*x*x + B*x*y + C*y*y + D*x + E*y + F = 0
AまたはBまたはCが0に等しくない場合(そうでない場合は直線)
A ... Fは、発見されるべき6つの未知数です。5組の(x、y)を使用して、5つの方程式で線形システムを構築し、スケーリングにより1つの次元を削除できます。つまり、A、B、Cのいずれかが0でない場合、1に設定できます(少なくとも1つが0でないことはわかっています)。
私は3つのシステムを構築して解決しようとします:最初にA = 1を試します。解決できない場合は、B = 1、C。(より良い方法があるかもしれませんが、それが当時のベストです)
A、B、Cの値を使用して、判別式を見て円錐曲線を分類できます。 d=B*B-4*A*C
- d == 0->放物線
- d> 0->双曲線
- d <0->楕円、特に(A == CおよびB == 0)->円
少ないゴルフ
F=p=>(
// Recursive function to find determinant of a square matrix
D=m=>m[1]
?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0)
:m,
// Try 3 linear systems, coefficients in Q
// Five equation made from the paramaters in p
// And a first equation with coefficient like k,0,0,0,0,0,1 (example for A)
[1,2,4].some(
x => (
// matrix to calc the determinant, last coefficient is missing at this stage
Q = [
[x&1, x&2, x&4, 0,0,0] // first one is different
// all other equations built from the params
,...p.map( ([x,y]) => [x*x, x*y, y*y, x, y, 1] )
],
d = D(Q), // here d is the determinant
d && ( // if solvable then d != 0
// add missing last coefficient to Q
// must be != 0 for the first row, must be 0 for the other
Q.map( r=> (r.push(x), x=0) ),
// solve the system (Cramer's rule), I get all values for A...F but I just care of a,b,c
[a,b,c] = Q.map((v,i)=>D(Q.map(r=>(r=[...r],r[i]=r.pop(),r))) / d),
d = b*b - 4*a*c, // now reuse d for discriminant
d = d<0 ? !b&c==a ? 'Circle' : 'Ellipse' // now reuse d for end result
: d ? 'Hyperbola' : 'Parabola'
) // exit .some if not 0
), d // .some exit with true, the result is in d
)
)
テスト
F=p=>[1,2,4].some(x=>(d=D(Q=[[x&1,x&2,x&4,0,0,0],...p.map(([x,y])=>[x*x,x*y,y*y,x,y,1])]))?[a,b,c]=Q.map((v,i)=>D(Q.map((r,j)=>(r=[...r],r[i]=x*!j,r)))/d):0,D=m=>m[1]?m[0].reduce((r,v,i)=>r+(i&1?-v:v)*D(m.slice(1).map(r=>r.filter((a,j)=>j-i))),0):m)&&(d=b*b-4*a*c)?d<0?!b&c==a?'Circle':'Ellipse':'Hyperbola':'Parabola'
console.log=(...x)=>O.textContent+=x+'\n'
;[
[[0, 0], [1, 5], [2, 3], [4, 8], [9, 2]]
,[[1.2, 5.3],[4.1, 5.6], [9.1, 2.5], [0, 1], [4.2, 0]]
,[[5, 0], [4, 3], [3, 4], [0, 5], [0, -5]]
,[[1, 0], [0, 1], [2, 1], [3, 4], [4, 9]]
].forEach(t=>console.log(t.join`|`+' => '+F(t)))
<pre id=O></pre>
circleは、非常に丸い楕円と区別するためにフロートの等価性をチェックする必要があるようです。ここではどのような精度を想定すべきですか?