# My Robot Has Escaped the Lab!

My robot has short circuited somehow and randomly run off somewhere from my lab!

Luckily, whenever he does this, his shut-down sequence initiates, giving him enough time to randomly turn and run in the direction its facing for five rounds before he switches off. His gyro and accelerometer functions are still relaying the data back to the lab while he is still on.

The data will always come in the form of five sets of two numbers, for example.

12:234,-135:47,-68:230,140:324,127,87

Your mission, golfers is to a) simulate the robot's frantic run and turn sequence by displaying five sets of numbers in the form of a1:d1,a2:d2,a3:d3,a4:d4,a5:d5 where a(n) is the clockwise angle (in degrees) such that -179<=a<=+180 that the robot will turn from its current heading (initially it is at zero heading before it runs amok and turns for the first time), and d(n) is the distance in feet it has run before the next heading change which is such that 0<=d<=500 feet; and b) A calculated heading from the lab (which is also facing a heading of zero), distance in feet (accuracy up to 3 decimal places is strongly encouraged, -5 bytes if you do), and the orientation heading (in degrees) of where my robot it is facing when it has switched off.

Easy example:

Data: 0:1,45:1,90:1,90:1,90:1
Distance: 1
Orientation: -45


The random turns and distances are just that, random. No set values are to be hard coded, we must see the randomness in action within the code.

Restrictions to randomness: No clock or date based references, we need to see a native random reference within the code. Whenever you run this code, the randomness must present itself with a possibility of showing 1 of 360 possible angles of turning with each turn-run round. So the robot may turn -36 degrees at one turn and may turn +157 degrees the next, followed by another turn of +2 degrees by another turn of -116 degrees and a final turn of +42 degrees on the final turn. At least 360 distinct values must be possible (between -179 to +180 degrees inclusive) with each random angle generation.

Restrictions to distance run: Similarly set, there are 501 possible distances the robot can run, (between 0 and 500 feet inclusive), so I expect the randomness to also be available when determining the robot's running distance. The robot could theoretically run 45, 117, 364, 27 and 6 feet with each of its respective rounds...

The data fed to you will always be in integer values... the robot will turn in integer ranges of degrees, and will run in integer ranges of distance. The output values however, will be floats...

This is code-golf. Shortest code wins... Now go find my robot!

PS: In reference to my "Accuracy up to 3 decimal places", if you can provide the heading (in degrees, to a MINIMUM of 3 decimal places) and a distance in feet (also accurate also to a MINIMUM 3 decimal places) you will get a -5 byte bonus).

• @IsmaelMiguel and @OP - I'm probably going to get shot for this, but couldnt you use -180 < a <= +180 as the < sign on its own means less than but not including AFAIK... – George Mar 11 '14 at 21:54
• @GeorgeH You are correct, but what WallyWest is saying is wrong. "-179 <= a <= 180 results in all 360 possible integer headings" -> this is wrong because there are 361 headings. Or the robot isn't allowed to go to -180º? – Ismael Miguel Mar 11 '14 at 22:06
• @IsmaelMiguel It is allowed to go -180 degrees, because that's exactly the same as 180. – Doorknob Mar 11 '14 at 22:39
• That is wrong. +180º means an half-turn clockwise. -180º means half-turn anti-clockwise (or counterclockwise, as you prefer). if the range is -179<=a<=+180, the robot can't turn 180º anti-clockwise. Why? He will be stuck at -179º! Maybe that is why he had short circuit... – Ismael Miguel Mar 12 '14 at 9:34
• @WallyWest I'm not stupid and I understand what you mean. I'm just saying that the range should be fixed. – Ismael Miguel Mar 12 '14 at 16:32

# Perl 6: 188 184 characters - 5 = 180 points

$_=((-179..180).pick=>(^501).pick)xx 5;my$o;$/=([+] .map:{unpolar .value,$o+=.key/($!=180/pi)}).polar;say "Data: {.fmt("%d:%d",",")} Heading: {$1*$!} Distance:$0
Orientation: {$o*$!}"


Golf with whitespace:

