14
\$\begingroup\$

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

\$\endgroup\$
13
  • \$\begingroup\$ 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? \$\endgroup\$
    – lirtosiast
    Jan 8, 2016 at 3:30
  • \$\begingroup\$ I've added that information. Thanks for pointing it out! @ThomasKwa \$\endgroup\$
    – Zach Gates
    Jan 8, 2016 at 3:39
  • \$\begingroup\$ You should add a test case where there's only one vector, e.g. x-->. Can vectors cross? \$\endgroup\$
    – lirtosiast
    Jan 8, 2016 at 3:45
  • \$\begingroup\$ 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 \$\endgroup\$
    – Zach Gates
    Jan 8, 2016 at 3:47
  • \$\begingroup\$ I've added them. @ThomasKwa \$\endgroup\$
    – Zach Gates
    Jan 8, 2016 at 3:58

2 Answers 2

3
\$\begingroup\$

Python 2, 238.5 (594 562 482 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).

\$\endgroup\$
3
  • \$\begingroup\$ Are you sure this works in python 2? Plus, you can change "from math import " to "from math import" (remove the space). \$\endgroup\$
    – Riker
    Jan 8, 2016 at 16:55
  • \$\begingroup\$ @RikerW It works for me. Ideone: ideone.com/9j86yj uses \n as linebreaks... \$\endgroup\$
    – TFeld
    Jan 9, 2016 at 22:12
  • \$\begingroup\$ 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! \$\endgroup\$ Jan 13, 2016 at 12:42
2
+100
\$\begingroup\$

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

v=>(l=v.search`
`+1,s=v.search`x`,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.search`x`,                                         // 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.search`x`,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>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.