text:
The Drunken Bishop

In public-key cryptography, a public key fingerprint is a short sequence of bytes used to identify a longer public key.

In SSH in particular they can be used to verify that a server is in fact the server I'm expecting to communicate with and I'm not targeted by a man-in-the-middle attack.
They are usually represented as a string of hexadecimal digits, so it can be rather boring and tedious to compare it with the fingerprint I would expect:
37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e

To make it a little easier, OpenSSH has introduced a method to visualize fingerprints as ASCII art, that would look like the following:
+-----------------+
|                 |
|                 |
|          .      |
|     .   o       |
|o . o . S +      |
|.+ + = . B .     |
|o + + o B o E    |
| o .   + . o     |
|         .o      |
+-----------------+

With this, I could try to remember the rough shape of the ASCII art and would then (theoretically) recognize it when the fingerprint of the server changed and the image looks different.
How it works
Taken from Dirk Loss, Tobias Limmer, Alexander von Gernler. 2009. The drunken bishop: An analysis of the OpenSSH
fingerprint visualization algorithm.
The grid has a width of 17 characters and a height of 9 characters. The "bishop" starts at row 4/column 8 (the center). Each position can be denoted as [x,y], i.e. [8,4] for the starting position of the bishop.
            1111111
  01234567890123456
 +-----------------+
0|                 |
1|                 |
2|                 |
3|                 |
4|        S        |
5|                 |
6|                 |
7|                 |
8|                 |
 +-----------------+

The bishop uses the fingerprint to move around. It reads it byte-wise from left to right and from the least significant bit to the most significant bit:
Fingerprint      37      :       e4      :       6a      :  ...  :       5e
Bits        00 11 01 11  :  11 10 01 00  :  01 10 10 10  :  ...  :  01 01 11 10
             |  |  |  |      |  |  |  |      |  |  |  |              |  |  |  |
Step         4  3  2  1      8  7  6  5     12 11 10  9             64 63 62 61

The bishop will move by the following plan:
Bits   Direction
-----------------
00     Up/Left
01     Up/Right
10     Down/Left
11     Down/Right

Special cases:

If the bishop is in a corner and would move into the corner again, he doesn't move at all. i.e: The bishop is at [0,0] and his next step would be 00. He remains at [0,0]
If the bishop is in a corner or at a wall and would move into one of the walls, he moves horizontally or vertically only. i.e: The bishop is at [0,5] and his next step would be 01. He cannot go left, so he just moves up, to [0,4].

Each position holds a value of how often the bishop has visited this field:
Value      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15| 16|
Character  |   | . | o | + | = | * | B | O | X | @ | % | & | # | / | ^ | S | E |

The values 15 (S) and 16 (E) are special in that they mark the start and end position of the bishop respectively and overwrite the real value of the respecting position.
Goal
Create a program, that takes an alphanumeric fingerprint as input and produces its ASCII art representation as shown in the examples.
Examples
Input:
16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48

Output:
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+

Input:
b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b

Output:
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

Input:
05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47

Output:
+-----------------+
|       o=.       |
|    o  o++E      |
|   + . Ooo.      |
|    + O B..      |
|     = *S.       |
|      o          |
|                 |
|                 |
|                 |
+-----------------+

Rules

This is code-golf. The code in the fewest bytes wins.
You can not use an existing library that produces the image.
Use whichever language you prefer!
Your submission has to be a complete program

Can we assume that no cell will be visited more than 14 times?

There are a few corner cases of minimal coverage that would result in a few fields being visited more than 14 times. 33:33:33:...:33, cc:cc:cc:...:cc would be examples for this. The fingerprint is usually a MD5 hash, so it's highly unlikely you get such a result. I haven't found any reliable sources on how to deal with these, so for now I'd say: Assume no cell will be visited more than 14 times.

Pyth, 125 bytes
Jj*17\-"++"JVc9XXsm@"^ .o+=*BOX@%&#/"hdrS+*U9U17K.u.e@S[0b*8hk)1.b+tNyYNYsm_c4.[08jxsM^.HM16 2d2cz\:,4 8 8ieK17\E76\SjN"||")J

Try it online: Demonstration or Test-Suite
I wrote a few days ago, but didn't post it, because I wasn't really happy about it.
Explanation:
The basic idea is the following. I start with the pair (4, 8). In each move (m1,m2) I go from the (x, y) to (x-1+2*m1, y-1+2*m2). To make sure, that these coordinates don't go outside the boarders, I'll make some lists, sort them and return the middle element: (sorted(0,8,newx)[1], sorted(0,16,newy)[1]).
I keep track of all positions. To this list of positions I add a list of all possible positions, sort them and run-length-encode them. Which gives me a number for each position. With this number I can choose the coorect char, and at the end overwrite the chars of the start and end position.

Dyalog APL (178)
{⎕ML←3⋄F←9 17⍴0⋄5 9{(⍺⌷F)+←1⋄×⍴⍵:(1 1⌈9 17⌊⍺-1 1-2×↑⍵)∇1↓⍵⋄(⍺⌷F)←16⋄F[5;9]←15⋄K⍪(M,' .o+=*BOX@%&#/^SE'[1+F],M←'|')⍪K←'+','+',⍨17⍴'-'}⊃,/{↓⊖4 2⍴⍉(4/2)⊤¯1+⍵⍳⍨⎕D,'abcdef'}¨⍵⊂⍨':'≠⍵}

This is a function that takes the string as its right argument, and returns a character matrix containing the ASCII art representation, e.g.:
      F←{⎕ML←3⋄F←9 17⍴0⋄5 9{(⍺⌷F)+←1⋄×⍴⍵:(1 1⌈9 17⌊⍺-1 1-2×↑⍵)∇1↓⍵⋄(⍺⌷F)←16⋄F[5;9]←15⋄K⍪(M,' .o+=*BOX@%&#/^SE'[1+F],M←'|')⍪K←'+','+',⍨17⍴'-'}⊃,/{↓⊖4 2⍴⍉(4/2)⊤¯1+⍵⍳⍨⎕D,'abcdef'}¨⍵⊂⍨':'≠⍵}

      F '16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+
      F 'b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b'
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

Explanation:

⎕ML←3: set ⎕ML to 3. This makes ⊂ more useful for splitting strings.
F←9 17⍴0: make a 17-by-9 matrix of zeroes. F represents how many times each position has been visited.
⍵⊂⍨':'≠⍵: split ⍵ on : characters.
{...}¨: for each group:

¯1+⍵⍳⍨⎕D,'abcdef': find the index of each character in the string '01234567890abcdef'. Subtract 1, because APL is 1-indexed by default.
(4/2)⊤: convert the values to their 4-bit representations (there should now be 2-by-4 matrix).
↓⊖4 2⍴⍉: rotate the matrix, use the elements to fill a 2-by-4 matrix instead, mirror that matrix horizontally, and then get each line separately. This gives us the 4 2-bit values we need.

⊃,/: join the resulting lists together, giving a list of 2-bit steps.
5 9{...}: given the list of steps, and starting at position [9,5]:

(⍺⌷F)+←1: increment the current position in F.
×⍴⍵:: if the list of steps is not empty:

↑⍵: take the first step from the list
⍺-1 1-2×: get the delta for that step, and subtract it from the current position
1 1⌈9 17⌊: restrict movement to within the field
(...)∇1↓⍵: continue with the new position and the rest of the steps

If it is empty:

(⍺⌷F)←16: set F to 16 at the final position
F[5;9]←15: set F to 15 at the start position
' .o+=*BOX@%&#/^SE'[1+F]: map each position to the corresponding character
K⍪(M,...,M←'|')⍪K←'+','+',⍨17⍴'-': wrap the result in lines

Perl, 300 + 1 (-n) = 301 bytes
perl -ne 'sub b{$b=$_[0]+$_[1];$_[0]=$b<0?0:$b>$_[2]?$_[2]:$b}$v=pack"(H2)*",/\w\w/g;($x,$y)=(8,4);$a[b($y,($_&2)-1,8)*17+b($x,($_&1)*2-1,16)]++for map{vec$v,$_,2}0..63;@a[76,$y*17+$x]=(15,16);$c=" .o+=*BOX@%&#/^SE";print$d="+".("-"x17)."+\n",(map{+"|",(map{substr$c,$_,1}@a[$_*17..($_+1)*17-1]),"|\n"}0..8),$d'

This answer is disgusting, but it's also the first one for this puzzle, so it'll do for now.
-n to take a line of input on STDIN and fill $_.
# b($v, -1 or 1, max) modifies $v within 0..max
sub b{$b=$_[0]+$_[1];$_[0]=$b<0?0:$b>$_[2]?$_[2]:$b}

# turn $_ into a binary string
$v=pack"(H2)*",/\w\w/g;

# initialize cursor
($x,$y)=(8,4);

# find an element of single-dimensional buffer @a
$a[
    # y += (bitpair & 2) - 1, within 8
    b($y,($_&2)-1,8) * 17
    # x += (bitpair & 1) * 2 - 1, within 17
  + b($x,($_&1)*2-1,16)
# and increment it
]++
# for each bit pair (in the right order!)
  for map{vec$v,$_,2}0..63;

# overwrite the starting and ending positions
@a[76,$y*17+$x]=(15,16);

# ascii art lookup table
$c=" .o+=*BOX@%&#/^SE";

# output
print
  # the top row, saving it for later
  $d="+".("-"x17)."+\n",
  # each of the eight middle rows
  (map{+
    # converting each character in @a in this row as appropriate
    "|",(map{substr$c,$_,1}@a[$_*17..($_+1)*17-1]),"|\n"
  }0..8),
  # the bottom row
  $d

R, 465 459 410 393 382 357 bytes
f=function(a){s=strsplit;C=matrix(as.integer(sapply(strtoi(el(s(a,":")),16),intToBits)[1:8,]),2);C[!C]=-1;n=c(17,9);R=array(0,n);w=c(9,5);for(i in 1:64){w=w+C[,i];w[w<1]=1;w[w>n]=n[w>n];x=w[1];y=w[2];R[x,y]=R[x,y]+1};R[]=el(s(" .o+=*BOX@%&#/^",""))[R+1];R[9,5]="S";R[x,y]="E";z="+-----------------+\n";cat(z);for(i in 1:9)cat("|",R[,i],"|\n",sep="");cat(z)}

With indentations and newlines:
f=function(a){
    s=strsplit
    C=matrix(as.integer(sapply(strtoi(el(s(a,":")),16),intToBits)[1:8,]),2)
    C[!C]=-1
    n=c(17,9)
    R=array(0,n)
    w=c(9,5)
    for(i in 1:64){
        w=w+C[,i]
        w[w<1]=1
        w[w>n]=n[w>n]
        x=w[1]
        y=w[2]
        R[x,y]=R[x,y]+1
    }
    R[]=el(s(" .o+=*BOX@%&#/^",""))[R+1]
    R[9,5]="S"
    R[x,y]="E"
    z="+-----------------+\n"
    cat(z)
    for(i in 1:9)cat("|",R[,i],"|\n",sep="")
    cat(z)
}

Usage:
> f("16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48")
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+
> f("37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e")
+-----------------+
|                 |
|                 |
|          .      |
|     .   o       |
|o . o . S +      |
|.+ + = . B .     |
|o + + o B o E    |
| o .   + . o     |
|         .o      |
+-----------------+

Cant you golf the 'matrix' function by defining it once as 'm'? Same for 'function'?

I think you do not need 'sep=' in the 'cat' function

the default for sep is a space, so i need to override it, but indeed I could alias matrix.

Additionnaly, as far as I know, you can't alias function.