$_ = ((-179..180).pick => (^501).pick) xx 5; my$o;
$/ = ([+] .map: { unpolar .value,$o += .key / ($!=180/pi) }).polar; say "Data: {.fmt("%d:%d", ",")} Heading: {$1*$!} Distance:$0
Orientation: {$o*$!}"


Ungolfed:

my &postfix:<°>  = */180*pi; # Deg → Rad
my &postfix:<㎭> = */pi*180; # Rad → Deg

my @data = ((-179..180).pick => (0..500).pick) xx 5;
say "Data: @data.fmt("%d:%d", ",")";

my $cum-angle = 0; my$complex = [+] @data.map: {unpolar .value, $cum-angle += .key°} my ($dist, $ang) =$complex.polar;

say "Heading: ",     $ang.㎭; say "Distance: ",$dist;
say "Orientation: ", $cum-angle.㎭;  This turns the data into complex numbers with unpolar, puts the sum of them into $complex, and then gets the polar coordinates as $dist, $ang.

The cumulative angle, $cum-angle is collected because the angles are relative to the robot as it moves through the lab and because we need the final angle of the robot in our output. Sample output: Data: -73:230,-144:453,-151:274,-52:232,88:322 Heading: -5.33408558001246 Distance: 378.74631610127 Orientation: -332  The only real trick the golf uses is that it (mis)uses all 3 of Perl 6's special variables to good effect: • $! is used for radians ↔ degrees
• $_ holds the data, and anything that looks like a lonely .method() actually means $_.method() (except inside the map {…} block, where $_ actually takes on the value of the number pairs that make up the data) • $/ holds what is in the ungolfed version ($dist,$ang). $0 and $1 actually mean $/[0], i.e., $dist, and $/[1], i.e., $ang
• Nice! You can still go down from 188 to 184 like this: $_=((-179..180).pick=>(^501).pick)xx 5;my$o;$/=([+] .map:{unpolar .value,$o+=.key/($!=180/pi)}).polar;say "Data: {.fmt("%d:%d",",")} Heading: {$1*$!} Distance:$0 Orientation: {$o*$!}" – Mathieu Rodic Mar 24 '14 at 13:13
• @MathieuRodic Oh, nice find! Thanks! Unfortunately, the space after .map: is mandatory – Mouq Mar 24 '14 at 22:00
• Oh, I was wrong about the space, cool :) – Mouq Mar 24 '14 at 22:10

# Ruby, 274252249245214211207204 202 characters (-5 = 197)

How did PHP beat Ruby in char count?! >:O Must find some way to golf more...

Edit: I beat the PHP answer, but the user who wrote it helped me do it! Go upvote him; he deserves it :-P

Another edit: Gah! He passed me again! You are a very worthy opponent, @MathieuRodic; congratulations, I have to let you win ;-)

P=(M=Math)::PI
puts"Data: #{([x=y=a=0]*5).map{a+=o=rand -179..e=180;x+=M.sin(b=a*P/e)*d=rand 500;y+=d*M.cos b;"#{o}:#{d}"}*?,}
Distance: #{M.hypot x,y}
Orientation: #{a}"


Ungolfed code (and slightly much older version):

data = Array.new(5) { [rand(-179..180), rand(0..500)] }
puts "Data: #{data.map{|x|"#{x[0]}:#{x[1]}"}.join ?,}"
x, y, a = [0] * 3
data.each do |o, d|
a += o
x += Math.sin(a * Math::PI / 180) * d
y += Math.cos(a * Math::PI / 180) * d
end
puts "Heading: #{Math.atan(y / x) / Math::PI * -180 + 90}
Distance: #{Math.sqrt(x * x + y * y)}
Orientation: #{a}"


Sample output:

c:\a\ruby>robotgolf
Data: 94:26,175:332,14:390,159:448,-45:20
Distance: 279.5742334385328
Orientation: 397

• How is the robot facing due north after having turned five random angles? – WallyWest Mar 11 '14 at 19:56
• @WallyWest I was under the impression that the orientation marks the starting angle of the robot, correct? I could make it mark the ending angle for only 3 extra chars. – Doorknob Mar 11 '14 at 20:54
• No, it is always facing due north (heading 0) at the code's execution... Then it turns, runs, turns, runs, turns, runs, turns, runs, turns and then runs... before it shuts down. It will need to have the final angle it is facing inthe Orientation section. – WallyWest Mar 11 '14 at 21:07
• @WallyWest Ah, okay, edited. Is it okay if the orientation is not in 0...360, or do we have to do a % 360 on it? – Doorknob Mar 11 '14 at 21:08
• You can save 11 characters by declaring M=Math and P=M::PI and replacing the code accordingly - and one more character by getting rid of the space after the second puts. – David Herrmann Mar 11 '14 at 22:35

