Scala 255: 224
object P extends App{
val(m,p)=(args(0).split("[^0-9-.]").filter(!_.isEmpty)).map(_.toFloat)splitAt 2
def v(l:Array[Float])=(l(1)-m(0)*l(0)-m(1))*(l(3)-m(0)*l(2)-m(1))<=0
println((p.drop(p.size-2)++p).sliding(4,2) exists v)}
Using splitAt, inspired by Howard. :) Before:
object P extends App{
val f=args(0).split("[^0-9-.]").filter(!_.isEmpty)
val m=f.take(2).map(_.toFloat)
val p=f.drop(2).map(_.toInt)
def v(l:Array[Int])=(l(1)-m(0)*l(0)-m(1))*(l(3)-m(0)*l(2)-m(1))<=0
println((p.drop(p.size-2)++p).sliding(4,2).exists(v))
}
How:
val f=args(0).split("[^0-9-.]").filter(!_.isEmpty)
- Line 2 just splits and filters away everything which isn't part of float or int, since we don't need '(' and ',' and such to identify our parameters - position is enough.
- m is shorthand for mn in m*x+n, the values m and n are floats.
- p is the polygon values.
- v is the verify function
Assume we have f(x) = mx + n and the line pq:
f(x)=mx+n
| /
| / |
|p *'--,,' |
| | / ''-* q
| | /
| /
| /
/___________________
f(x) crosses only by random the origin in this example. For the two points of the polygon p and q we can for px calculate f(px) and it can lay to the south or to the north of py, the real value of the polygon, or lay exactly on it.
If both calculated values f(px) and f(qx) are on the same side, north or south, the line doesn't cross.
So we have two values for the function:
val a = m*px+n
val b = m*qx+n
if (a == py || b == qy)
the function line touches one of the points.
if ((a < py && b > py) || (a > py && b < py))
they are on different sides, and cross as well. We can express this by substracting:
d1 = py - a
d2 = qy - b
if (( d1 == 0 || d2 == 0 || (sign (d1) != sign(d2))) ...
If the signs are different, the multiplication will return a negative value, and if they match, it returns a positive value. If one of the values is 0, the product is null. So we can condense the whole question to:
d1 * d2 <= 0
And that's what the verify-method v does.
The values of the polygon are (x1, y1), (x2, y2), ...(xn, yn), but they are flattened to x1, y1, x2, y2, ...xn, yn. The drop-statement takes the last 2 of them and prepends them to the front, to build a closed shape (xn, yn -> x1, y1). Sliding (4, 2) takes 4 values and advances for a step size of 2 through the collection. If a pair of xy exists, for which the verify function returns true, the line crosses the polygon or touches it.
Now I have to understand why the Ruby solution is so much shorter. Okay - a few less type declarations, shorter conversions. No println, no object, no App. Similar approach.
Invocation:
scala P "0.5x+3.1 (1, 2), (-1, 2), (5, 8), (6, 7), (2, 10)"