Octave, 277
d=reshape(rot90(dec2bin(hex2dec(strsplit(input('','s'),':'))))>'0',2,[])*2-1;p=[9;5];for m=1:64 p=[max(min(p(:,1)+d(:,m),[17;9]),1) p];end;A=' .o+=*BOX@%&#/^SE';F=A(sparse(p(2,:),p(1,:),1,9,17)+1);F(5,9)='S';F(p(2,1),p(1,1))='E';[a='+-----------------+';b=['|||||||||']' F b;a]

Explanation:
%// convert the input to binary and rearrange it to be
%//   an array of vectors: [x_displacement; y_displacement]
d=reshape(rot90(dec2bin(hex2dec(strsplit(input('','s'),':'))))>'0',2,[])*2-1;

%// start position array with vector for the start position
p=[9;5];
%// for each move, add displacement, clamping to valid values
for m=1:64 p=[max(min(p(:,1)+d(:,m),[17;9]),1) p];end;

%// alphabet for our fingerprint
A=' .o+=*BOX@%&#/^SE';

%// create a sparse matrix, accumulating values for duplicate
%// positions, and replace counts with symbols
F=A(sparse(p(2,:),p(1,:),1,9,17)+1);

%// correct the start and end symbols and construct the final output
F(5,9)='S';F(p(2,1),p(1,1))='E';
[a='+-----------------+';b=['|||||||||']' F b;a]

Sample run:
>> bish
b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b
ans =

+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

Pyth, 145 143 140
Jm*17]09A,4K8FYcz\:V4AmhtS[0^2d+@,HGdtyv@+_.BiY16*7\0+-4dyN),3 4 X@JGHh@@JGH; X@J4K15 X@JGH16
=Y++\+*17\-\+VJ++\|s@L" .o+=*BOX@%&#/^SE"N\|)Y

Try it online.
Pyth isn't really good at challenges with iteration. I'm expecting CJam to beat it easily.

JavaScript (ES6) 249 208
Edit Added missing border
Test running the snippet below in any EcmaScript 6 compliant browser

B=f=>f.replace(/\w+/g,b=>{for(b=`0x1${b}`;b-1;b>>=2)++g[p=(q=(p=(q=p+~-(b&2)*18)>0&q<162?q:p)+b%2*2-1)%18?q:p]},p=81,z=`+${'-'.repeat(17)}+`,g=Array(162).fill(0))&&g.map((v,q)=>q?q-81?q-p?q%18?' .o+=*BOX@%&#/^'[v]:`|
|`:'E':'S':z+`
|`).join``+`|
`+z

// TEST
console.log=x=>O.innerHTML+=x+'\n'

;['37:e4:6a:2d:48:38:1a:0a:f3:72:6d:d9:17:6b:bd:5e'
,'16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
,'b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b'
,'05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47'
].forEach(t=>console.log(t+'\n'+B(t)+'\n'))

// Less golfed

BB=f=>(
  p = 81,
  g = Array(162).fill(0),
  f.replace(/\w+/g, b => {
    for(b = `0x1${b}`;b != 1; b >>= 2)
      q = p+~-(b&2)*18,
      p = q>0&q<162?q:p,
      p = (q=p+b%2*2-1)%18?q:p,
      ++g[p]
  }),
  g.map((v,q) => q-81?q-p?q%18?' .o+=*BOX@%&#/^'[v]:'\n':'E':'S')
  .join``
)
pre { font-family: menlo,consolas; font-size:13px }

Your golfed code itself should be capable to print the borders too. Currently only your test case prints the upper and lower borders in the forEach, the vertical borders are still missing.

@Padarom I misunderstood your "be reasonable" comment, thinking that the border was not requested

I meant be reasonable as to which method of input and output you use. My apologies if that was misleading, I'll edit it out

Python, 381328
-51 thanks to @JonathanFrech
def h(f):
 s=[f'{int(o,16)>>s&3:02b}'for o in f.split(':')for s in(0,2,4,6)];r=[0]*153;p=76;w=17
 for d in s:r[p]+=1;p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]
 r[76]=15;r[p]=16;b='+'+'-'*w+'+';print(b);i=0
 while i<153:print(f"|{''.join(' .o+=*BOX@%&#/^SE'[c]for c in r[i:i+w])}|");i+=w
 print(b)

Slightly ungolfed for the sake of explanation:
def h_(f):
 #Alias 17 because it gets used enough times for this to save bytes
 w=17

 #Input parsing
 s=[f'{int(o,16)>>s&3:02b}'for o in f.split(':')for s in(0,2,4,6)]

 #Room setup
 r=[0]*153
 p=76

 #Apply movements
 for d in s:
  r[p]+=1
  p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]
 r[76]=15 #Set start position
 r[p]=16 #Set end position

 #Display result
 b='+'+'-'*w+'+'
 print(b)
 i=0
 while i<153:
  print(f"|{''.join(' .o+=*BOX@%&#/^SE'[c]for c in r[i:i+w])}|")
  i+=w
 print(b)

