# Euclidean Vectors

Given the ASCII art of two vectors, find the resultant vector's magnitude and degree.

## Input

This can be received via STDIN, read from a local file, or provided through a function call. Here is an example of a two vector input:

^------>
|
|
|
x


This represents a change of 4 units north and 7 units east. Every input's starting point will be represented by an x (decimal 120).

• All vectors are horizontal or vertical lines.

• Each vector has one of these four endpoints: ^v<>, and is made up of either a dash (-, decimal 45) or a vertical bar (|, decimal 124).

• Empty points on the plane are filled with spaces (, decimal 32).

• The input may be a single x.

• Adjacent vectors are always perpendicular to each other.

• All vectors are tip-to-tail.

## Output

This will be the displacement of the resulting point (distance from the starting point) and the degree to which it has moved, relative to the starting point.

For the above input, the output should be 8.06 units and 60.3 degrees. Each should have exactly 3 significant figures. Here are a few examples of numbers with 3 significant digits:

• 1.00
• 60.1
• 453
• 7.08
• 4.50
• 349

All unit measurements will be <= 999.

These numbers should be output in the below format. This is using the numbers from above.

8.06 units @ 60.3 degrees


This may be followed by a single trailing space or newline.

If the input is a single x, with no displacement and hence no angle of displacement, the output should be either an empty line (a single newline character) or in the following format:

0 units @ - degrees


If you're trying to qualify for the bonus, the direction should be - as well.

In the case that bonuses 2, 3, or both are completed, the output should follow the below model and abide by the same restrictions as the above.

8.06 units @ 60.3 degrees NE


Degrees should be measured according to the standard plane.

       90
135  |  45
\|/
180 ---x---- 0
/|\
225  |  315
270


0 degrees is east, 1 - 89 degrees is northeast, 90 is north, etc.

## Bonuses

The following are worth a total of -50%.

1. Take a -10% bonus for each additional vector that can be handled. This bonus can be applied to up to 3 times. Vectors will never overlap or cross.

2. Take a -10% bonus if your output includes the cardinal direction of the angle (north, south, east, west).

3. Take a -10% bonus if your output includes the intermediate directions of the angle (northeast, northwest, southeast, southwest).

## Examples

In:

x---->
|
v


Out:

5.39 units @ 338 degrees


Optionally SE

In:

<--------------^
|
|
x


Out:

15.3 units @ 169 degrees


Optionally NW

In:

x
|
|<-----^
|      |
v------>


Out:

2.24 units @ 297 degrees


Optionally SE

## Examples (multiple vectors)

In:

x--->
|
|
v----------->


Out:

16.3 units @ 349 degrees


Optionally SE

In:

<-------^
|       |
|       |
v       |
|
|
x


Out:

8.54 units @ 159 degrees


Optionally NW

In:

^-->
|  |
|  v
|
<--------x


Out:

6.32 units @ 162 degrees


Optionally NW

• Will vectors ever have a zero component in one direction? If so, what should output be for x? What's the boundary between North and Northwest? Jan 8, 2016 at 3:30
• I've added that information. Thanks for pointing it out! @ThomasKwa Jan 8, 2016 at 3:39
• You should add a test case where there's only one vector, e.g. x-->. Can vectors cross? Jan 8, 2016 at 3:45
• The regular input will be two vectors. The single exception is the empty x. There may be more than two (if attempting to complete the bonus), but not less. I'm working on examples for multiple vector inputs. In no inputs will vectors cross. @ThomasKwa Jan 8, 2016 at 3:47

## Python 2, 238.5 (594562482 477-50%) bytes

from math import*
def F(x):s='%.3g'%x;return[[s+'.',s]['.'in s].ljust(4,'0'),s][x>99]
I=input()
V=I.split('\n');N=len(V)
l=max(len(x)for x in V)
q=[' '*(l+2)];V=q+[' '+x.ljust(l+1)for x in V]+q
for k in range(N*l):
i,j=k/l,k%l;c=V[i+1][j+1]
if c in'<>^v'and['|'not in zip(*V)[j+1][i:i+3],'-'not in V[i+1][j:j+3]][c>'?']:a,b=i,j
if c=='x':A,B=i,j
Y=A-a;X=b-B;a=atan2(Y,X)/pi*180%360
print[F(hypot(X,Y))+' units @ '+F(a)+' degrees '+' NS'[cmp(Y,0)]+' EW'[cmp(X,0)],''][I=='x']


Explanation

Finds the start and end positions by looking at each character in the input.

Start is x

End is found by looking at each arrow (<>^v), and their neighbors. If neighbors are continuing vectors, ignore. Else, this is the end.

Look at the neighbors perpendicular to the arrow direction.

If they contain a perpendicular line, then it is a continuing vector.

Examples (_ indicates space):

_#_
->_   Neighbors marked by #
_#_

___
->_   (end)
___

_|_
->_   (not end)
___

___
->|   (end)
___

---
->_   (end)
___


Because the end point is found, there can be any number of vectors (30% bonus).

• Are you sure this works in python 2? Plus, you can change "from math import " to "from math import" (remove the space). Jan 8, 2016 at 16:55
• @RikerW It works for me. Ideone: ideone.com/9j86yj uses \n as linebreaks... Jan 9, 2016 at 22:12
• Well done, with a nice explanation of the "neighbours". I was a little concerned by your use of input() and the corresponding wrapping of the input with "", but there doesn't seem to be a rule against it! Jan 13, 2016 at 12:42

# JavaScript (ES6), 305 bytes - 50% bonus = 152.5 score

v=>(l=v.search
+1,s=v.searchx,u=0,d="-",v.replace(/[<>v^]/g,(p,i)=>{c=o=>v[i+o]!=q;with(Math)if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1))d=(atan2(x=i%l-s%l,y=(i/l|0)-(s/l|0))*180/PI+270)%360,u=sqrt(x*x+y*y)}),u[p="toPrecision"](3)+ units @ ${d[p](3)} degrees)  ## Explanation Input must be padded with spaces. Uses all bonuses. v=>( l=v.search +1, // l = line length s=v.searchx, // s = index of start point u=0, // u = units d= // d = degrees w="-", // w = cardinal direction v.replace(/[<>v^]/g,(p,i)=>{ // for each endpoint c=o=>v[i+o]!=q; // compares cell at offset to char with(Math) // save having to write "Math." if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1)) // check for line branching off d=(atan2( x=i%l-s%l, // x = relative x y=(i/l|0)-(s/l|0) // y = relative y )*180/PI+270)%360, // convert to degrees u=sqrt(x*x+y*y), w="N S"[sign(y)+1]+"W E"[sign(x)+1] // get cardinal direction }), u[p="toPrecision"](3)+ units @${d[p](3)} degrees +w // format output
)


## Test

var solution = v=>(l=v.search
+1,s=v.searchx,u=0,d=w="-",v.replace(/[<>v^]/g,(p,i)=>{c=o=>v[i+o]!=q;with(Math)if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1))d=(atan2(x=i%l-s%l,y=(i/l|0)-(s/l|0))*180/PI+270)%360,u=sqrt(x*x+y*y),w="N S"[sign(y)+1]+"W E"[sign(x)+1]}),u[p="toPrecision"](3)+ units @ \${d[p](3)} degrees +w)
<textarea id="input" rows="6" cols="60">x
|
|<-----^
|      |
v------></textarea><br />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>