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.


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 is a comma-delimeted string containing pairs of characters. This string will always be valid - you do not have to validate the input.


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)
  • 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\$ Dec 3, 2016 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, 2016 at 0:40
  • \$\begingroup\$ if we write a function, can we take input as a list of instructions? \$\endgroup\$
    – FlipTack
    Dec 3, 2016 at 12:56
  • \$\begingroup\$ @Flp.Tkc Can you change the challenge to make it easier? No :) \$\endgroup\$
    – ArtOfCode
    Dec 3, 2016 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, 2016 at 13:05

4 Answers 4


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,"-/"))
                // right
                if(T(r,"~-")) d=(d+3)%4;
                // left
                if(T(r,"-~")) d=(d+1)%4;
                // come forward
                if(T(r,"~~")) {
                // move back
                if(T(r,"::")) {
  • \$\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, 2016 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, 2016 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, 2016 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, 2016 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, 2016 at 12:13

Befunge, 201 185 bytes

 #_7-:v v0-1
 _69*-:v NESW v+g01g
v v-*93_g10g\->4+4%10p
v<_100g >*:10g:1\-\2%!**03g+03p10g:2\-\2%**02g+02p

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).


Python 2.7.12, 295 bytes

from operator import*
for c in x.split(','):
 if n:
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)

  • 3
    \$\begingroup\$ There's a lot of extraneous whitespace you can remove here. \$\endgroup\$
    – ArtOfCode
    Dec 3, 2016 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\$
    – Wheat Wizard
    Dec 3, 2016 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, 2016 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\$
    – clismique
    Dec 3, 2016 at 23:29
  • \$\begingroup\$ @Qwerp-Derp, I believe I fixed the map() error. \$\endgroup\$
    – Eric
    Dec 3, 2016 at 23:47

Python 2, 142 bytes

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]


% 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.


Your Answer

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

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