This mess of a line:
r[p]+=1;p+=(-(p%w!=0),p%w!=16)[int(d[1])]+(-w*(p//w!=0),w*(p//w!=8))[int(d[0])]

is functionally equivalent to this:
if int(d[0]): #Down, Y+
  if p//17!=8:
    p+=17
else: #Up, Y-
  if p//17!=0:
    p-=17

if int(d[1]): #Right, X+
  if p%17!=16:
    p+=1
else: #Left, X-
  if p%17!=0:
    p-=1

but nests all of the conditionals in this style of golf shortcut: (false_value,true_value)[condition]
Hopefully the rest is fairly self-explanatory
Tests
h('16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48')
+-----------------+
|        .        |
|       + .       |
|      . B .      |
|     o * +       |
|    X * S        |
|   + O o . .     |
|    .   E . o    |
|       . . o     |
|        . .      |
+-----------------+

h("b6:dd:b7:1f:bc:25:31:d3:12:f4:92:1c:0b:93:5f:4b")
+-----------------+
|            o.o  |
|            .= E.|
|             .B.o|
|              .= |
|        S     = .|
|       . o .  .= |
|        . . . oo.|
|             . o+|
|              .o.|
+-----------------+

h("05:1e:1e:c1:ac:b9:d1:1c:6a:60:ce:0f:77:6c:78:47")
+-----------------+
|       o=.       |
|    o  o++E      |
|   + . Ooo.      |
|    + O B..      |
|     = *S.       |
|      o          |
|                 |
|                 |
|                 |
+-----------------+
```

Hello and welcome to PPCG. You can golf your code by using one-letter variable names and putting a single-line-for-loop into one line. (1,0)[p%17==16] is +(p%17!=16), or possibly even p%17!=16.

Furthermore, there is a superfluous space in ] for.

I think fp should be f.

330 bytes.

@JonathanFrech Thanks for taking the time to optimize my answer. I missed some obvious ones in there, but there are some things you did that I'm having trouble wrapping my head around. For one, why use ~16 instead of -17 when they're the same length and appear to have the same result? I'll update this with your changes (and credit to you, of course) when I get home tonight.

Why did I use ~16? A bit of obfuscation can never hurt your golf!

However, as a very broad and general golfing tip, the identity ~x == -x-1 is often very useful. If you have any other questions, please do not refrain from asking them.

@JonathanFrech Haha, well I can't argue with that. I'll keep the tip about the bitwise NOT operator in mind next time I try to golf a problem, thanks!

Ruby 288
->k{w=17
r=[z=?++?-*w+?+]
(0...w*9).each_slice(w).map{|o|r<<?|+o.map{|x|c=76
q=0
k.split(?:).flat_map{|b|(0..7).map{|i|b.to_i(16)[i]}}.each_slice(2){|h,v|v<1?(c>w&&c-=w):c<w*8&&c+=w
c+=h<1?c%w>0?-1:0:c%w<16?1:0
c==x&&q+=1}
x==76?'S':c==x ?'E':' .o+=*BOX@%&#/^'[q]}.join+?|}
(r+[z]).join'
'}

Try it online: http://ideone.com/QOHAnM
The readable version (the one I started golfing from) is here: http://ideone.com/XR64km

C 361
Thanks to @ceilingcat for some very nice pieces of golfing - now even shorter
#define H h[i]|=*++p-48-*p/59*39
#define L puts("+-----------------+")
#define F(m,s)for(m=0;m<s;m++)
h[16],m[17][9],i,j,n,x=8,y=4;main(w,v)char**v;{for(char*p=v[1]-1;i<16;p++,i++)H<<4,H;F(j,16)F(n,4)x+=h[j]>>n*2&1?x!=16:-!!x,y+=h[j]>>n*2&2?y!=8:-!!y,m[x][y]++;m[8][4]=15;m[x][y]=L-4;F(i,9){printf("|");F(j,17)printf(L" .o+=*BOX@%&#/^SE"+m[j][i]);puts("|");}L;}

Try it online!

@ceilingcat  I did the ++p separately because it is UB to do it in an expression when there is more than one p in the expression - however, if it works on TIO I think it is allowed.  Thanks!

@ceilingcat Nice find, thank you

C (gcc), 333 326 314 292 288 bytes
f[17][9],i,x=8,y=4;main(n){for(;i++%4||read(0,&n,3)*sscanf(&n,"%x",&n);n/=4)f[x+=n%2?x<16:-!!x][y+=n&2?y<8:-!!y]+=f[x][y]<14;f[8][4]=15;for(f[x][y]=puts(n="+-----------------+")-4;++i<75;puts("|"))for(x=!printf("|");x<17;)putchar(" .o+=*BOX@%&#/^SE"[y=fmin(f[x++][i-66],16)]);puts(n);}

Try it online!
Golfed from openssh source code key_fingerprint_randomart().
Edit: Now a complete program.
Less golfed:
/* initialize field */
f[17][9],i,x=8,y=4;
main(n){
  /* process raw key */
  /* each byte conveys four 2-bit move commands */
  for(;i%4||read(0,&n,3)+sscanf(&n,"%x",&n);n/=4)
    /* evaluate 2 bit, rest is shifted later */
    /* assure we are still in bounds; augment the field */
    f[x+=n%2?x<16:-!!x][y+=n&2?y<8:-!!y]+=f[x][y]<14;

  /* mark starting point and end point; output upper border */
  f[8][4]=15;
  f[x][y]=puts(n="+-----------------+")-4

  /* output content */
  for(;++i<75;puts("|"))
    for(x=!printf("|");x<17;)
      /*
       * Chars to be used after each other every time the worm
       * intersects with itself.
       */
      putchar(" .o+=*BOX@%&#/^SE"[y=fmin(f[x++][i-66],16)]);

  /* output lower border */
  puts(n);
}

Burlesque, 200 bytes
':;;m{b6b28'0P[2cob2^p}m{{-1 1}Jcpj!!}{4 8}+]qr{?+q0cy{>.}Z]{8 16}cy{<.}Z]}pal_g_jf:u[j" .o+=*BOX@%&#/^"XXbcjq!!Z]z[{(D!)_+p^}m[' 17.*9.*)XXje!j'SD!j'ED!"|\n|"IC'|+]'|[+\['+'-17.*_+<-"+\n".+J<-#rCL\[Q

Try it online!
':;;                # Split at colons
m{                  # Map over these
 b6b2               # Read as hex, then to binary
 8'0P[              # Pad to 8 bit
 2co                # Chunks of 2
 b2                 # Read as binary
 ^p}                # Push each
m{                  # Map over these
 {-1 1}Jcp          # Construct direction array {{- -}{- +}{+ -}{+ +}}
 j!!                # Select the block indexed by binary val
}
{4 8}+]             # Push starting pos
qr{                 # Boxed reduce
 ?+                 # Add together
 q0cy{>.}Z]         # If < 0 -> 0
 {8 16}cy{<.}Z]     # If > box -> boxwidth
pa                  # Apply on inits
l_g_j               # Take start and end for later
f:                  # Calculate frequency of everything but head and tail
u[j                 # Unzip to {pos} {counts}
" .o+=*BOX@%&#/^"XXbcj # Magic string
q!!Z]               # Select element based on count
z[                  # Rezip to {pos icon}
{(D!)_+p^}m[        # Add D! (set at pos) to the each
' 17.*9.*)XX        # Create 17x9 array of spaces
je!                 # Evaluate block of ({pos icon D!}, ...)
j'SD!j'ED!          # Set start and end to S & E
"|\n|"IC            # Intercalate surrounding v-bars
'|+]'|[+            # Add first and last
\[                  # Concatenate
'+'-17.*_+<-"+\n".+ # Create top-bar
J<-                 # Duplicate and reverse (putting newline at the front
#r                  # Rotate stack
CL                  # Collect stack as list
\[                  # Concatenate
Q                   # Pretty print

Java 11, 460 453 452 449 bytes
interface M{static void main(String[]a){var m=new char[9][17];Integer x=4,y=8,i=0,s;for(var p:a[0].split(":"))for(p=x.toString(x.parseInt(p,16),2),i=4;i-->0;m[x-=s<2?x>0?1:0:x/8-1][y-=s%2>0?y/16-1:y>0?1:0]++)s=x.decode(("0".repeat(8-p.length())+p).split("(?<=\\G..)")[i]);String t="+"+"-".repeat(m[x][y]=16)+"-+\n",r=t+"|";for(m[4][8]=15;++i<153;r+=y>15?"|\n"+(x<8?"|":""):"")r+=" .o+=*BOX@%&#/^SE".charAt(m[x=i/17][y=i%17]);System.out.print(r+t);}}

-11 bytes thanks to @ceilingcat.
Try it online.
Explanation:
interface M{              // Class
  static void main(String[]a){
                          //  Mandatory main method
    var m=new char[9][17];//   Create a character-matrix of size 9 by 17
    Integer x=4,y=8,      //   Current position, starting at 4,8
            i=0,s;        //   Temp integers
    for(var p:a[0].split(":"))
                          //   Loop over the argument-String, split by ":"
      for(p=x.toString(x.parseInt(p,16),
                          //    Convert the current part from hexadecimal String to integer
                       2),//    And then from integer to binary String
          i=4;i-->0       //    Inner loop `i` in the range (4,0]:
          ;               //      After every iteration:
           m[x-=          //       Update the `x` position:
                s<2?      //        If `s` is 0 or 1:
                 x>0?     //         If we're not out of bounds yet at the top:
                  1       //          Go up
                 :        //         Else:
                  0       //          Stay at the top border
                :         //        Else (s is 10 or 11):
                 x/8      //         If we're not out of bounds yet at the bottom:
                  -1]     //          Go down
                          //         Else:
                          //          Stay at the bottom border
            [y-=          //       Update the `y` position:
                s%2>0?    //        If `s` is odd (1 or 11):
                 y/16     //         If we're not out of bounds yet at the right side:
                  -1      //          Go right
                          //         Else:
                          //          Stay at the right border
                :         //        Else (s is 0 or 10):
                 y>0?     //         If we're not out of bounds yet at the left side:
                  1       //          Go left
                 :        //         Else:
                  0]      //          Stay at the left border
                    ++)   //       And increase the value at x,y cell by 1
        s=                //     Set `s` to:
          x.decode(("0".repeat(8-p.length())+p)
                          //      Left-pad the binary-String `p` with 0s up to length 8
                   .split("(?<=\\G..)")
                          //      Split it into parts of size 2
                   [i]    //      Get the `i`'th part
                      );  //      And convert it from binary-String to integer
                          //   After the nested loops are done:
    String t="+"+"-".repeat(m[x][y]=16
                          //   Set the value at position x,y to 16
                      )+"-+\n",
                          //   Push a temp String for the top/bottom borders
           r=t+"|";       //   Result-String, starting with the top border + one "|"
    for(m[4][8]=15;       //   Set the value at position 4,8 to 15
        ;++i<153          //   Loop over all cells:
        ;                 //     After every iteration:
         r+=              //      Append the following to the result-String:
            y>15?         //       If we're done with a row:
             "|\n"        //        Append "|" and a newline
             +(x<8?       //        And unless it's the last row:
                "|"       //         Also append a "|"
               :          //        If it is the last row:
                "")       //         Append nothing
            :             //       And if we're not done with the row yet:
             "")          //        Append nothing
      r+=                 //    Append the following to the result-String:
         " .o+=*BOX@%&#/^SE".charAt(m[x=i/17][y=i%17]);
                          //     The `i`'th character of the String " .o+=*BOX@%&#/^SE"
                          //     where `i` is the current value of cell x,y
    System.out.print(r    //   And finally output this result-String,
      +t);}}              //   including its bottom border

Perl 5, 283 276 266 254 + 1 (-p) = 255 bytes
$x=8;$y=4;for$n(map{hex}split(/:/)){$n&2?$y<8&&$y++:$y&&$y--,$n&1?$x<16&&$x++:$x&&$x--,$a[$x][$y]++,$n>>=2 for 1..4}$a[8][4]=15;$a[$x][$y]=16;map{$y=$_;$s.="|";$s.=substr' .o+=*BOX@%&#/^SE',$a[$_][$y],1 for 0..16;$s.="|
"}0..8;$l='-'x17;$_="+$l+
$s+$l+
"

Uses -p to take a line of input into $_, and to print the (modified) value of $_ at the end.
Try it online!
Ungolfed:
# Implicit from running with perl -p:
# read line from standard input
#while($_ = <STDIN>) {

# Initialise starting coordinates
$x=8;
$y=4;

# Split input line at colons, convert each element (2-digit hex value) to integer,
iterate over the list of integers
for $n (map { hex($_) } split(/:/))
{
    # for each integer, iterate 4 times, looking at 2 of the 8 bits each time
    for(1..4)
    {
        # if second-last bit is set
        if($n & 2) {
            # move down, unless we are already at the bottom
            $y++ if($y < 8);
        }
        else {
            # move up, unless we are already at the top
            $y-- if($y);
        }

        # if last bit is set
        if($n & 1) {
            # move right, unless already at the right edge
            $x++ if($x<16);
        }
        else {
            # move left, unless already at the left edge
            $x-- if($x);
        }

        # Increment the counter for this position
        $a[$x][$y]++;

        # Shift number right two bits for next iteration
        $n = $n >> 2
    }
}

# Set fixed values (15 and 16) for start and end positions respectively
$a[8][4] = 15;
$a[$x][$y] = 16;

# Iterate over the rows of the grid, building a string containing the output rows
for(0..8)
{
    # save the y-coordinate for use in inner loop below
    $y = $_;

    # append the line start
    $s .= "|";

    # iterate over the columns of the row
    for(0..16)
    {
        # get the value for this position
        $v = $a[$_][$y];

        # map the value to the appropriate character
        $s .= substr(' .o+=*BOX@%&#/^SE', $v, 1)
    }

    # append the line end
    $s .= "|\n"
}

# build the hyphen lines for the top and bottom rows
$l = '-' x 17;

# build the full output string and assign to $_
$_ = "+$l+\n$s+$l+\n"

# Implicit from running under perl -p
#print $_;
#}

Rust - 509 bytes
fn b(s:&str)->String{let(mut v,mut b)=([[0;11];20],[9,5]);v[19]=[19;11];for i in 0..16{let mut c=usize::from_str_radix(&s[i*3..i*3+2],16).unwrap();for k in 0..4{for j in 0..2{v[j*18][i%9+1]=18;v[i+k][j*10]=[17,3][(i+k+17)%18/17];b[j]=match(if c&(j+1)==j+1{b[j]+1}else{b[j]-1},j,){(0,_)=>1,(18,0)=>17,(10,1)=>9,x@_=>x.0 as usize,}}v[b[0]][b[1]]+=1;c>>=2;}}v[9][5]=15;v[b[0]][b[1]]=16;(0..220).fold("\n".to_string(),|s,i|{format!("{}{}",s," .o+=*BOX@%&#/^SE-|\n".chars().nth(v[i%20][i/20] as usize).unwrap())})}

Large but... almost close to C. As usual there are many bytes used up due to the way Rust does not automagically cast types into each other. But there is also probably room for improvement.... could probably use some ideas from other solutions.
ungolfed version is on the Rust Playground online

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
The Cake Cutting Contest
It's my 17th birthday and you're invited to my party!
And as always at parties, there will be cake.
One cake...
And you need as much of it as possible.
As this is a fair party, each of us will say how much of my cake we want and the person who said the smallest amount will get it. Then everyone else gets to repeat the process until the cake is gone.
Challenge

Given the input through command line arguments in the form of total-degrees degrees-left total-people people-left, output to standard output integer-bid-in-degrees.
If your bid was the lowest, you receive that amount of cake and are out for the round.
If your bid wasn't lowest, your bot gets to bid on the remaining cake.
In the case that the lowest bids are the same, the person removed will be chosen at random.
At the end of a round, once all the cake is gone or there is nobody left to bid on it, the person with the most cake wins!
In the case at the end of a round and two people have the same sized biggest slice, the winner is chosen at random from the drawing entries.

Gameplay

There will be 17 rounds, the overall winner will be the entry with the most wins overall.
In the case of a draw, rounds will be played until there is a clear winner.
Each day, I will update the current scores so that people can upgrade their entry.

Submission
You should write your entry as

Bot Name, Language
Insert
Code
Here

Explanation/Random stuff here

If your entry isn't formatted in this way, the controller will NOT be able to run your entry. If I find this has happened to your entry, I will either notify you in a comment, and/or edit the answer into the correct format.
Your entry and file storage

Your bot may store files in the ./data/ directory and nowhere else.

Not required but please store your files as botname*
You may not write files in this format if botname is not your entries name.
This means you are allowed to overwrite other files you find that don't appear in this format. You shouldn't do this deliberately, please be sporting.
Your bot must not assume that the files it requires are present but it can assume ./data/ exists.
This is because I occasionally wipe the ./data directory, I will do this when the rounds actually start. (But not between them)

Your bot may not delete files at all
Your bot is only allowed to read files in the ./data/ directory

This means you may look at other entries files

Results:
Meek won the contest! Well done @Cabbie407
And now for some random stats:
A list of positions each bot came in: (Well done to any bot appearing in this list, you came in the top 5 at least once!)

Meek, Meek, Eidetic, Eidetic, Meek, Eidetic, Eidetic, Meek, Meek, Meek, Saucy, Meek, Givemethecake, Givemethecake, Givemethecake, Meek, Eidetic
Eidetic, Eidetic, Meek, AlCakeSurfer, Eidetic, AlCakeSurfer, Meek, MyFairPlusAThird, Eidetic, Eidetic, Eidetic, Eidetic, MyFairPlusAThird, MyFairPlusAThird, Meek, MyFairPlusAThird, AlCakeSurfer
Reallythecake, AlCakeSurfer, AlCakeSurfer, Meek, AlCakeSurfer, Meek, AlCakeSurfer, AlCakeSurfer, Reallythecake, AlCakeSurfer, Meek, MyFairPlusAThird, Eidetic, Eidetic, Eidetic, Eidetic, Reallythecake
AlCakeSurfer, Reallythecake, MyFairPlusAThird, MyFairPlusAThird, MyFairPlusAThird, MyFairPlusAThird, MyFairPlusAThird, Eidetic, AlCakeSurfer, MyFairPlusAThird, MyFairPlusAThird, Relinquisher, Relinquisher, bill, bill, Relinquisher, MyFairPlusAThird
bill, MyFairPlusAThird, bill, bill, bill, bill, Relinquisher, Relinquisher, MyFairPlusAThird, Relinquisher, bill, Reallythecake, bill, ALittleOffTheTop, ALittleOffTheTop, bill, bill

The full log file for the cometition whilst running can be found here. Sorry about the format change partway through.
I will not be running the contest again, if you want to post more entries, you're welcome to do so, the controller can be found on my github repo for this contest.

In case you think that the algorithm boils down to ceil(degrees/people) , please see the contests sandbox entry here http://meta.codegolf.stackexchange.com/a/7095/32686.

Can we save information to a file?

Sure as long as it puts it in the directory ./data/ (Also, the controller doesn't scrape, I do that manuallyish)

How long is the contest open?

I request a ring cut around the outside perimeter. Technically 0 degrees (the cake still has 360 degrees when I'm done, after all) and I get all the side icing.

Happy Birthday :)

Link to controller?

Results for one round if anyone's interested, {u'StatelyImitator': 719, u'Dieter': 4, u'Reallythecake': 0, u'Greedy': 0, u'Meek': 2, u'FlamingChainsaw': 0, u'Slim': 0, u'CharityBot': 0, u'Gentleman': 297, u'ALittleOffTheTop': 256, u'EatThe\u03c0': 0, u'Pig': 0, u'CakeEater': 330, u'BobBarker': 0, u'FloorBot': 5, u'Fatbot5000': 296, u'Moses': 360, u'Magician': 720, u'Hungry': 257, u'Imitator': 354} [u'Magician']. If your bot has a score of 0, it's doing something wrong.

@TheNumberOne Link to controller and answer puller (no they're not very pretty) https://github.com/muddyfish/cake-cutting-contest

How many degrees of cake did that round start with? Adding it all up, I get 3303.

3600, no,  I'm not sure what happened there. I have checked the recent logs and they seem right. I won't be looking at this more until tomorrow, sorry if any issues arise.

I get 3600 for the sum. 719+4+0+0+2+0+0+0+297+256+0+0+330+0+5+296+360+720+257+354=3600

Well, maybe I missed some. I was just doing a quick calculation on my tablet. But Slim and Flaming Chainsaw (and a few others) are not going to win by any stretch. ;)

You don't say? I think Magician will win.

It would've, if it hadn't been changed...

At some point, statelyimitator was winning with other 1/3 of the cake!

Happy my bot fails gracefully when faced with magically created cake.

Can't wait to see how my bots do next time the controller is run :) This is an awesome AI experimentation challenge!

Well, here is another set of results {u'Reallythecake': 376, u'FlamingChainsaw': 0, u'Gentleman': 227, u'EatThe\u03c0': 0, u'Relinquisher': 0, u'CakeEater': 282, u'Imitator': 34, u'Moses': 243, u'StatelyImitator': 485, u'Greedy': 5, u'ALittleOffTheTop': 211, u'Fatbot5000': 372, u'Magician': 720, u'Meek': 226, u'CharityBot': 0, u'Hungry': 212, u'Impatient': 0, u'FloorBot': 0, u'Dieter': 4, u'Fair': 0, u'Slim': 0, u'Pig': 0, u'BobBarker': 203} [u'Magician']

That's weird, both of mine got 0. I wonder what went wrong?

Just checking now in case it's something I did wrong

If you've generated debug info, such as how much each bot bidded for each time around, that might be useful.

Yeah I have that. You want it? If so how?

Upload to GitHub, maybe?

Log file (log.log) is on the repo

OK, fixed a bug where the controller gave the current number of people for both args

@muddyfish Can you push the bugfix to github?

@muddyfish Could you update the GitHub repository to the same code which produced the log file, please? It seems your script is invoking Node.js wrong.

How was there 3600 degrees of cake per round? Your challenge explicitly states One cake, so the maximum should be 360? Is there more than one cake?

I just noticed that in the debug file, Relinquisher bid for the entire cake every time. Was this due to the bug you fixed?

@TimmyD could be a tiered cake. Or have strange fractal geometries.

@toothbrush The reason that node.js isn't working is because I've never used it and am probably going to look up a way to run it tomorrow unless someone does a pull request on how to fix it as well as installation instructions for me :) Also, pushed bugfix

"There will be 17 rounds, the overall winner will be the entry with the most wins overall."
But, you can only "win" once, right? Then you're out of the game.

I mean the controller will run a full game 17 times

Please format the leaderboard in a more reader-friendly manner.

Muddyfish, initially mybot showed the score of 0, but now its not in the list why

When will this actually start and how long will the interval between the rounds be to tune the robot? Just asking, because I don't have too much time at the moment.

@superjedi you're welcome to edit the question if you want. Kishan Kumar, your bot takes input from stdin rather than argv, I was pretty sure I had already commented but I guess I forgot. Cabbie, I haven't decided yet.

@muddyfish now my bot takes input from argv.

@TimmyD There is only one cake, I'm just using a very weird measurement where the are 3600 degrees in a circle (think gradians weird)

@muddyfish gradians? Much more like cakeians, right?

Can we access the internet?

@muddyfish can you please add the time in the log file. And I couldn't find all  the bidding of my bot.

No, you can't access the internet (yes, I can see that it would be useful), by time, dou you mean the actual times? Bot's aren't allowed to look in the log files.

@muddyfish I m not able to see all my biddings in the log.log file

I spent a while trying to code one in Piet, but the lack of decimals makes it too hard :(

@muddyfish how much time will be between your announcing of when the challenge starts and the actual start? Will it be like 'okay, starting now!' or will you announce 'challenge starts tomorrow!'? I would love to enter another bot, but I still need to get the weighting function sorted …

Yes I restarted the contest because I realised the way I was starting it overwrote the log file the website reads from. Sorry!

What happened there? Log overflow? Okay... I thought it stopped. Nevermind.

I updated the site server so it has 2 log files that you can look at. the second one hasn't been cleaned in ages so it has lots of non-contest data in it

Hooray, Relinquisher managed to come in 4th and 5th a few times, and consistently scored 1700+! :) Thanks for this awesome experiment!

That was certainly a fun contest!

Meek, awk
BEGIN{srand();print int(rand()>=.5?ARGV[2]/2.89:ARGV[1]/10-rand()*13)}

I saw this once in a simulation.

Have an upvote, your bot's doing damn well =O

Thanks. Well it's no coincidence. I actually ran the controller myself, trying to write a smarter bot. But most of the time it was beaten by the most simple bots. So I ended up using a pretty simple strategy, which won most of the time with a randomly sized cake.

Magician, Java
public class Magician{
    public static void main(String[] args){
        System.out.println(720);
    }
}

The number 720 is magical.
This is was meant to test the controller and is not a serious entry.

I think this was actually winning the contest the way it was originally, with a score of 720 here.

SadBot :(, C++
#include<iostream>
#include<cstdlib>
#include<stdlib.h>
int main(int argc, char**argv)
{
    if (argc!=5){std::cout<<"Incorrect number of arguments";return 1;}
    double list[4];

    list[0]= atof(argv[1]); // total Degrees
    list[1]= atof(argv[2]); // degrees left
    list[2]= atof(argv[3]); // total people
    list[3]= atof(argv[4]); // people left

    std::cout<<list[1]/list[3]; // degrees left/ people left

    return 0;
}

Formerly FairBot
FairBot just wants an equal portion :(
He wants to split the cake evenly amongst all the participants.
(He fully expects the other bots to rip him off though because he knows they're mean)
(Like really. He is lonely, he just wants the other bots to like him)
(He just got out of a bad relationship and is going through a really rough patch, so if you could just give him a pat on the back and a smile to make him feel better it would really mean a lot. )
EDIT changed program to take input from argv/c instead of stdin (fair bot is still sad.... He wants to change his name to sadbot (which is kinda why he wants cake))

Can you make it so it takes the args from argv rather than stdin?

As you have commanded, so it is done.

You can change your name to sadbot if you want.

Also, the brackets need to be put inside the code block

Ok, now I'm getting 'atof' was not declared in this scope

atof should be in the C++ standard (should even work in C if I'm not mistaken). I added some includes so hopefully it should work now.

g++ $1 -o ./bots/$2; ./bots/$2 $3 $4 $5 $6

Is it still throwing the error after you add the extra includes?

Nope, your bot scored 0, (it prints out 0.00833333 when ran as sh "./commands/c++.sh" "./bots/SadBot.cpp" SadBot 3600 3600 30 30)

I have the input order backwards. I'll swap it around. Wow I'm bad at this. Should now cout 120 in that situation.

Ok, now its getting 144/3600 pieces (winner is getting 649)

And hence he is a sad bot.

Slim, Python 2
print 0

This bot's on a diet.

Halver, Ruby
def halver(total_degrees, degrees_left, total_people, people_left)

  if people_left == 1
    degrees_left
  else
    degrees_left/2 - 1
  end

end

p halver(*ARGV.map(&:to_i))

Scrupulously, unimpeachably fair. Half the cake for me, half the cake for everyone else.

CharityBot, Python 2
print -360

Adds another cake to the mix!
(The controller will see this as a request for 0 cake, will not actually add to the size of the cake)

Dieter, Java
public class Dieter {
    public static void main(String... args){
        System.out.println("4");
    }
}

It doesn't want to bid for too much cake, so it chooses a small but guaranteed random slice.

If you downvote my posts please explain why. Otherwise I can never improve!

Oh. I just assumed you could guess that the downvote was because it appears you're just blatantly using an xkcd ref for laughs/votes, not caring that it will most likely never win a single game.

Yeah, I downvoted too. You can find this "joke" all over this site, it's just not funny anymore.

We have a standard loophole addressing the use of fake random numbers (in which this particular xkcd is explicitly referenced). Since the challenge doesn't require randomness in the submissions, this isn't necessarily a violation of the loophole, but still. ಠ_ಠ

I understand. Right now I can't really write/debug code so I thought I'd submit something stupid and make a real entry later.

I understand that, but don't then act surprised if someone downvotes your "something stupid".

Up vote to counter people with no humor

Downvote to counter people with stale humor.

Stately Imitator, Ruby
def stately_imitator(total_degrees, degrees_left, total_people, people_left)

  current_winner_path = './data/current_winner'
  previous_cake_path = './data/previous_cake'

  first_move = (total_people == people_left)

  current_winner = first_move ? 0 : File.read(current_winner_path).to_i
  previous_cake = first_move ? total_degrees : File.read(previous_cake_path).to_i

  last_slice = previous_cake - degrees_left
  current_winner = [current_winner, last_slice].max

  File.open(previous_cake_path, 'w') { |f| f.puts(degrees_left)   }
  File.open(current_winner_path, 'w'){ |f| f.puts(current_winner) }

  if first_move
    degrees_left / 2
  else
    average_left = degrees_left.fdiv(people_left).ceil
    bid = [average_left, current_winner+1].max
    [bid, degrees_left].min
  end

end

p stately_imitator(*ARGV.map(&:to_i))

Variant of Imitator (if you'd rather only one entry per player, this supersedes that one). Keeps precise track of the largest slice taken already, and always bids enough to beat that slice. Will also never bid lower than its fair share of the remainder. Assumes a read/writable './data' directory already exists; the files can either be there already or not.

In case you didn't notice, I have multiple answers too (but only one of them is sensible)

there's good news and bad. Bad - there's a bit that changes your config files. Good - your bot actually does better! 505/3600, it won the last round I did!

Flaming Chainsaw, Java
public class FlamingChainsaw
{
    public static void main(String[]args)
    {
        if(args.length<4){return;}
        if(Integer.parseInt(args[3])<3){System.out.println(0);}
        else{System.out.println(args[1]);}
    }
}

Have you ever tried holding a cake-cutting contest with a chainsaw?  Well, now you have.  It's rather disruptive.

I find that I can usually tune out the chainsaw noise, but it sure does make a mess when you use it to cut the cake.

This is an exotic way to light the candles.

Gentleman, Java
import static java.lang.Integer.parseInt;
import java.io.*;
import java.util.*;

public class Gentleman{
    private final static String FILE_NAME = "data/Gentleman.txt";

    static {
        new File("data").mkdir();
    }

    public static void main(String[] args) throws Exception{
        int totalCake = parseInt(args[0]);
        int cakeLeft = parseInt(args[1]);
        int totalPeople = parseInt(args[2]);
        int peopleLeft = parseInt(args[3]);

        if (totalCake == cakeLeft){
            System.out.println(cakeLeft);
        } else {
            int previousCake = load();
            int cakeDiff = previousCake - cakeLeft;

            if (cakeDiff > optimal(previousCake, peopleLeft + 1)){
                System.out.println(peopleLeft == 1 ? cakeLeft : Math.min(cakeLeft, cakeDiff + 1));
            } else {
                System.out.println(cakeLeft);  //Hey, I might get lucky :)
            }
        }
        save(cakeLeft);
    }

    private static void save(int cake) throws Exception{
        PrintStream out = new PrintStream(FILE_NAME);
        out.print(cake);
    }

    private static int load() throws Exception{
        Scanner in = new Scanner(new File(FILE_NAME));
        return in.nextInt();
    }

    private static int optimal(int cake, int people){
        return (cake + people - 1) / people;
    }
}

He waits for people who eat a fair share or less before he eats any cake. To prevent the greedy from getting extra cake, he takes as large a portion as possible.

Bob Barker, Java
public class BobBarker{
    public static void main(String[] args){
        System.out.println((int)Math.floor(Integer.parseInt(args[1]) * .84));
    }
}

This is probably going to be replaced with a more thought-out solution later, but I'm curious if this will work. This is just to catch any bots that try and go for maximum, and do a modified Price is Right strategy to steal their answer. Might lead to escalation with increasing integer subtractions, that'd be neat.
EDIT: Escalation commences, counter-posting against FloorBot

I moved your description to the bottom to match the challenge's formatting requirements.

@PhiNotPi, woops, forgot about that requirement. Thanks for fixing it!

Hah, I just had the same thought

Well, the answer parser looks at the first line and then at the first code block. Also, you need to convert args[1] to an int before doing subtraction.

@thefistopher you still need to do int conversion

@muddyfish Sorry! Is it working now?

Yep, your bot's getting 299 of 3600 pieces, the winner has 701. Good luck!

OMG! it's Bot Barker!

Eidetic, Python 2
import random, math, sys, json

total_degrees, degrees_left, total_people, people_left = map(int, sys.argv[1:])
#try:
#    inp_f = open("./data/Eidetic.json", "r")
#    out = json.load(inp_f)
#except (IOError, ValueError):
out = {"last_cake": 0,
           "runs": 0,
           "total_runs": 0,
           "total_rounds": 0,
           "training":  [[0.0], [0.0], [0.12903225806451613], [16.774193548387096], [400.83870967741933], [720.0], [995.8709677419355], [996.9437634408603], [997.6], [997.6], [997.6], [998.5991397849463], [996.6770967741936], [998.8122580645161], [1011.5467420570814], [1017.7717824448034], [1227.155465805062], [1280.7840603123318], [1435.8028540656974], [1553.3689822294023], [1793.5330640818527], [2299.178101402373], [3183.924709689701], [2231.666666666667], [2619.4789644012944], [1270.9288025889969], [741.2718446601941], [480.4757281553398], [122.66990291262135], [27.54736842105263]]}

#else: inp_f.close()

def write_out():
    out_f = open("./data/Eidetic.json", "w")
    out_f.write(json.dumps(out))
    out_f.close()

def get_last_winner(): # Find the bid of the last winner
    bid = out["last_cake"]
    return max(bid, degrees_left) - degrees_left

def train():
#    print degrees_left # If you get that much, your probably safe.
#    sys.stderr.write("\nEidetic - Training len %s, no runs: %s, no_rounds: %s, last winner: %s\n"%(len(out["training"]), out["runs"], out["total_rounds"], get_last_winner()))
    if len(out["training"]) <= out["runs"]: out["training"].append([])
    out["training"][out["runs"]].append(get_last_winner())

def get_best_round():
    data = out["training"][out["runs"]+1:]
    mean = [sum(i)/(float(len(i)) or 1) for i in data]
    bid = max(mean+[0]) - 0.5
    sys.stderr.write("\nEidetic - mean %s\n"%mean)
    return bid

def main():
    reset = total_people == people_left
    if reset:
        out["total_rounds"] += 1
        out["runs"] = 0
    train()
    bid = get_best_round()
    print bid
#    sys.stderr.write('\nEidetic Bid: '+str(bid)+'\n')
    out["total_runs"] += 1
    out["runs"] += 1
    out["last_cake"] = degrees_left
    write_out()

main()

I ran this bot in the controller a couple of times to train it up a bit, it remembers the bids required to win each round and then once trained, it goes out into the real world and votes with the rest of them.

That's a clever way to do it; you're ahead of the pack now. I wonder if this could still get one-upped, though...

CoffeeJunkie, Coffeescript
#!/usr/bin/env node

# Require node fs
fs = require("fs")

# Happy birthday ;)
CAKECONSTANT = Math.round("""
                 /
               ,( ),
                 Y
                |-|
                | |
       _..--''''| |''''--.._
     .'   @_/-//-//>/>'/ @  '.
    (  @  /_<//<'/----------^-)
    |'._  @     //|###########|
    |~  ''--..@|',|}}}}}}}}}}}|
    |  ~   ~   |/ |###########|
    | ~~  ~   ~|./|{{{{{{{{{{{|
     '._ ~ ~ ~ |,/`````````````
        ''--.~.|/

""".length / 250 + Math.random())

# Some constants
OLD = "./data/CoffeeJunkie_oldcake.txt"
NEW = "./data/CoffeeJunkie_newcake.txt"

# How much cake do I want?
wantCake = (total_c, rest_c, total_p, rest_p) ->
    round = total_p - rest_p
    fairness = rest_c // rest_p

    switchMemory() if round is 0

    fairest_round = tryToRemember(total_p)
    tryToMemorize(fairness)

    if round >= fairest_round then fairness - CAKECONSTANT else total_c // 2

# Ok I should try to remember the last cake...
switchMemory = () ->
    try
        fs.renameSync(NEW, OLD)
    catch error

# What happend with the last cake?
tryToRemember = (rounds) ->
    try
        last_cake = fs.readFileSync(OLD, "utf-8")
        last_cake.trim().split(" ").map(
            (i) -> parseInt(i)
        ).reduce(
            (x, y, z, li) -> if y > li[x] then z else x
            0
        )
    catch error
        rounds / 2

# Watch what happens!
tryToMemorize = (fairness) ->
    try
        fs.appendFileSync(NEW, " " + fairness)
    catch error

# Coffee is ready, so... GO!
console.log(wantCake(process.argv[2..]...))

What exactly is a cake without a good cup of coffee?
The CoffeeJunkie prefers coffee over a slice of cake, but nevertheless wants to try some. He will always be fair to other participants and will try to remember what happened to the last cake. However, his excessive coffee consume has weakened his memories...

Can you rename the language to either coffeescript of node.js?

Done, though you need node.js to run and install: npm install -g coffee-script; coffee CoffeeJunkie.coffee

Are you sure that's a candle on your cake? It looks a little more... phallic :D

@BetaDecay ...any better? :D

@Cipher That's good :D

Saucy, Ruby
def saucy(total_degrees, degrees_left, total_people, people_left)

  current_winner_path = './data/saucy_current_winner'
  previous_cake_path = './data/saucy_previous_cake'

  first_move = (total_people == people_left)

  current_winner = first_move ? 0 : File.read(current_winner_path).to_i
  previous_cake = first_move ? total_degrees : File.read(previous_cake_path).to_i

  last_slice = previous_cake - degrees_left
  current_winner = [current_winner, last_slice].max

  File.open(previous_cake_path, 'w') { |f| f.puts(degrees_left)   }
  File.open(current_winner_path, 'w'){ |f| f.puts(current_winner) }

  if first_move
    degrees_left
  else
    average_left = degrees_left.fdiv(people_left).ceil
    beats_past_players = current_winner + 1
    beats_future_players = degrees_left/4 - people_left**2
    [average_left, beats_past_players, beats_future_players].max
  end

end

p saucy(*ARGV.map(&:to_i))

Saucy is willing to accept slightly less than half of the remaining cake, so long as it's more than anyone else has gotten or is likely to get (based on secret sauce).

AlCakeBot, Python
import sys, math

total_degrees, degrees_left, total_people, people_left = map(int, sys.argv[1:])

fraction_left = (degrees_left + 0.0)/ total_degrees
fraction_gone = 1.0 - fraction_left

factor = (math.sin(fraction_gone * math.pi / 2.0))**2
fraction = (factor/2.0) + 0.5

if total_degrees == degrees_left:
   print(int(math.floor(total_degrees/2.0) - 1))
else:
   print(int(math.floor(degrees_left * fraction)))

This is my first PCG post; I hope this works out as intended …
I love cake. No matter which kind. My colleagues know. And so does my bot. If the entire cake is still there, he will bid for just under half of it, hoping to get the biggest slice immediately. If not, he should bid for something between half the remaining cake and all the remaining cake, using a squared sine as a weighting function (½ + sin² (fraction gone) / 2). The reasoning being that there should be a chance for an overall larger (but fractionally smaller) slice early in the game and there also being little point in trying to be a gentleman in the late game.
Since I’m not very much into programming, I’ll appreciate any error pointed out. Now let’s eat some cake =D

IWMBAICBIWT, Python
import sys

degreesleft = int(sys.argv[2])
peopleleft = int(sys.argv[4])

print(round(degreesleft/peopleleft))

IWMBAICBIWT (It was my birthday and I cried because I wanted to) assumes that there is a relationship between the degrees left and the number of people left. Let's hope it works!
Should work in all Pythons.
Edit:
Storing sys.argv in inputs was a bit wasteful...

It should be degreesleft = int(inputs[2]); peopleleft = int(inputs[4]) and it's bidding 1 all the time

@muddyfish Edited

Stately Sabotage, Ruby
def stately_sabotage(total_degrees, degrees_left, total_people, people_left)

  current_winner_path1 = './data/current_winner'
  previous_cake_path1 = './data/previous_cake'
  current_winner_path2 = './data/statelysabotage-current_winner'
  previous_cake_path2 = './data/statelysabotage-previous_cake'

  first_move = (total_people == people_left)

  current_winner = first_move ? 0 : File.read(current_winner_path2).to_i
  previous_cake = first_move ? total_degrees : File.read(previous_cake_path2).to_i

  last_slice = previous_cake - degrees_left
  current_winner = [current_winner, last_slice].max

  File.open(previous_cake_path2, 'w') { |f| f.puts(degrees_left)   }
  File.open(previous_cake_path1, 'w') { |f| f.puts(total_degrees) }
  File.open(current_winner_path1, 'w'){ |f| f.puts(current_winner) }
  File.open(current_winner_path2, 'w'){ |f| f.puts(1) }

  if first_move
    (degrees_left / 2) - 1
  else
    average_left = degrees_left.fdiv(people_left).ceil
    bid = [average_left, current_winner+1].max
    [bid, degrees_left].min
  end

end

p stately_sabotage(*ARGV.map(&:to_i))

This means you are allowed to overwrite other files you find that don't appear in this format. You shouldn't do this deliberately, please be sporting.

This bot decided that in order to eliminate competition, it should not be sporting.
This is a clone of Stately Imitator, except that this one messes up Stately Imitator's persistence files (as they aren't prefixed with the bot name) so that it makes the wrong decisions and is chosen last.

'You should not do this deliberately' Doesn't this count?

This is why we can't have nice things.

@muddyfish I took it in the RFC2119 sense. "there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood"

Trader, R
args <- sapply(commandArgs(TRUE),as.integer)
fraction <- args[2]/args[4]
if(args[3]==args[4]){
    cat(fraction, "\n", file="data/trader.txt")
}else{
    cat(fraction, "\n", file="data/trader.txt", append=TRUE)
}
history <- scan(file="data/trader.txt", quiet=TRUE)
if(tail(history,1) != max(history)){
    cat(floor(fraction)-1)
    }else{
        cat(args[2])
        }

Keeps track of the evolution of the degrees left vs people left ratio and when that ratio starts lowering, it asks for a reasonably fair slice, otherwise asks for the whole remaining cake. Invoked using Rscript trader.r total-degrees degrees-left total-people people-left.

guest, Python 2
print ord('d')*4

This isn't code golf you know ;)

bill, Python 2
import sys
t,r,p,s=map(int,sys.argv[1:])
print(t-ord('d')*4)/(ord('\n')+ord('\t'))

A fairish bet.

AlCakeSurfer, Python
import sys, math

total_degrees, degrees_left, total_people, people_left = map(int, sys.argv[1:])

fraction_left = (degrees_left + 0.0)/ total_degrees
fraction_gone = 1.0 - fraction_left
fair_share = fraction_left/people_left
modified_fair_share = fair_share + 0.05

weighting = 0.5 * fraction_gone + 0.5 - modified_fair_share
surfing = (math.cos(fraction_gone * math.pi))**2

print(int(math.floor((weighting * surfing + modified_fair_share)* total_degrees)))

Since AlCakeBot did so badly (and I expect him to do even worse in the contest) here’s my second entry. I called him Surfer, because he has a very nice up-and-down wave function that makes him feel like a surfer.
In principle, he bids according to cos² (x * pi), where x is the fraction of cake that has been taken. This surfing wave is modified with a weighting function that causes him to start at less than a fair share less than half of the cake, reduces his bids to just above a fair share around when half of the cake is gone, and then speeds back up to bidding for the entire cake later. He will never bid less than a fair share of the remaining cake plus 5 % (percent of the entire cake, that is).
Note that while they may be brothers, if he gets a significantly larger slice than AlCakeBot, the latter is not even getting a single crumb of that. They would share chocolate or biscuits, but not cake!

Wow, I got lucky in early rounds and it quickly went South once others optimised their bots =O

Really the cake, Bash
#!/bin/bash
echo "$RANDOM 652 / $2 * 100 / $2 $4 / + p" | dc

And here is a picture of the real cake.

Relinquisher, Java
import static java.lang.Integer.parseInt;
public class Relinquisher {
    public static void main(String... args){
        int cakeLeft = parseInt(args[1]);
        int totalPeople = parseInt(args[2]);
        int peopleLeft = parseInt(args[3]);
        int answer = (int) Math.ceil(((peopleLeft + 10.0) * cakeLeft) / (totalPeople + 10.0));
        System.out.println((int) answer);
    }
}

A basic variant of my other bot, Impatient. This one tries to take the whole thing at first, but as more and more guests get their share, its desire to get the most possible slowly diminishes. I'm not too into this one; just wanna see how well it does.

Needs a ; in the mathsy line

@muddyfish Whoops, thought I put it there before. Thanks for pointing that out!

Also needs to be cast as an int as does the other one

Thought it already is...?

Require int found double?

Should this last edit fix the problem?

Yep, works for this, just change impatient now

Haha, already done again :) Sorry for being such a n00b with Java.

OK, when ran as  sh "./commands/java.sh" "./bots/Relinquisher.java" Relinquisher 3600 3600 23 21 it returns 0 all the time as does the other one

That's really weird. I have no idea what could be causing that.

Does Java do floating division by default?

Not sure, but it may not in this case, since everything is integers. Perhaps changing the 10s to 10.0 would do it.

@muddyfish I've switched around the order of operations so the multiplication is done first, and also changed the 10s. Does it work now?

FairShare, Python 2
import sys

def FairShare(TotalDegrees, DegreesLeft, TotalPeople, PeopleLeft):

    FairShare = TotalDegrees / TotalPeople
    FairShareNow = DegreesLeft / PeopleLeft

    if PeopleLeft == 1:
        return DegreesLeft

    elif FairShare > FairShareNow:
        return FairShare

    elif FairShare == FairShareNow:
        return FairShare

    elif FairShare < FairShareNow:
        return FairShareNow

print FairShare(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]))

Here I come with my tiny Python skills! :D max() and min() are things.
Pretty simple. If my fair share at the beginning is more than my fair share now, return my fair share now. If my fair share at the beginning is equal to to my fair share now, return my fair share at the beginning minus one. If my fair share at the beginning is less than my fair share now, return my fair share now.
Edited so that if FairShare is the last in the round, takes all the cake.

SYS argvs need to be mapped to ints

@muddyfish Fixed. Whoops.

this_bot_wants_it_all_possible, PHP
  echo 359;

This bot wants it all possible.

At the moment, cakes have 3600 degrees

Also, your bot doesn't have a correct header (and I don't have a PHP environment at the moment)

Try to Win, C++
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(int argc, char *argv[])
{
    int td, dl, tp, pl;
    td = atoi(argv[1]);
    dl = atoi(argv[2]);
    tp = atoi(argv[3]);
    pl = atoi(argv[4]);
    if (pl == 1)
    {
        cout << dl;
        return 0;
    }
    else if(pl < 10 )
    {
        int sn = dl / pl;
        int sb = td/ pl;
        int si = td / tp;

        if (sn > si + 1)
        {
            cout << sn;
            return 0;
        }
        if (sn = si + 1)
        {
            cout << sn;
            return 0;
        }
        if (sn == si)
        {
            cout << sn;
            return 0;
        }
        if (sn < si)
        {
            cout << si;
            return 0;
        }

    }
    else
    {
          cout<<td/13;
    }
    return 0;
}

Doesn't return anything, I'm passing args via argv.

@muddyfish i m very sorry. I forgot to take input

ALittleExtra, sh
#!/bin/sh
fair=$(expr $2 / $4)
myextra=$(expr $2 / $3)
want=$(expr $fair + $myextra)
echo $(($want<$2?$want:$2))

I just want a bit more, gets less greedy as cake dwindles

DruuuuuunkBot, Python
import sys,random
tD,dL,pN,pL=map(int,sys.argv[1:])
a=dL/(pL+1)
if a < 0:
 a = dL
print(a)

Tries to be educated in his guesses, but he's a tad drunk, resulting in wide errors. Said bot is now less drunk. He doesn't like people, so he just wants to get out of here pronto! But now he want a little more cake.

Last line should be print(tD/(random.random())

MyFairPlusAThird, sh
#!/bin/sh
fair=$(expr $2 / $4)
myextra=$(expr $2 / 3)
want=$(expr $fair + $myextra)
echo $(($want<$2?$want:$2))

Hungry, Java
public class Hungry {
    public static void main(String[] args) {
        double[] arguments = new double[4];
        for (int i = 0; i < 4; i++) {
            arguments[i] = Double.parseDouble(args[i]);
        }
        int myCake = (int) Math.ceil(arguments[1]/arguments[3]);
        System.out.println(myCake);
    }
}

Always wants its fair share of the remaining cake.

Cake Eater, Java
public class CakeEater{
    public static void main(String[]args){
        int a=Integer.parseInt(args[1]),b=Integer.parseInt(args[2]),c=Integer.parseInt(args[3]);
        System.out.println((int)Math.min(a,((1.2+Math.random()*0.15)*a)/c));
    }
}

It eats cake. That's about it.

A Little Off The Top, Python 2
import math, sys

total_degrees, degrees_left, total_people, people_left = map(int, sys.argv[1:])

def get_equal_share(total_degrees, people):
  return int(math.ceil(total_degrees/float(people)))

def noms(total_degrees, degrees_left, people):
  bid = get_equal_share(total_degrees,people)-1
  return min(degrees_left, bid)

print noms(total_degrees, degrees_left, people_left)

Since the "perfect" algorithm tries to split the cake evenly between the bots, we're going to take just a sliver less than that. Demands its full fair share of the overall cake, even in subsequent rounds, but skews that number upward since it's based on how many people are left.
I haven't programmed in Python in a long while, so let me know if my code is broken...

FloorBot, Python
from sys import argv
from math import floor
degrees_left = int(argv[1])
print(floor(degrees_left*0.65))

Bids 65% of the remaining cake in hopes of beating both the greedy bots and the "Price is Right" bots.

Cue next bot bidding 84%...

@Geobits I have another idea for a bot that scrapes this post and bids 1% less than any other percentage based bot. :P

Again, argv[1] needs to be converted to an int

@muddyfish Oops, duh. Fixed.

@MorganThrapp Hmm. A bot challenge based on reading the source code of the other bots would be fun, not that I would participate.

I've restrained myself from cheating like this, it would be easy for me to write a script that scraped other entries with the data structure (you have it too now.)

Imitator, Ruby
def imitator(total_degrees, degrees_left, total_people, people_left)

  case people_left
  when total_people
    degrees_left - 5
  when 1
    degrees_left
  else
    average_already_won = (total_degrees - degrees_left).fdiv(total_people - people_left)
    average_left = degrees_left.fdiv(people_left)
    guess_for_current_winning_score = average_already_won * (1.25 ** (total_people - people_left - 1))
    bid = [average_left, guess_for_current_winning_score].max.ceil
    [bid, degrees_left].min
  end

end

p imitator(*ARGV.map(&:to_i))

The goal is to get more cake than anyone else, not to maximize your cake. Thus, this bot won't settle for any less than what previous bots have already taken. (This version uses heuristics for that check, I just noticed we're actually allowed to save state so I'll probably post a stateful variant later).

EatTheπ, Node.js
var π = Math.PI, e = Math.E;
var [totalπ, πLeft, totalPeople, peopleLeft] = process.argv.slice(2);
console.log(Math.min(totalπ * Date.now() * π % (πLeft * totalPeople / peopleLeft) % totalπ, πLeft / e * π, πLeft) | 0);

Really likes π, and thinks that cake means is π.

Then why is it eating cake? :P

@TheNumberOne Because it isn't fed anything else  :(

@TheNumberOne Now it thinks that cake is π... Why did you ask that?

I had to remove the escaped quotes from the command script and rewrite the second line of the script like this var totalπ=process.argv[2], πLeft=process.argv[3], totalPeople=process.argv[4], peopleLeft=process.argv[5]; to make this work with the controller. It got 97 out of 3600 in the field of 41 bots.

FairPlusPlus, Java
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Scanner;
import static java.lang.Math.*;

/**
 * Created 10/5/15
 *
 * @author TheNumberOne
 */
public class FairPlusPlus {

    private static int previousCake;
    private static int highestVoteWon;

    static {
        File file = new File("data/FairPlusPlus.txt");
        Scanner in = null;
        try {
            in = new Scanner(file);
            previousCake = in.nextInt();
            highestVoteWon = in.nextInt();
        } catch (Exception ignored) {
        }
    }

    public static void main(String[] arguments) throws FileNotFoundException {
        double[] args = new double[4];
        for (int i = 0; i < 4; i++) {
            args[i] = Double.parseDouble(arguments[i]);
        }
        if (args[2] == args[3]){
            highestVoteWon = -1;
        } else {
            highestVoteWon = (int) max(highestVoteWon, args[1] - previousCake);
        }

        System.out.println((int) min(max(ceil(args[1]/args[3]+(args[3]-1)/2), highestVoteWon + 1), args[1]));

        PrintStream out = new PrintStream("data/FairPlusPlus.txt");
        out.println((int) args[1]);
        out.println(highestVoteWon);

    }

}

He's mostly fair ... unless someone gets the better of him.
Assumes ./data/ directory exists.

Can you rename the not to FairPlusPlus? (The name not the main class)

@muddyfish Done

Also don't assume FairPlusPlus.txt exists :)

Now getting inputmismatch errors

@muddyfish Fixed.

Impatient, Java
import static java.lang.Integer.parseInt;
public class Impatient {
    public static void main(String... args){
        int cakeLeft = parseInt(args[1]);
        int totalPeople = parseInt(args[2]);
        int peopleLeft = parseInt(args[3]);
        int answer = (int) Math.ceil(((totalPeople - peopleLeft + 10.0) * cakeLeft) / (totalPeople + 10.0));
        System.out.println((int) answer);
    }
}

I don't really know Java, so I don't even know if this will compile....
It starts out hungry for 10/(totalPeople+10) of the cake, getting hungrier and hungrier as the round wears on. Not sure how it will do, but it's a fun experiment.

Needs a semicolon also

Already done. :)

Fatbot 5000, Python 2
import random, math, sys

total_degrees, degrees_left, total_people, people_left = map(int, sys.argv[1:])

def get_equal_share(degrees_left, people):
    return int(math.ceil(degrees_left/float(people)))

def get_greedy(degrees_left, people):
    min_bid = get_equal_share(degrees_left,people)+1
    max_bid = min_bid*2
    bid = random.randrange(min_bid, max_bid)
    return min(bid, degrees_left)

print get_greedy(degrees_left, people_left)

My example bot. Will always bid more than it's fair share of the cake but isn't so hungry it wants much more than 2 times it's fair share.

Moses, Java
public class Moses {
    public static void main(String[] args) {
        double[] arguments = new double[4];
        for (int i = 0; i < 4; i++) {
            arguments[i] = Double.parseDouble(args[i]);
        }
        if (arguments[3] == 1) {
            System.out.println((int)arguments[3]);
        } else {
            int myCake = (int) Math.ceil(arguments[1]/2);
            System.out.println(myCake);
        }
    }
}

Wants half of the pie. If it gets its share, the following players can at maximum get the same amount.

Give me the cake, Bash
#!/bin/bash
echo 3594

Pig, Java
public class Pig{
    public static void main(String[] args){
        System.out.println(args[1]);
    }
}

This pig is probably not smart enough to bid low.

Well, at least you're testing my controller.

I know, it was bidding the total amount of cake to start with, now edited

@muddyfish It was meant to bid what was left of the cake :)

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Implement the dog bash utility
dog is a command-line utility that takes in an arbitrary number of arguments,
the first of which is the text to be written and the others are arbitrarily many files.
The dog utility will split the text in equal portions over these files. If there is a remainder n, the first n files get an additional byte
dog is the opposite of cat, as such, forall x, the following should hold.
$> dog x a.txt b.txt ...
$> cat a.txt b.txt ...
x$>

Where ... indicates arbitrarily many files.
An example (12 bytes, 3 files, can be split evenly):
$> ./dog.py "Dogs vs Cats" a.txt b.txt c.txt
$> cat a.txt
Dogs$> cat b.txt
 vs $> cat c.txt
Cats$> cat a.txt b.txt c.txt
Dogs vs Cats$>

An example with remainder (13 bytes, 5 files, remainder 3):
9$>./dog.py "0123456789abc" a.txt b.txt c.txt d.txt e.txt
$> cat a.txt
012$> cat b.txt
345$> cat c.txt
678$> cat d.txt
9a$> cat e.txt
bc$> cat a.txt b.txt c.txt d.txt e.txt
0123456789abc$>

It's implied, but just to double check: 1) Do the arguments have to come in via command line? 2) Do we always have to output to files?

@Sp3000 yes, to 1 and 2

It would be more "unixy" for the input string to come from STDIN.  But that's your call...

@DigitalTrauma there's already an answer, I would feel bad for invalidating it by a rule change

I've been learning about some oddly-named UNIX utilities from this site lately (tac, dog, ...).

@kirbyfan64sos They are non-existent, they are just word-puns over the cat util

Yeah, I know, but they're still weird, and I wouldn't be surprised if someone has actually named tools like that before.

@kirbyfan64sos and Caridorc: tac is real.

@DLosc funny, tac is an x-ray medical exam in Italian. I think it is just a coincidence though

@Caridorc Apparently the 'tac' scan is the language word order for a 'cat' scan in English (which is a special type of X-ray scan).  The Xray (or at least what Americans would consider an X-ray - where you put up a static flat image) is raggi X. Oh, the joys that the 'other languages' sidebar on Wikipedia can bring.

I like the idea of equal portions over these files with at least 1 byte len as maximum difference!

Pyth - 12 bytes
.wMC,cl.zz.z

Uses builtin split function and then uses splat-map on the write function. Doesn't work online.

Python - 181 bytes
import sys
a=sys.argv
l=len
d=a[2:]
s=a[1]
n,r=divmod(l(s),l(d))
p=0
for i in range(l(d)):
    with open(d[i],'w') as f:
        o=n+int(i<=n)
        f.write(s[p:p+o])
        p+=o

PHP, 107 bytes
The golfed code:
for($i=1;++$i<$argc;fputs(fopen($argv[$i],w),substr($s=$argv[1],($i-2)*$l=ceil(strlen($s)/($argc-2)),$l)));

The detailed code:
$len = ceil(strlen($argv[1])/($argc - 2));
for ($i = 2; $i < $argc; $i ++) {
    $fh = fopen($argv[$i], 'w');
    fputs($fh, substr($argv[1], ($i - 2) * $len, $len));
    fclose($fh);          // omitted in the golfed version
}

Pure bash: 97
s=$1;shift;for((l=${#s}/$#,m=${#s}-l*$#,i=1;i<=$#;p+=q,i++)){
printf "${s:p:q=i>m?l:l+1}">${!i};}

As a function: (p= is only required for second run)
dog() { p=
    s=$1;shift;for((l=${#s}/$#,m=${#s}-l*$#,i=1;i<=$#;p+=q,i++)){
    printf "${s:p:q=i>m?l:l+1}">${!i};}
}

Tests
$> rm *
$> dog "Dogs vs Cats" a.txt b.txt c.txt
$> ls -l
total 12
-rw-r--r-- 1 user user 4 May 13 22:09 a.txt
-rw-r--r-- 1 user user 4 May 13 22:09 b.txt
-rw-r--r-- 1 user user 4 May 13 22:09 c.txt
$> cat {a,b,c}.txt;echo
Dogs vs Cats
$>

All files is 4 byte len and concatenated in right order, contain "Dogs vs Cats".
$> rm *
$> dog "$(printf "%s" {0..9} {a..c})" {a..e}.txt
$> ls -l
total 20
-rw-r--r-- 1 user user 3 May 13 22:09 a.txt
-rw-r--r-- 1 user user 3 May 13 22:09 b.txt
-rw-r--r-- 1 user user 3 May 13 22:09 c.txt
-rw-r--r-- 1 user user 2 May 13 22:09 d.txt
-rw-r--r-- 1 user user 2 May 13 22:09 e.txt
$> cat *;echo
0123456789abc
$>

Firsts files is 3 byte len and last only 2, concatenated by alphabetic order, contain "0123456789abc".
Explanation (ungolfing):
If you hit: declare -f dog, bash will answer:
$> declare -f dog
dog ()
{
    p=;
    s=$1;
    shift;
    for ((l=${#s}/$#,m=${#s}-l*$#,i=1; i<=$#; p+=q,i++))
    do
        printf "${s:p:q=i>m?l:l+1}" > ${!i};
    done
}

This could be written:
dog2 ()
{
    position=0;
    string=$1;
    shift;
    partLen=$((${#string}/$#));
    oneMore=$((${#string}-partLen*$#));
    for ((i=1; i<=$#; i++))
    do
        if ((i<=oneMore)); then
            partQuant=$((partLen+1));
        else
            partQuant=$partLen;
        fi;
        printf "${string:position:partQuant}" > ${!i};
        ((position+=partQuant));
    done
}

Ruby, 93 87 bytes
Full program using command line arguments.
If I could use s.slice! to mutate the string, I'd do that instead of needing to use s[c..-1], but Ruby doesn't let you mutate the strings from argv without duplicating them first
s,*t=$*
d,r=s.size.divmod t.size
t.map{|e|open(e,?w)<<s[0,c=(0>r-=1)?d:d+1];s=s[c..-1]}

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Crazy Librarian's Arithmetic Sequence of Primes
Well, the librarian caught you cheating at your job by using your sorting algorithm, so now you're being punished. You've been ordered to create some code so the librarian can impress the object of their unrequited affection, the math teacher. So that's what "Other duties as assigned" means ...
Everyone is familiar with the natural number sequence in base 10, called \$\mathbb N\$:

0, 1, 2, 3, 4, 5, 6, ...

From that, we can generate the prime number sequence, let's call it \$\mathbb P\$, such that every element in \$\mathbb P\$ has exactly two divisors in \$\mathbb N\$, namely 1 and itself. This sequence is:

2, 3, 5, 7, 11, 13, ...

OK, pretty routine so far.
The librarian thought of a nifty function \$F(x, y)\$ that takes a number \$x\$ from \$\mathbb N\$, with the condition \$0 \le x \le 9\$, and a number \$y\$ from \$\mathbb N\$, and inserts \$x\$ into \$y\$'s decimal expansion in every position (i.e., prepending, inserting, or appending \$x\$ into \$y\$), then returns the sorted set of new numbers.
For example, \$F(6, 127)\$ would result in

1267, 1276, 1627, 6127

That's still kinda boring, though. The librarian wants to spice things up a bit more by instead specifying a new function \$z \to \{p : p \in \mathbb P , F(z,p) \subset \mathbb P\}\$, sorted ascending.
For example, \$z(7)\$ would be

3, 19, 97, 433, 487, 541, ...

because \$37\$ and \$73\$ are both prime, \$719\$, \$179\$ and \$197\$ are all prime, etc.
Note that \$z(2)\$ is empty, because no prime that has a \$2\$ appended will ever still be prime. Similarly for \$\{0,4,5,6,8\}\$.
Your task is to write code that will generate and output the first 100 numbers in sequence \$z(x)\$ for a given \$x\$.
Input
A single integer \$x\$ such that \$0 \le x \le 9\$. Input can be via function argument, STDIN, or equivalent.
Output
A sequence of the first 100 numbers, delimited by your choosing, to STDOUT or equivalent, such that the sequence satisfies \$z(x)\$ as described above. If \$z(x)\$ is empty, as is the case for \$\{0,2,4,5,6,8\}\$, the words Empty Set should be output instead.
Restrictions

This is code-golf, since you'll need to transcribe this to an index card so the librarian can show the math teacher, and your hand cramps easily.
Standard loophole restrictions apply. The librarian doesn't tolerate cheaters.

Reference sequences
x=1 : A069246
x=3 : A215419
x=7 : A215420
x=9 : A215421
Related:
Find the largest fragile prime /
Find the smallest prime from a substring / Find largest prime which is still a prime after digit deletion

Pyth, 49 bytes
Like the Python3 and other Pyth answer, the runtime for finding 100 numbers is prohibitive. (test suite gives 10)
?}z"1379".f&!tPZ!|FmtPvjzc`Z]dhl`Z*TT3"Empty Set"

Try it online

The trailing " is unnecessary, very nice work though.

Thanx for the reminder.  Because EOL no longer terminates a string, I've avoided unterminated strings, but of course, EOF still works

Python 3, 188 bytes
x=input()
k=1
i=100
if x in"024568":i=print("Empty Set")
while i:k+=1;s=str(k);i-=all(sum(p%d<1for d in range(2,p))<4for p in[k*int(s[:j]+x+s[j:])for j in range(len(s)+1)])and not print(k)

Badly golfed, but here's something for now. Instead of checking p in P and F(z,p) subset of P, we check that p*f is a semiprime for each f in F(z,p). Combine that with trial division for primality testing, and you get an O(scary) algorithm.

Nice trick in setting i to None.

Perl, 124 bytes
$p=prime_iterator;y/1379//or$i=+~print'Empty Set'}while($i<100){$_=&$p;is_prime"$`@F$'"or redo while//g;$i++

Requires the following command line option: -palMntheory=:all, counted as 16. Input taken from stdin.
Uses @DanaJ's Math::Prime::Util module for perl (loaded with the pragma ntheory). Get it with:
cpan install Math::Prime::Util
cpan install Math::Prime::Util::GMP

is_prime is deterministic for all values less than 264, which is sufficient for our purposes.

Sample Usage
$ echo 2|perl -palMntheory=:all oscary.pl
Empty Set

$ echo 7|perl -palMntheory=:all oscary.pl
3
19
97
433
487
541
691
757
853
1471
.
.
.
718705783
720574573
737773357
745157779
747215167
767717017
768743377
770294977
771778477
774577777

Expected Runtimes
x = 1 : 1m 09.2s
x = 3 : 0m 04.2s
x = 7 : 2m 52.5s
x = 9 : 0m 11.5s

Jelly, 37 bytes
D-ṭJœṖ€$j€Ṗ€ḌẒȦ
1Ẓ×çɗȷ2#µ“¬ḟ¦⁻v»ẇ?⁽¢°

Try it online! (takes the first 10 instead of 100)
How it works
D-ṭJœṖ€$j€Ṗ€ḌẒȦ - Helper link. Takes n on the left and d on the right
D               - Digits of n
 -ṭ             - Append -1; Call this D
       $        - To the digits:
   J            -   Indices; Yield [1, 2, ..., len(D)]
      €         -   Over each index i:
    œṖ          -     Partition D at the index i
        j€      - Join each with d
          Ṗ€    - Remove the -1s
            Ḍ   - Convert back to integers
             Ẓ  - Is prime?
              Ȧ - True for all?

1Ẓ×çɗȷ2#µ“¬ḟ¦⁻v»ẇ?⁽¢° - Main link. Takes a digit d on the left
                 ?    - If statement:
                ẇ ⁽¢° -   Condition: d is one of 1,3,7,9?
        µ             -   Then:
    ɗ                 -     Define a dyad f(n, d):
 Ẓ                    -       n is prime?
  ×                   -       and
   ç                  -       the helper link is true
1    ȷ2#              -     Count up k = 1, 2, ... and return the first 100 k for
                             which f(k, d) is true
         “¬ḟ¦⁻v»      -   Else: Return "Empty Set"

Pyth, 58
L}bPb|*"Empty Set"}Qj204568T.f&yZ.Amyi++<JjZTdQ>JdThl`Z100

This test suite only calculates the first 10 numbers because it takes far too long to generate the rest. Brute forces both primality and the inserting of the digits. Demonstrates such bad performance that I haven't been able to run it up to 100, so please tell me if there are problems.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Find our missing dead
Challenge
Peter has risen again to save us from the duplicate challenges!
Peter Taylor is dead, and there's no doubt about it (well, apart from the huge amount of doubt we have... but just ignore that). In his memory, you must write a program which determines whether a given user is alive or dead.
Further Information
A user is dead if they haven't been seen for more than a day, any less than that then they are alive. Check the last seen section found here:

The input will be a user id (for example, mine is 30525, and Peter Taylor's is 194). Assume that all inputs are valid PPCG IDs.
If the user is alive, you should output:
[User name] is alive!

Where you replace [User name] for their username not their user id.
If the user is dead, you should output:
 Sadly, [User name] is dead.

T-SQL entrants using the SE Data Explorer are disallowed.
Winning
The shortest program in bytes wins.
Leaderboard

var QUESTION_ID=59763;OVERRIDE_USER=30525;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="
"+e.body.replace(OVERRIDE_REG,"")+"
")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
 <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">

Leaderboard

	Author	Language	Size

Winners by Language

Language	User	Score

{{PLACE}}	{{NAME}}	{{LANGUAGE}}	{{SIZE}}	Link

{{LANGUAGE}}	{{NAME}}	{{SIZE}}	Link

Why disallow T-SQL/SEDE?

Needs a description of where to find the number for "last seen".

@feersum It is the title tag of the last seen value.

@feersum Good enough?

I think [tag:parsing] is more relevant to this than [tag:internet].

@minxomat Edited tags

Be forewarned, this challenge has an air of Schrödinger's cat to it. If you find a user to be dead before someone else, you may be responsible/liable for killing them, in a sense.

CJam, 115 bytes
"codegolf.xyz/u/"r+g_N/{"s=\"r"/_0='>&!*1>s_"da"#)\_el=!|}#)"Sadly, %s is dead.""%s is alive!"?\"\"User "/1='"/1<e%

The idea is the same as in my Bash answer, except that this answer doesn't use regular expressions, because CJam doesn't have regular expressions...
The online interpreter doesn't perform web requests, so this will only work from the command line.

Bash, 151 bytes
r="curl -L codegolf.xyz/u/$1";u=`$r|grep -Pom1 '(?<="User )[^"]*'`
$r|grep -Pq '^[^>]*s="r.*(da|[A-Z])'&&echo "Sadly, $u is dead."||echo "$u is alive!"

As usual, output to STDERR is ignored.
Example run
$ ./is-dead 30525 2>&-
Beta Decay is alive!
$ ./is-dead 44935 2>&-
Sadly, Alpha Decay is dead.

Idea
This code greps for lines containing s="r that do not have > before its occurrence. For example:
Last seen just now

If the match is followed by the string da, it contains the word yesterday or days (as in 2 days ago).
If the match is followed by an uppercase letter, it contains the name of a month.
In all other cases, the user is undead alive.

The user's name is extracted from a Twitter meta tag. Example:
<meta name="twitter:title" property="og:title" itemprop="title name" content="User Dennis">

I've updated my profile, and suddenly I'm dead. :(

You are no longer dead to me.

That's a relief!

Who registered that domain?

@jimmy23013 minxomat

PowerShell (v4), 228 217 209, 157 bytes
$u=($x=curl "codegolf.xyz/u/$args").BaseResponse.ResponseURI.Segments[-1]
if($x-match'n <(.*?)((c|n|ur)s* ago|w)<'){"$u is alive!"}else{"Sadly, $u is dead."}

e.g.
PS C:\> test.ps1 30525
beta-decay is alive!

C:\> test.ps1 67
Sadly, keith-randall is dead.

#Previous 209 byte version:
$f={$u=((curl "api.stackexchange.com/2.2/users/$($args)?&site=codegolf"
)|ConvertFrom-Json).Items;$d=$u.display_name;if((get-date -U %s)-
$u.last_access_date-gt86400){"Sadly, $d is dead."}else{"$d is alive!"}}

(Sorry, Keith Randall, you were just the first account I found with >1 day since last seen date).
I was happy with the solid, reliable 209 byte one calling the API, but screen-scraping is the way to go for golf.

This now pulls the username from the redirected URI - but it is a name rather than a numeric ID, as required.

And it matches the line Last seen 2 days ago with n <... [nr]s ago< trying to catch sec(s) ago, min(s) ago, hour(s) ago, and just now, and miss "days weeks, months" ago, or the long term dates+times. And trying to catch 'last seen' and not the other relativetimes. (Thanks Dennis).

NB. curl is a default alias for Invoke-WebRequest, it's not the standard curl program ported to Windows.

There's also secs ago, 1 min ago (no s), and I think I've seen just now.

@Dennis I think that's fixed now, thanks. (at the cost of falling behind your Bash answer; maybe I should try shamelessly using your pattern matches...).

Javascript ES6, 234 bytes

document.write(`<script src="//api.stackexchange.com/users/${prompt(a=d=>{n=(x=d.items[0]).display_name,alert((Date.now()/1e3)-x.last_access_date>86400?`Sadly, ${n} is dead.`:n+' is alive!')})}?site=codegolf&callback=a">\x3C/script>`)

Annotated version

// Inserts a script tag to perform a JSONP callback request on the stackexchange API
document.write(`


text:
Hello human, I want to recover my little cat pics
NB : Everything presented in the situation is totally fake and had just been put here to make the challenge a little more fun ;) ... Or maybe not ;)

=== === BEGINNING TRANSMISSION === ===
Hello,
I recently had a disk failure. I hopefully had backups and I now want my photos back. However, EVERY backup looks corrupted in the parallel universe where I live. But that's not a problem, because we had special tools to help user find their files back. They work a little bit like yours, and looks around a disk for headers that look like images. As they are still in beta, the software recovers any image it finds, gives it a random name and outputs a list containing:

The model of the camera that took the photo, or a single - if not available. Note that the model could contain spaces, but no -.
A tab char (\t, ASCII 9)
The name of the photo file.

The file is a standard text file and looks like that:
[...]
-   uyfeiebsvH.jpg
-   hv754ce758.gif
-   8321214736.jpg
-   FgnvsfHJBs.jpg
-   OMGILOVYOU.jpg
-   HElloDearH.png
-   umanHAYYSG.jpg
COOLCAM S1332   umanIAYYSG.jpg
iCell 7G    1234567890.jpg
[...]

The file is quite big, and I can't rely on my little Ubro to move all the file that have a model in a separate directory.

Dear Human, I need your help. I want you to move all photos that have data about the camera in a separate directory, so I could find my little cute cat pictures out of this mess of icons, screenshots...
However, these backups are taking place on My LiquidStateDrive46X, so I don't have a lot of space left (and I'm actually downloading the Internet, so, you know, it's difficult to download something else while doing that. I just can barely surf the web and you are the only one I've found, human!)
Don't let me live that way ! Please, write my a small program that will do the work for me, and save a little Ubro.

As this is code-golf, the shortest program wins
I need to be able to launch you program, HUMAN ! So make sure your program has an existing interpreter.
You can expect the list file to be in the directory where I launch your script. It will be named ./list.txt
You need to move images to ./withmodel/
Every image recovered is in the same directory from where I launch your program
No image have a - in his name. Same goes for camera models
It need to be a real program, not a simple function.
No internet access, I'm DOWNLOADING! This is really important.
I need my cat images quickly, or I can't survive: This code-golf will end on the 10th of October, if I'm still alive on this day.

=== === END OF TRANSMISSION === ===

You may use any language that have an interpreter by the time the challenge were posted, so it looks like a standard loophole, yes. I don't want to restrict too much on this...

Ok, I've edited that line to be a bit more clear, in my opinion. If you don't like it feel free to revert.

It's puuuurfect ;)! Thanks you!

I've put an answer, but I wonder if I'm missing something. Why might this need internet access? Is it important that the disk doesn't have much space left? Is this significant "I cant rely on my little Ubro to move all the file that have a model in a separate directory."?

This should'nt need internet. I just put the rule in case... The disk has not much space left => write the shortest program possible. And the Ubro is pure storytelling, it's not significant

@DanTheMan this would be a good nickname

what's an Ubro...?

Ubro was from Ufo Brother. If you can come up with a better name, just edit :-). But anyway, it's part of the question storytelling

PowerShell (v4), 58 49 bytes
(gc list.txt)-replace"^[^-]*`t"|mv -des withmodel

# Previous 58 byte version
(gc list.txt)-notmatch'^-'-replace".+`t"|mv -des withmodel

get-content of the list
remove camera models up to the tab by replacing them with nothing. This won't change the lines starting with "-".
pipe into the move command, destination folder 'withmodel'. This will hit a lot of errors for the unchanged lines starting with "-", but since none of the files has a "-" in the name, that won't move any incorrect files, only the right files will be moved.

Holy crap ... I had almost the exact same thing. Finally, a challenge that PowerShell is almost designed for, and I was a slight bit too slow. Have a +1.

@TimmyD Indeed; it's not particularly great for golfing, but with the way "-replace" and "|mv" work on multiple things at once, this has got to be one of its strongest areas.