8
\$\begingroup\$

Given a string representing a series of aircraft marshalling hand signals, write a function or program to calculate the final position of an aircraft following these signals.

N.B.: Co-ordinates in this challenge are represented as a pair of Cartesian co-ordinates, plus a compass direction heading: (x, y, h) where x is the x-coordinate, y is the y-coordinate, and h is one of N, E, S, or W.

You start with an aircraft at (0, 0, N) on an imaginary grid, with engines off. Your input is a string containing comma-delimeted pairs of characters, where each pair represents one marshalling signal. You must follow each marshalling signal in turn, and output the co-ordinates in (x, y, h) form of the aircraft's final position.

If a signal requires your aircraft to move, assume it moves one unit in the required direction for each signal of that type that it receives. If a signal requires your aircraft to turn, assume it turns 90 degrees in the required direction for each signal of that type that it receives.

An aircraft cannot move if its engines are off. If your aircraft's engines are off and you receive a movement/turn signal, do not apply the movement/turn.

Signals

Each marshalling signal is represented by one pair of characters. The first of the pair represents the position of the marshaller's left arm, from the aircraft's point of view, and the second the right arm from the same POV. This handy chart of signals may help.

o/  —  START ENGINES (no movement, no turn)
-/  —  CUT ENGINES   (no movement, no turn)
-~  —  TURN LEFT     (no movement, left turn)
~-  —  TURN RIGHT    (no movement, right turn)
~~  —  COME FORWARD  (forward movement, no turn)
::  —  MOVE BACK     (backward movement, no turn)
/\  —  NORMAL STOP   (no movement, no turn)

This is not the complete list of marshalling signals, but it's all you're required to support.

Input

Input is a comma-delimeted string containing pairs of characters. This string will always be valid - you do not have to validate the input.

Output

Output is a set of co-ordinates as described above. You can return this in any convenient format - if your language supports multiple return values, you may use that; alternatively, you can use a string (the brackets surrounding the co-ordinates are non-compulsory), array, tuple, list, or whatever else you find convenient. The only rule is that it must contain x, y, and h values, in that order.

Test Cases

Input  —  Output
o/,~~,~~,~-,::  —  (-1, 2, E)
::,~-,o/,/\,~~,-~,~~,~~,~~  —  (-3, 1, W)
o/,::,-/,~~,o/,~-,~~,~~,~-  —  (2, -1, S)
o/,~-,~-,::,::,~-,~~,-~  —  (-1, 2, S)
~-,~-,o/,::,::,-/,~~,-~  —  (0, -2, N)
\$\endgroup\$
  • 1
    \$\begingroup\$ What do start engines and cut engines actually do? Will only those moves between start engines and cut engines be executed? Otherwise I fail to see the relevance. \$\endgroup\$ – Level River St Dec 3 '16 at 0:03
  • \$\begingroup\$ @LevelRiverSt "An aircraft cannot move if its engines are off." I've been through that in the text. \$\endgroup\$ – ArtOfCode Dec 3 '16 at 0:40
  • \$\begingroup\$ if we write a function, can we take input as a list of instructions? \$\endgroup\$ – FlipTack Dec 3 '16 at 12:56
  • \$\begingroup\$ @Flp.Tkc Can you change the challenge to make it easier? No :) \$\endgroup\$ – ArtOfCode Dec 3 '16 at 13:01
  • \$\begingroup\$ I didn't realise using a builtin "split" function was so challenging. Having a rigid input format on code-golf is not advised; the standard is "take the input in any convenient format". \$\endgroup\$ – FlipTack Dec 3 '16 at 13:05
2
\$\begingroup\$

Java 8, 505 bytes

Golfed (with help from @masterX244 for shaving a big chunk off)

class f{static boolean T(String u,String v){return u.equals(v);}public static void main(String[]a){java.util.Scanner q=new java.util.Scanner(System.in);String s=q.nextLine();int x=0;int y=0;int d=0;int[][]v={{0,1},{-1,0},{0,-1},{1,0}};int b=1;for(String r:s.split(",")){if(T(r,"o/")||T(r,"-/"))b=~1;if(b<0){if(T(r,‌​"~-"))d=(d+3)%4;if(T‌​(r,"-~"))d=(d+1)%4;i‌​f(T(r,"~~")){x+=v[d]‌​[0];y+=v[d][1];}if(T‌​(r,"::")){x-=v[d][0]‌​;y-=v[d][1];}}}Syste‌​m.out.println("("+x+‌​","+y+","+"NWSE".cha‌​rAt(d)+")");}}

More readable