# PHP - 238232221212203 199 characters

for(;$i<5;$h+=$a=rand(-179,181),$x+=cos($b=$a*$k=M_PI/180)*$l=rand(0,501),$y+=$l*sin($b),$d.=($i++?",":"")."$a:$l");echo"Data:$d
Heading: $h Distance: ".hypot($x,$y)." Orientation: ".atan2($y,$x)/$k


(test it here: http://ideone.com/dNZnKX)

Non-golfed version:

$k = M_PI / 180;$h = $x =$y = 0;
$d = ""; for ($i=5; $i--;){$h += $a = rand(-179,181);$x += ($l = rand(0, 501)) * cos($b = $k *$a);
$y +=$l * sin($b);$d .= ($d ? "," : "") . "$a:$l"; } echo "Data:$d\nHeading: $h\nDistance: " . sqrt($x*$x +$y*$y) ."\nOrientation: " . atan2($y, $x)/$k . "\n";


(test it here: http://ideone.com/1HzWH7)

• Looks like Perl just narrowly beat us both at the last minute. :-O – Doorknob Mar 24 '14 at 11:47
• @Doorknob Yup, sorry :) – Mouq Mar 24 '14 at 22:02
• Definitely. Mouq, you kind of wiped out all our efforts with only 188... – Mathieu Rodic Mar 24 '14 at 22:06

# Python - 264259256 258 - 5 = 253 characters

from math import*;import random as R;r,k,d=R.randint,pi/180,[];h=x=y=0;exec"a,l=r(-179,180),r(0,500);d+=[a+':'+l];h+=a;x+=l*cos(k*a);y+=l*sin(k*a);"*5;print('Data: %s\nHeading: %d\nDistance: %.3f\nOrientation: %d'%(','.join(d),h,hypot(x,y),atan2(y,x)/k))


(test it at http://ideone.com/FicW6e)

Ungolfed version:

from math import *
from random import randrange as r

k = pi / 180
h = x = y = 0
d = []
for i in range(5):
a = r(-179,181)
l = r(501)
d += ['%d:%d' % (a, l)]
h += a
x += l * cos(k * a)
y += l * sin(k * a)

print('Data: %s\nHeading: %d\nDistance: %.3f\nOrientation: %f' % (','.join(d), h, sqrt(x*x+y*y), atan2(y,x)/k))


(test it at http://ideone.com/O3PP7T)

NB: many answers include -5 in their title, while their program does not represent the distance with accuracy up to 3 decimal places...

# Python 301-5=296

from math import*
r=__import__("random").randint
o=x=y=0
s=[]
for i in[0]*5:a=r(-179,180);d=r(0,500);o+=a;o+=180*((o<-179)-(o>180));n=pi*o/180;x+=d*cos(n);y+=d*sin(n);s+=["%d:%d"%(a,d)]


Nothing too fancy here, rather verbose. This is one problem for which I am not happy that python's trig functions work in radians.

> python robot.py
Data: 17:469,110:383,-146:240,-78:493,62:1
Distance: 405.435748
Orientation: -35
> python robot.py
Data: -119:363,89:217,129:321,10:159,-56:109
Distance: 130.754395
Orientation: 53


## Python 2 = 376 319 characters (-5 for distance=314)

import random,math
h=x=y=0
for i in range(5):
a=random.randint(-179,180)
d=random.randint(0,500)
print '%d:%d,'%(a,d),
h+=a
if h>180:
h-=360
x+=d*math.cos(h)
y+=d*math.sin(h)
t=math.sqrt(x**2+y**2)
o=math.atan2(y,x)
print
print 'Heading: %d\nDistance: %3f\nOrientation: %d' % (h,t,o)


sample output

-141:245, 56:355, 145:223, -10:80, -38:253,