class f {
    static boolean T(String u,String v){return u.equals(v);}
    public static void main(String[] a) {
        java.util.Scanner q=new java.util.Scanner(System.in);
        String s=q.nextLine();
        int x=0;
        int y=0;
        int d=0;
        int[][] val = {
                {0,1},  // N
                {-1,0}, // W
                {0,-1}, // S
                {1,0}   // E
        };
        int b=1;
        for (String r: s.split(",")) {
            // toggle b if either start or stop engine
            if(T(r,"o/") || T(r,"-/"))
                b=~1;
            if(b<0){
                // right
                if(T(r,"~-")) d=(d+3)%4;
                // left
                if(T(r,"-~")) d=(d+1)%4;
                // come forward
                if(T(r,"~~")) {
                    x+=val[d][0];
                    y+=val[d][1];
                }
                // move back
                if(T(r,"::")) {
                    x-=val[d][0];
                    y-=val[d][1];
                }
            }
        }
        System.out.print("("+x+","+y+","+"NWSE".charAt(d)+")");
    }
}
\$\endgroup\$
  • \$\begingroup\$ some free bytes: class containing main() doesnt have to be public (see the golfing tips for java here) and quite a bunch of whitespace that can be optimized out (anything next to nonalphanumeric symbols can be stripped). also false can be writtten as 0>1 \$\endgroup\$ – masterX244 Dec 3 '16 at 11:52
  • \$\begingroup\$ Also: replacing the bool with a int and comparing it for being greater or smaller than zero shaved some bytes off, too. (using *=-1 to toggle it) code in next comment. And always use print() over println when you only need one line outputted \$\endgroup\$ – masterX244 Dec 3 '16 at 12:05
  • \$\begingroup\$ class f{static boolean T(String u,String v){return u.equals(v);}public static void main(String[]a){java.util.Scanner q=new java.util.Scanner(System.in);String s=q.nextLine();int x=0;int y=0;int d=0;int[][]v={{0,1},{-1,0},{0,-1},{1,0}};int b=1;for(String r:s.split(",")){if(T(r,"o/")||T(r,"-/"))b*=-1;if(b<0){if(T(r,"~-"))d=(d+3)%4;if(T(r,"-~"))d=(d+1)%4;if(T(r,"~~")){x+=v[d][0];y+=v[d][1];}if(T(r,"::")){x-=v[d][0];y-=v[d][1];}}}System.out.print("("+x+","+y+","+"NWSE".charAt(d)+")");}} \$\endgroup\$ – masterX244 Dec 3 '16 at 12:05
  • \$\begingroup\$ @masterX244 thx I'm clearly a bit knew to this. Ill add in the edit for print \$\endgroup\$ – Bobas_Pett Dec 3 '16 at 12:11
  • \$\begingroup\$ the import is also a spot to optimize. for one or 2 mentions a fully qualified reference on both is shorter than importing. (code i pasted in comment contains all optimizes i found) \$\endgroup\$ – masterX244 Dec 3 '16 at 12:13
1
\$\begingroup\$

Befunge, 201 185 bytes

p10p2p3pv
~/3-*95~<v:+-"/"
  v!:-*53_v
 #_7-:v v0-1
vv!:-3_100>p
 _69*-:v NESW v+g01g
v v-*93_g10g\->4+4%10p
v<_100g >*:10g:1\-\2%!**03g+03p10g:2\-\2%**02g+02p
>>~65*`#v_2g.3g.10g9+5g,@

Try it online!

Befunge doesn't have a string type as such, so to make the signals easier to compare, each character pair is converted into an integer using the formula (c1 - 45)/3 + c2 - 47. This can mean we'll get false matches on invalid input, but that's doesn't matter if the input is guaranteed to be valid.

The rest of the code is based around the manipulation of four "variables": the engine state (1 or 0), the heading (0 to 3 for NESW), and the x and y positions. The calculations for each signal are then as follows:

Start engine: engine = 1
Cut engine: engine = 0
Turn left: heading = (heading - engine + 4) % 4
Turn right: heading = (heading + engine) % 4
Movement: (where dir is 1 for forward and -1 for backwards)
y += dir*engine*(1-heading)*!(heading%2)
x += dir*engine*(2-heading)*(heading%2)

Once we reach the end of the input sequence, it's then just a matter of outputting the x, y, and heading (converted to a char with a simple table lookup).

\$\endgroup\$
1
\$\begingroup\$

Python 2.7.12, 295 bytes

from operator import*
l=[0,0]
m=[['N',[0,1]],['E',[1,0]],['S',[0,-1]],['W',[-1,0]]]
n=0
x=raw_input()
for c in x.split(','):
 if'o/'==c:n=1
 if'-/'==c:n=0
 if n:
    if'-~'==c:m=m[-1:]+m[:-1]
    if'~-'==c:m=m[1:]+m[:1]
    if'~~'==c:l=map(add,l,m[0][1])
    if'::'==c:l=map(sub,l,m[0][1])
print l+[m[0][0]]

The first level of indentation after for uses a single \s. The indentation of the second level uses a single \t. (the wysiwyg replaces \t with multiple spaces so please keep this in mind when testing for size)

\$\endgroup\$
  • 3
    \$\begingroup\$ There's a lot of extraneous whitespace you can remove here. \$\endgroup\$ – ArtOfCode Dec 3 '16 at 22:16
  • \$\begingroup\$ Not just white space but other easy to fix inefficientcies. Try the tips for golfing in python for specific examplrs. \$\endgroup\$ – Sriotchilism O'Zaic Dec 3 '16 at 22:27
  • \$\begingroup\$ Note that in code-golf you don't have to have any input prompt: you can just do raw_input(). \$\endgroup\$ – FlipTack Dec 3 '16 at 22:38
  • \$\begingroup\$ This code errors for me on line 15: TypeError: Argument to map() must support iteration (I'm using Python 2.7.12). \$\endgroup\$ – Qwerp-Derp Dec 3 '16 at 23:29
  • \$\begingroup\$ @Qwerp-Derp, I believe I fixed the map() error. \$\endgroup\$ – Eric Dec 3 '16 at 23:47
1
\$\begingroup\$

Python 2, 142 bytes

s=raw_input()
e=p=0;d=1
while s:exec'd-=e d+=e p+=1j**d*e e=0 0 e=1 p-=1j**d*e 0'.split()[ord(s[0])+ord(s[1])*2&7];s=s[3:]
print p,'ESWN'[d%4]

Example:

% python2.7 ams.py <<<'o/,~~,~~,~-,::'
(-1+2j) E

This prints complex numbers, which should be okay, I think? The x, y, h order is still there, and the 'j' doesn’t cause any confusion. Tell me if I should change it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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