title: Display an xkcd

text:
# Question
Title: Display an xkcd
xkcd is everyone's favorite webcomic, and you will be writing a program that will bring a little bit more humor to us all.
Your objective in this challenge is to write a program which will take a number as input and display that xkcd and its title-text (mousover text).

## Input

Your program will take a positive integer as input (not necessarily one for which there exists a valid comic) and display that xkcd: for example, an input of 1500 should display the comic "Upside-Down Map" at xkcd.com/1500, and then either print its title-text to the console or display it with the image.

`Due to their proximity across the channel, there's long been tension between North Korea and the United Kingdom of Great Britain and Southern Ireland.`

Test case 2, for n=859:

`Brains aside, I wonder how many poorly-written xkcd.com-parsing scripts will break on this title (or ;;"''{<<[' this mouseover text."`

Your program should also be able to function without any input, and perform the same task for the most recent xkcd found at xkcd.com, and it should always display the most recent one even when a new one goes up.

You do not have to get the image directly from xkcd.com, you can use another database as long as it is up-to-date and already existed before this challenge went up. URL shortners, that is, urls with no purpose other than redirecting to somewhere else, are not allowed.

You may display the image in any way you chose, including in a browser. You may ***not***, however, directly display part of another page in an iframe or similar. CLARIFICATION: **you cannot open a preexisting webpage, if you wish to use the browser you have to create a new page**. You must also actually display an image - outputting an image file is not allowed.

You can handle the case that there isn't an image for a particular comic (e.g. it is interactive or the program was passed a number greater than the amount of comics that have been released) in any reasonable way you wish, including throwing an exception, or printing out an at least single-character string, as long as it somehow signifies to the user that there isn't an image for that input.

You can only display an image and output its title-text, or output an error message for an invalid comic. Other output is not allowed.

This is a challenge, so the fewest bytes wins.

# Answer
# Perl + curl + feh, ~~86~~ ~~84~~ 75 bytes

```
`curl xkcd.com/$_/`=~/<img src="(.*)" title="(.*?)"/;$_=$2;`feh "http:$1"`

```

Requires the `-p` switch. I have accounted for this in the byte count.
> 13 votes

# Answer
## PowerShell v3+ ~~110~~ ~~99~~ ~~107~~ 103 Bytes

```
iwr($x=((iwr "xkcd.com/$args").images|?{$_.title})).src.Trim("/") -outf x.jpg;if($x){ii x.jpg;$x.title}

```

Thanks to Timmy for helping save some bytes by using inline assignments.

If no arguments are passed then `$args` is null and it will just get the current comic. Download the picture, by matching the one with alt text, into a file in the current running directory of the script. Then display it with the default viewer of jpg's. The alt text is then displayed to console. `iwr` is an alias for `Invoke-WebRequest`

If the number passed (or any invalid input for that matter) does not match the process fails with at least a 404 error.

```
iwr(                                  # Request the comic image from XKCD
  $x=((iwr "xkcd.com/$args").images|  # Primary search to locate either the current image
                                      # or one matching an argument passed
     ?{$_.title}))                    # Find the image with alt text
        .src.Trim("/")                # Using the images associated link and strip the leading slashes
  -outf x.jpg                         # Output the image to the directory local to where the script was run
if($x){                               # Test if the image acquisition was successful
    ii x.jpg                          # Open the picture in with the default jpg viewer
    $x.title                          # Display alt text to console
}                                     # I'm a closing bracket.

```
> 9 votes

# Answer
## AutoIt, 440 bytes

Yes, it's long, but it's stable.

```
#include<IE.au3>
#include<GDIPlus.au3>
Func _($0='')
_GDIPlus_Startup()
$1=_IECreate('xkcd.com/'&$0)
For $3 In $1.document.images
ExitLoop $3.title<>''
Next
$4=_GDIPlus_BitmapCreateFromMemory(InetRead($3.src),1)
$6=_GDIPlus_ImageGetDimension(_GDIPlus_BitmapCreateFromHBITMAP($4))
GUICreate(ToolTip($3.title),$6[0],$6[1])
GUICtrlSendMsg(GUICtrlCreatePic('',0,0,$6[0],$6[1]),370,0,$4)
_IEQuit($1)
GUISetState()
Do
Until GUIGetMsg()=-3
EndFunc

```

First of all, this doesn't use RegEx to scrape the site (because I have no time to test this on all comics), but rather uses the Internet Explorer API to iterate through the DOM's `img` tags until it finds one with a title text.

The binary stream is read from the image URL and rendered into a bitmap using GDIPlus. This is then displayed in a nice, auto-sized GUI with an actual tooltip to make it behave almost exactly like the website.

Here's a test case (`_(859)`):

)
> 8 votes

# Answer
## Powershell, 93 Bytes

93 Byte version to use local image viewer.

```
$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;iwr ("http:"+$n.src) -OutF x.jpg;ii x.*

```

Saved 2 bytes by removing needless doublequotes, then another lot by using `("http:"+$n.src)` instead of `"https://"+$n.src.trim("/")` \- since the `img` src comes with `//` already on it, and xkcd doesn't require https.

```
$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;saps ("http:"+$n.src)

```

`$n=(iwr "xkcd.com/$args").images|?{$_.title};$n.title;saps ("https://"+$n.src.trim("/"))`

extremely similar to Matts powershell answer, (should probably be a comment but low reputation)

Instead this opens a new tab/window in the default browser, and other things, saving some bytes.

`iwr` is an alias for `Invoke-WebRequest`

`saps` is an alias for `Start-Process` which opens 'it' in the default context.
> 7 votes

# Answer
# R, ~~358~~ ~~328~~ ~~310~~ 298 bytes

```
f=function(x){H="http:";p=paste0;library(XML);a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]];download.file(p(H,a[1]),'a');I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a');d=dim(I)/100;quartz(,d[2],d[1]);par(mar=rep(0,4));frame();rasterImage(I,0,0,1,1);cat(a[2])}

```

With new lines and comments:

```
f=function(x){
H="http:"
p=paste0
library(XML) #Needed for xpathSApply, htmlParse and xmlAttrs
# The following line find the first img element and extract its attributes
a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]]
download.file(p(H,a[1]),'a') #Download to a file called 'a'
I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a') #Check if png or jpeg and load the file accordingly
d=dim(I)/100 #convert dimension from pixel to inches (100 ppi).
quartz(,d[2],d[1]) #open a window of the correct dimension
par(mar=rep(0,4)) #Get rid of margins
frame() #Create empty plot
rasterImage(I,0,0,1,1) #Add png/jpeg to the plot
cat(a[2]) #Print title text to stdout
}

```

Screenshots of test cases:

for x=1500:

for x empty:

case when picture is a jpeg:

x=859:
> 4 votes

# Answer
## PHP, 95 bytes

```
<?php echo str_replace("title=\"","/>",file_get_contents("https://xkcd.com/".$_GET["id"])); ?>

```

Save as main.php, run server

```
php -S localhost:8123

```

Open http://localhost:8123/main.php?id=1500
> 3 votes

# Answer
## Python 2.7, ~~309~~ ~~299~~ ~~295~~ 274 bytes

Full program. Definitely more golfable, but having read xkcd comics for so long I couldn't let this pass (who knows if this will be helpful in a future for easily browsing xkcd).

If no input is passed, gets current comic. If a valid comic number is passed as input then gets that comic. If an invalid input (not a number comic in the valid range) is passed, throws an error.

Any suggestions on how to reduce byte count are welcome! Will revisit (and add explanation) when I have more time.

-10 bytes thanks to @Dopapp

-21 bytes thanks to @Shebang

```
import urllib as u,re
from PIL import Image
h='http://';x='xkcd.com/'
o=u.URLopener()
t=u.urlopen(h+x+raw_input()).read()
c=sum([re.findall(r,t)for r in[h+'imgs.'+x+'c.*s/.*\.\w{1,3}','\.\w{1,3}" t.*e="(.*)" a']],[])
Image.open(o.retrieve(c[0],'1.png')[0]).show();print c[1]

```
> 2 votes

# Answer
# PHP, 42 bytes

```
<?=@file('http://xkcd.com/'.$_GET[i])[59];

```

Save to a file and fire it up in your web server of choice
> 2 votes

# Answer
# Wolfram Language 45 bytes ( Mathematica )

```
Import["https://xkcd.com/"<>#,"Images"][[2]]&

```

Usage with number:

```
%@"1500"

```

Usage without number:

```
%@""

```
> 2 votes

# Answer
# Python 3 + Requests + PIL, ~~192~~ 186 bytes

```
from requests import*
import PIL.Image as f
from io import*
r=get("https://xkcd.com/%s/info.0.json"%input()).json()
f.open(BytesIO(get(r["img"],stream=1).content)).show()
print(r["alt"])

```

Opens up an image viewer (whichever is default on the system it's being run on) containing the comic, and posts the title text to the console.
> 1 votes

# Answer
# JavaScript + HTML, 124 + 18 = 142 bytes

```
i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))

```

```
<img id=B><p id=A>

```

Cross-origin solution thanks to Kaiido's answer here.

17 bytes (`//crossorigin.me/`) can be saved if the proxy required to connect to xkcd.com can be subtracted (meta post about this).

## Test Snippet

```
f=
i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))
```

```
<style>img{width:50%}</style><input id=I> <button onclick="f(I.value)">Run</button><br>
<img id=B><p id=A>
```
> 1 votes

---
Tags: code-golf, internet
---


title: Creepy Corridors

text:
# Question
Title: Creepy Corridors
This challenge is inspired by a board game I played some time ago.
The story of this challenge doesn't necessarily have to be read, the **goal of the challenge**-section should explain everything necessary.

## The Story

*People are locked inside a large room with a human-devouring monster. The walls of the room are enchanted, teleporting objects across the room when touched. Said monster marches across the room, hunting for flesh. The first human in its sight will be consumed by its sharp teeth.*

## The Goal of the Challenge

You are given the map of the room, including the people's and the monster's location.

```
%%%KLMNOPQRSTA%
%%J           B
%I       %    C
H             D
G   %%        E
F             F
E      %      G
D             H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

```

Let's break down the components of the map.

* **Letters from `A` to `T`:** If the monster steps onto one of these, it will be teleported to this letter's second appearance and not change its direction. There will only ever be zero or two of any letter on the board.
* **`%`:** Wall tiles. Just for formatting & nice looks.
* **`#`:** The monster's starting location.
* **`*`:** The people's locations.
* **:** Empty tiles, the monster can move freely on them.

Some additional things to note about the map:

* The map dimensions and object location will not be constant, so your code will have to dynamically adapt to that.

---

The monster will **always** go in the direction that it currently facing (facing west at the start) **unless** it spots a human, in which case it will turn towards the **closest** human.
The monster spots a human if there are no wall or teleporter tiles in a straight horizontal or vertical line between it and the human.

Another thing to note is that if the monster is in front of a solid wall (`%`) or has to decide between two humans, it will always prioritize **right** over left.

If the monster is **not** able to *turn right and make a step forwards* for some reason, it will turn **left** instead.

So, in the end, the order that the monster prioritizes directions would we forward, right, left, backwards.

## Input

* The map, including the monster's starting location and the people's positions as their respective characters. There should not be any other input than the map string, or the array of strings, or characters.

The input may be received in any reasonable format; a single string or an array of strings for the map.

## Output

The coordinate of the person that first gets eaten by the monster.

The coordinates start from the top-left corner and are 0-indexed, so the first tile will have the coordinates (0|0). If you are using 1-indexing, please specify it in your answer.

## Rules

* This is , the shortest code in bytes in any language wins.
* Standard loopholes are forbidden.
* You may assume that the monster will always be able to reach a human.

---

## Test Cases

Input:

```
%%%KLMNOPQRSTA%
%%J           B
%I       %*   C
H   *         D
G   %%        E
F       #     F
E      %      G
D      *      H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

```

Output: `(10,2)`, since the monster cannot see the two other people when it runs past them, it gets teleported to the other `F` wall, where it will then see the last person.

Input:

```
%%%KLMNOPQRSTA%
%%J           B
%I      *     C
H     %%%   * D
G      #%     E
F     %%%   % F
E             G
D       %     H
C       *    I%
B       *   J%%
%ATSRQPONMLK%%%

```

Output: `(12,3)`

Input:

```
%%%KLMNOPQRSTA%
%%J           B
%I     %%%    C
H     *%#%    D
G             E
F             F
E       %     G
D             H
C            I%
B           J%%
%ATSRQPONMLK%%%

```

Output: `(6, 3)`

Input:

```
%%%%%%%%%%%%%%%
%#%       %%% %
%A%ABCD   %*% %
%*F     G %%% %
% %BC% FD     %
% %   %    %%%%
% %  %       %%
%   % %%   G  %
%             %
%*%    %    % %
%%%%%%%%%%%%%%%

```

Output: `(1,9)`

---

Good luck!

# Answer
# Python 2, ~~565 .. 422 4451 .. 444 4632 .. 468~~ ~~467~~ 463 bytes

```
u,U='*%'
G=lambda s:u==s.strip('# ')[0]and len(N)-s.find(u)
b=input()
D=3;j=''.join;N,w,P,t,B=j(b),len(b[0]),[0,1,0,-1],{},map(j,zip(*b))
for c in N:
 l,r=N.find(c),N.rfind(c)
 if u<c:t[l]=r;t[r]=l
 if'#'==c:x,y=l%w,l/w
while u!=b[y][x]:
 O=[B[x][y-1::-1],b[y][x+1:],B[x][y+1:],b[y][x-1::-1]];L,R=O[D-1],O[~D]
 if u<b[y][x]:X=t[x+w*y];x,y=X%w,X/w
 elif(G(O[D])<1)*(G(R)+G(L)+(U==O[D][0])):D-=0<G(L)>G(R)or(U==R[0])*-~(U==L[0])or-1;D%=4
 x+=P[D];y+=P[~D]
print x,y

```

Try it online!

Saved a lot of bytes thanks to Halvard, Ian and Jonathan

1: Got longer, in order to fix the case of turning twice, and to find the location of the monster.
2: Got even longer.. Monster shouldn't change direction on when teleporting.
> 7 votes

# Answer
# Perl 6, ~~343~~ ~~334~~ ~~333~~ ~~328~~ ~~322~~ 308 bytes

```
{my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});my \a=m<>:k.classify
({m{$_}});my$m=a<#>[0];my$d=-1;{$d=($d,i*$d,-i*$d,-$d).min({$^q;first ?*,map
{(((my \u=m{$m+$_*$q})~~"%")*(1+!($_-1))+(u~~"A".."Z"))*m+(u~~"*")*$_},^m});
$m+=$d;$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"}...{m{$m}~~"*"};$m}

```

Try it online!

*(There are no newlines in the actual code. I inserted them just to wrap the lines for easier reading.)*

**This is unable to deal with maps where it is possible to see outside of the map bounds. (I. e. maps with empty spaces at the border.) If this matters, +5 bytes.** But, since the teleporters block LoS now, it shouldn't.

**Explanation**: It's a function which takes the map as a list of lists of characters. Let's break it down into statements:

`my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});`: Let's make a hash ("dictionary" for Pythonists) called `m` (it's a sigilless variable, so we need to be explicit about assigning a hash into it with `%(...)`) which associates complex keys of form `x+iy` with characters which are in the `y`th rown and `x`th column of the map.

`my \a=m<>:k.classify({m{$_}});`: This makes an "inverse dictionary" of `m`, called `a`: there is one key corresponding to each value in `m`, and the value is a list of complex coordinates (keys in `m`) that contain that character. So, for instance `a{"#"}` will give a list of all coordinates where there is a `#` on the map. (This is also a sigilless variable, but we're in luck since `classify` returns a hash.)

`my$m=a<#>[0];my$d=-1`: Set the initial monster position. We look up the `#` in the inverse hash `a`. We must use `[0]` since `a<#>` is still a list, even when it contains only 1 element. The `$d` contains the direction of monster; we set it to the West. (The direction is a complex number as well, so `-1` is west.)

OK, the next statement is quite nasty. First, let's have a look at this: `{$^q;first ?*,map {(((my$u=m{my$t=$m+$_*$q})~~"%")*(1+!($_-1))+($u~~"A".."Z"))*m+($u~~"*")*abs($t-$m)},^m}` This is a routine that evaluates LoS in the given direction. If there is a human in this direction, it returns the distance to the human. If there is a wall or a teleport in this direction, it returns the total number of squares of the map. (The point is to give such a high number that it is greater than any legitimate distance to a human.) Finally, if the wall is in this direction *and* in distance 1, we return 2 × total number of squares of the map. (We want never ever be running through walls, so these need even a bigger score. We will be choosing the minimum shortly.)

We use this in the construct `$d=($d,i*$d,-i*$d,-$d).min( LoS deciding block );`. Since we use complex numbers for everything, we can easily get directions which are relative forward, right, left and backwards from the original direction just by multiplying it by 1, i, -i (remember that the `y` axis goes the other way that you may be used to from math) and -1, respectively. So we form the list of directions in this order, and find the direction which has the minimal "distance to a human" (according to the block above), which makes sure that any human beats any wall and anything beats a wall which is right under the monster's nose. We use the fact that the `min` function gives the *first* minimal value. If there is a tie in distance between several directions, the monster will prefer forward to right to left to backwards, which is exactly what we want. So we get a new direction which is then assigned to `$d`.

`$m+=$d;` just makes the monster step in the new direction.

`$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"` takes care of the teleports. Let's say the monster is at a teleport `A`. First we search for `A` in the inverse hash `%a` and that turns up the two positions of the teleport `A`, then we discard the current position using the set difference operator (which looks like a backslash). Since there are exactly 2 occurences of each teleport on the map and the monster is surely standing on one, the difference will be a set with 1 element. We then use `.pick` to pick a random element (believe or not, but this is the shortest way to get the element of 1-element set :—)). This kind of thing happens until the monster ends up somewhere not in a portal.

Everything in the last 4 paragraphs describes one massive construction of form `{change direction; step; handle teleports}...{m{$m}~~"*"}`. This is a sequence that calls the block on the left of `...` until the condition on the right of the `...` is true. And that one is true when the monster is on a square with a human. The list itself contains return values of the huge block on the left, which is garbage (most likely `(Any)`) because it returns the value of the while loop at the end. Essentially, we use it as a cheaper while loop. The value of the list is discarded (and the compiler moans about a "useless use of `...` in a sink contest", but who cares). When this all is done, we return `$m` — the monster's position after it found a human, still as a complex number (so, for the first test, we give `10+2i` and so on).
> 6 votes

# Answer
# JavaScript (ES6), ~~258~~ 245

```
g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

```

*Less golfed*

```
g=>{
    var u, // temp current position
        q, // distance so far scanning for a human
        o, // value of grid at current position
        d, // offset to move given current direction
        n = 1/0 // current distance from human
        m = g.indexOf(`#`), // monster position
        w = g.indexOf(`\n`)+1, // grid width + 1 (offset to next row)
        D = [w,-1,-w,1], // offset for moves, clockwise
        k = 1, // current direction, start going west
        t = 1; // displacement for turn
    g=[...g]; // string to array
    while (n) // repeat while not found (distance > 0)
    {
      // look around to find humans
      D.forEach( (d,j) => { // for each direction
        // scan grid to find a human
        for(q=0, u=m; g[u+=d]<'$'; ++q); // loop while blank space
        if ( g[u] == '*' // human found at position u
             & n>q ) // and at a shorter distance than current
        {
           n = q; // remember min distance
           k = j; // set current direction
        }
      })
      // if human found, the current direction is changed accordingly
      d = D[k] // get delta
      m += d // move
      o = g[m] // current cell in o
      if (o > '@') // check if letter (teleporter)
      {
        t = 1 // keep current direction, next turn will be right
        u = m // save current position in u
        g[u] = 1 // clear current cell, so I can find only the other teleporter
        m = g.indexOf(o) // set current position to other teleporter
        g[u] = o // reset previous cell content
      }
      else if (o > '%') // check if '*'
      {
        // set result, so we can exit the loop
        r = [ m%w, m/w|0 ] // x and y position
      }
      else if (o == '%') // check if wall
      {
        // turn
        m -= d // current position invalid, go back
        k = (k+t) % 4 // turn right 90° * t
        t = t+1 // next turn will be wider
      }
      else
      {
        t = 1 // keep current direction, next turn will be right
      }
    }
    return r
}

```

**Test**

```
var F=
g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

var grid=[`%%%KLMNOPQRSTA%\n%%J           B\n%I       %*   C\nH   *         D\nG   %%        E\nF       #     F\nE      %      G\nD      *      H\nC   %        I%\nB           J%%\n%ATSRQPONMLK%%%`
,'%%%KLMNOPQRSTA%\n%%J           B\n%I      *     C\nH     %%%   * D\nG      #%     E\nF     %%%   % F\nE             G\nD       %     H\nC       *    I%\nB       *   J%%\n%ATSRQPONMLK%%%'
,'%%%KLMNOPQRSTA%\n%%J           B\n%I     %%%    C\nH     *%#%    D\nG             E\nF             F\nE       %     G\nD             H\nC            I%\nB           J%%\n%ATSRQPONMLK%%%'
,'%%%%%%%%%%%%%%%\n%#%       %%% %\n%A%ABCD   %*% %\n%*F     G %%% %\n% %BC% FD     %\n% %   %    %%%%\n% %  %       %%\n%   % %%   G  %\n%             %\n%*%    %    % %\n%%%%%%%%%%%%%%%'
]
$(function(){
  var $tr = $('tr')
  grid.forEach(x=>{
    $tr.eq(0).append("<td>"+x+"</td>")
    $tr.eq(1).append("<td>"+F(x)+"</td>")
  })
})
```

```
td {padding: 4px; border: 1px solid #000; white-space:pre; font-family:monospace }
```

```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table ><tr/><tr/></table>
```
> 3 votes

---
Tags: code-golf
---


title: Minimal NetHack

text:
# Question
Title: Minimal NetHack
NetHack is a roguelike game where a player must retrieve the Amulet of Yendor from the lowest level of the dungeon. Commonly played via telnet, the entire game is represented with ASCII graphics. The game is extremely challenging and requires knowledge of many game mechanics in order to succeed.

For the purposes of this challenge, assume that the entire dungeon is a single level and only 5×16 characters. Furthermore, assume that this is a "safe" dungeon or that you are only implementing a prototype—there will be no monsters, concerns about hunger, etc. In fact, you must only track the location of the character and the amulet and the game will effectively end when the player arrives at the same location as the amulet.

# Challenge requirements

* There will be a 5×16 dungeon (single level).
* Give the player a starting location (optionally random) and the amulet a separate random (different each time the program is run) starting square inside the dungeon. That is, the amulet is not allowed to start on the same square as the player.
* Accept four input keys which move the player one square at a time (four cardinal directions). Reading/processing other input is allowed (a readline() function that requires pressing 'enter', etc).
* Travelling outside the bounds of the dungeon is not allowed. E.g., if the player is on the right edge of the dungeon pressing right should do nothing.
* After initial generation and after each movement, print the state of the game. As this is code golf and printing is rather uninteresting, ignore the character count for the print function and function call *assuming no state changes*. Empty cells should be shown as period (`.`), amulet as double quote (`"`) and character as at symbol (`@`).
* The game is over when the player "discovers" the amulet (arrives at the same square)

# Winning

This is a code golf challenege, the shortest code to meet the requirements one week from today will be declared winner.

# Example

Here is an example solution in C# (ungolfed) to show basic requirements and sample output.

```
using System;

namespace nh
{
    class Program
    {
        static Random random = new Random();

        // player x/y, amulet x/y
        static int px, py, ax, ay;

        static void Main(string[] args)
        {
            px = random.Next(0, 16);
            py = random.Next(0, 5);

            // amulet starts on a position different from the player
            do { ax = random.Next(0, 16); } while (px == ax);
            do { ay = random.Next(0, 5); } while (py == ay);

            print();

            do
            {
                // reads a single keypress (no need to press enter)
                // result is cast to int to compare with character literals
                var m = (int)Console.ReadKey(true).Key;

                // Move the player. Here standard WASD keys are used.
                // Boundary checks for edge of dungeon as well.
                if (m == 'W')
                    py = (py > 0) ? py - 1 : py;
                if (m == 'S')
                    py = (py < 5) ? py + 1 : py;
                if (m == 'A')
                    px = (px > 0) ? px - 1 : px;
                if (m == 'D')
                    px = (px < 16) ? px + 1 : px;

                // print state after each keypress. If the player doesn't
                // move this is redundant but oh well.
                print();

            // game ends when player is on same square as amulet
            } while (px != ax || py != ay);
        }

        static void print()
        {
            Console.Write('\n');
            for (int y=0; y<5; y++)
            {
                for (int x = 0; x < 16; x++)
                {
                    if (x == px && y == py)
                        Console.Write('@');
                    else if (x == ax && y == ay)
                        Console.Write('"');
                    else
                        Console.Write('.');
                }
                Console.Write('\n');
            }
        }
    }
}

```

Total character count is 1474, but ignoring calls to the print function and its definition the final character count is `896`.

Output when the program is run:

```
................
...."...........
..........@.....
................
................

```

Output (including above) after the 'a' key is pressed twice:

```
................
...."...........
..........@.....
................
................

................
...."...........
.........@......
................
................

................
...."...........
........@.......
................
................

```

# Answer
> 38 votes
# TI-BASIC, ~~42~~ ~~41~~ ~~38~~ ~~36~~ 35 bytes

For your TI-83 or 84+ series graphing calculator.

```
int(5irand→A                          //Randomize amulet position
6log(ie^(6→C                          //15.635 + 4.093i
Repeat Ans=A                          //Ans holds the player pos. (starts bottom right)
iPart(C-iPart(C-Ans-e^(igetKey-i      //Boundary check, after adjusting player position
prgmDISPLAY
End

----------
PROGRAM:DISPLAY
For(X,0,15
For(Y,0,4
Output(Y+1,X+1,".
If A=X+Yi
Output(Y+1,X+1,"¨
If Ans=X+Yi
Output(Y+1,X+1,"@
End
End

```

Which direction the player will go is a function of the key code of the key pressed, but four keys that definitely work are these on the top row:

```
Key        [Y=]  [WINDOW]  [ZOOM]  [TRACE]  [GRAPH]
           -------------------------------------------
Key code    11      12       13               15
Direction  Left     Up     Right             Down

```

The amulet starts on one of the five squares in the first column, and the player starts at the bottom right square. For example, a possible arrangement is:

```
................
¨...............
................
................
...............@

```

## Explanation

The player's position is stored as a complex number from `0+0i` to `15+4i`, where the real part goes to the right and the imaginary part goes down. This facilitates easy boundary checking on the top and left: we simply offset the number slightly and round towards zero. For example, if the offset is `0.5` and our position is `-1+3i` (off the screen to the left), then the position will be corrected to `iPart(-0.5+3.5i)=0+3i`, where it should be. Checking for the bottom and right boundaries is slightly more complicated; we need to subtract the number from a constant `C`, which is about `15.635 + 4.093i` (it's the shortest one I could find between `15+4i` and `16+5i`), round, subtract from `C` again to flip the number back, and round again.

When a key is pressed, the unadjusted player position will move by 1 unit in some direction, but the integer part only changes when certain keys are pressed. Luckily, the keys that work are all on the top row. Below is a graph of the offsets in cases where keys 11, 12, 13, and 15 are pressed, and when no key is pressed (No press is the point inside the center square, causing the integer parts to be unchanged; the four keypresses' offsets have different integer parts). `C` is the red cross at the center of the circle.

## Old code (42 bytes):

```
int(9irand→A                     // 0≤rand≤1, so int(9irand) = i*x where 0≤x≤8
1                                //set "Ans"wer variable to 1+0i
Repeat Ans=A
Ans-iPart(i^int(48ln(getKey-1    //add -i,-1,i,1 for WASD respectively (see rev. history)
Ans-int(Ans/16+real(Ans/7        //ensure player is inside dungeon
prgmDISPLAY                      //display on top 5 rows of the homescreen
                                 //(for this version switch X+Yi with Y=Xi in prgmDISPLAY)
End

```

### Limitations

There is no way to escape a `"` character, so strings with a `"` cannot be generated inside a program. Therefore, this uses the umlaut mark `¨` instead of a quote (if there were an already-existing string with a quote mark, I could display that). To get `¨` and `@` in a program, an outside tool is required; however, it is valid TI-BASIC.

# Answer
> 44 votes
# CHIP-8, 48 bytes

This may not be considered legal, but why the hell not. I wrote my program in CHIP-8, a bytecode-based programming language for a virtual game console. You can try the complete program (99 bytes) in your browser using an emulator/debugger I wrote called Octo:

http://johnearnest.github.io/Octo/index.html?gist=1318903acdc1dd266469

A hex dump of that complete program is as follows:

```
0x60 0x14 0x61 0x04 0xC4 0x3C 0xC5 0x08
0x22 0x36 0xF6 0x0A 0x22 0x52 0x40 0x00
0x12 0x16 0x46 0x07 0x70 0xFC 0x40 0x3C
0x12 0x1E 0x46 0x09 0x70 0x04 0x41 0x00
0x12 0x26 0x46 0x05 0x71 0xFC 0x41 0x10
0x12 0x2E 0x46 0x08 0x71 0x04 0x22 0x52
0x3F 0x01 0x12 0x0A 0x00 0xFD 0xA2 0x58
0xD4 0x54 0x22 0x52 0x62 0xFF 0xA2 0x5B
0xD2 0x34 0x72 0x04 0x32 0x3F 0x12 0x40
0x62 0xFF 0x73 0x04 0x33 0x14 0x12 0x40
0x00 0xEE 0xA2 0x5F 0xD0 0x14 0x00 0xEE
0xA0 0xA0 0x40 0x00 0x00 0x20 0x00 0xF0
0x90 0x90 0xD0

```

You can move the player with the ASWD keys, or the 7589 keys on the original CHIP-8 keypad. If I remove all the code and data for drawing the background and the player, I instead get this 48 byte dump:

```
0x60 0x14 0x61 0x04 0xC4 0x3C 0xC5 0x08
0xF6 0x0A 0x40 0x00 0x12 0x12 0x46 0x07
0x70 0xFC 0x40 0x3C 0x12 0x1A 0x46 0x09
0x70 0x04 0x41 0x00 0x12 0x22 0x46 0x05
0x71 0xFC 0x41 0x10 0x12 0x2A 0x46 0x08
0x71 0x04 0x3F 0x01 0x12 0x08 0x00 0xFD

```

The ungolfed, complete form of the program was written in a high level assembly language as follows:

```
:alias px v0
:alias py v1
:alias tx v2
:alias ty v3
:alias ax v4
:alias ay v5
:alias in v6

: main
    px := 20
    py := 4
    ax := random 0b111100
    ay := random 0b001000
    draw-board
    loop
        in := key
        draw-player
        if px != 0 begin
            if in == 7 then px += -4
        end
        if px != 0x3C begin
            if in == 9 then px +=  4
        end
        if py != 0 begin
            if in == 5 then py += -4
        end
        if py != 16 begin
            if in == 8 then py +=  4
        end
        draw-player
        if vf != 1 then
    again
    exit

: draw-board
    i := amulet
    sprite ax ay 4
    draw-player
    tx := -1
    i := ground
    : draw
    loop
        sprite tx ty 4
        tx += 4
        if tx != 63 then jump draw
        tx := -1
        ty += 4
        if ty != 20 then
    again
;

: draw-player
    i := player
    sprite px py 4
;

: amulet  0xA0 0xA0 0x40
: ground  0x00 0x00 0x20 0x00
: player  0xF0 0x90 0x90 0xD0

```

Note that the compiled bytes *themselves* are the CHIP-8 programming language; the assembler is simply a more convenient means of composing such programs.

# Answer
> 10 votes
# Python 3, 86 bytes

```
def d():
    import sys
    for y in range(5):
        line = []
        for x in range(16):
            line.append('@' if y*16+x == p else \
                        '"' if y*16+x == a else \
                        '.')
        print(''.join(line))
    print()
    sys.stdout.flush()

p=79;a=id(9)%p
while p-a:d();p+=[p%16<15,16*(p<64),-(p%16>0),-16*(p>15)][ord(input())%7%5]

```

Only counting the bottom two lines, and dropping `d();`.

# Answer
> 10 votes
# C, ~~122~~ ~~121~~ ~~115~~ ~~104~~ ~~102~~ 101 bytes

```
#define o ({for(int t=0;t<80;++t)t%16||putchar(10),putchar(t^p?t^a?46:34:64);})
p;main(a){for(a=1+time(0)%79;p^a;o,p+=(int[]){-16*(p>15),16*(p<64),-!!(p%16),p%16<15}[3&getchar()/2]);}

```

First time posting here ! I hope you like it :)

`o` is the printing, erm, function. Our brave hero can be moved around with 2, 4, 6 and 8, but beware of not sending any other input (no newlines !).

**Update 1 :** brought `a` and `i` into `main`'s parameters.

**Update 2 :** OP having confirmed that a single string of input is OK, I got rid of `scanf` (which I used to skip the newline).

**Update 3 :** Used a compound array literal and modified the input layout. Program now goes haywire if you enter an invalid direction ;)

**Update 4 :** Noticed that the call to the printing function does not count. Took note to read rules more carefully.

**Update 5 :** one byte saved, thanks to Mikkel Alan Stokkebye Christia.

# Answer
> 9 votes
# CJam, ~~46~~ ~~45~~ ~~44~~ ~~40~~ ~~39~~ 37 bytes

```
{'.80*W$Gb'"t1$Gb'@tG/W%N*oNo}:P;
5,G,m*:Dmr~{P_l~4b2fm.+_aD&!$_W$=!}gP];

```

The first line (defines a function that prints the current game state) and the **P**'s on the second line (call that function) do not contribute to the byte count.

Both the starting position and the amulet's position are selected pseudo-randomly. The distribution is as uniform and the underlying PRNG allows.

Input is `E`, `6`, `9` and `B` for **Up**, **Down**, **Left** and **Right**, with `Caps Lock` activated, followed by `Enter`.

### Alternate version

```
{'.80*W$Gb'"t1$Gb'@tG/W%N*oNo}:P;
5,G,m*:Dmr~{P_ZYm*l~(=:(.+_aD&!$_W$=!}gP];

```

At the cost of four more bytes, the input format is improved significantly:

* This version accepts `8`, `2`, `4` and `6` for **Up**, **Down**, **Left** and **Right**, which matches the corresponding arrow keys on the numpad.
* It also accepts `7`, `9`, `1` and `3` for the corresponding diagonal moves.

### Testing

Since the I/O is interactive, you should try this code with the Java interpreter.

Download the latest version and run the program like this:

```
java -jar cjam-0.6.5.jar nethack.cjam

```

To avoid pressing `Enter` after each key, and for in-place updates of the output, you can use this wrapper:

```
#!/bin/bash

lines=5
wait=0.05

coproc "$@"
pid=$!

head -$lines <&${COPROC[0]}

while true; do
    kill -0 $pid 2>&- || break
    read -n 1 -s
    echo $REPLY >&${COPROC[1]}
    printf "\e[${lines}A"
    head -$lines <&${COPROC[0]}
    sleep $wait
done

printf "\e[${lines}B"

```

Invoke like this:

```
./wrapper java -jar cjam-0.6.5.jar nethack.cjam

```

### Main version

```
5,G,   e# Push [0 1 2 3 4] and [0 ... 15].
m*:D   e# Take the Cartesian product and save in D.
mr~    e# Shuffle and dump the array on the stack.
       e# This pushes 80 elements. We'll consider the bottommost the amulet's
       e# position and the topmost the player's.
{      e# Do:
  P    e#   Call P.
  _    e#   Copy the player's position.
  l~   e#   Read and evaluate one line of input.
       e#      "6" -> 6, "9" -> 9, "B" -> 11, "E" -> 14
  4b   e#   Convert to base 4.
       e#     6 -> [1 2], 9 -> [2 1], 11 -> [2 3], 14 -> [3 2]
  2f-  e#   Subtract 2 from each coordinate.
       e#     [1 2] -> [-1 0], [2 1] -> [0 -1], [2 3] -> [0 1], [3 2] -> [1 0]
  .+   e#   Add the result to the copy of player's position.
  _aD& e#   Push a copy, wrap it in an array and intersect with D.
  !    e#   Logical NOT. This pushes 1 iff the intersection was empty.
  $    e#   Copy the corresponding item from the stack.
       e#     If the intersection was empty, the new position is invalid
       e#     and 1$ copies the old position.
       e#     If the intersection was non-empty, the new position is valid
       e#     and 0$ copies the new position.
  _W$  e#   Push copies of the new position and the amulet's position.
  =!   e#   Push 1 iff the positions are different.
}g     e# While =! pushes 1.
P      e# Call P.
];     e# Clear the stack.

```

### Alternate version

```
ZYm*   e# Push the Cartesian product of 3 and 2, i.e.,
       e#   [[0 0] [0 1] [0 2] [1 0] [1 1] [1 2] [2 0] [2 1] [2 2]].
l~     e#   Read and evaluate one line of input.
(=     e# Subtract 1 and fetch the corresponding element of the array.
:(     e# Subtract 1 from each coordinate.

```

### Function P

```
'.80*  e# Push a string of 80 dots.
W$Gb   e# Copy the amulet's position and convert from base 16 to integer.
'"t    e# Set the corresponding character of the string to '"'.
1$Gb   e# Copy the player's position and convert from base 16 to integer.
'@t    e# Set the corresponding character of the string to '@'.
G/     e# Split into chunks of length 16.
W%     e# Reverse the chunks (only needed for the alternate program).
N*     e# Join the chunks, separating by linefeeds.
oNo    e# Print the resulting string and an additional linefeed.

```

# Answer
> 8 votes
# Java, 231 bytes (196 if function)

Here's the full program code at 342:

```
class H{public static void main(String[]a){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}static void p(int p,int y){for(int i=0;i<80;i++){System.out.print((i==p?'@':i==y?'"':'.')+(i%16>14?"\n":""));}}}

```

Without the print function, 231:

```
class H{public static void main(String[]a){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}}

```

If just a function is okay (I'm unclear from the spec), then I can cut this down a bit further to 196:

```
void m(){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}

```

And with some line breaks for a bit of clarity...

```
class H{
    public static void main(String[]a){
        int p=0,y=79,c;
        y*=Math.random();
        y++;p(p,y);
        do
            p(
                (p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?
                    p-1:
                    c==68&p%16<15?
                        p+1:
                        c>86&p>15?
                            p-16:
                            c==83&p<64?
                                p+16:
                                p)
                ,y);
        while(p!=y);
    }

    static void p(int p,int y){
        for(int i=0;i<80;i++){
            System.out.print((i==p?'@':i==y?'"':'.')+(i%16>14?"\n":""));
        }
    }
}

```

Note that I'm not counting the print function `p(p,y)` itself, but I *am* counting the call to it, since I have stuff changing inside the call statement.

It works with capital letters `ASDW`. Due to the way it checks for those, some other letters might also work, but the spec doesn't really say anything about what should happen if I press different keys.

# Answer
> 5 votes
# Java, 574 bytes

```
import java.util.*;public class N{static Random r=new Random();static int v,b,n,m;public static void main(String[] a){v=r.nextInt(16);b=r.nextInt(5);n=r.nextInt(16);m=r.nextInt(5);p();do{Scanner e=new Scanner(System.in);char m=e.next().charAt(0);if(m=='w')b=b>0?b-1:b;if(m=='s')b=b<5?b+1:b;if(m=='a')v=v>0?v-1:v;if(m=='d')v=v<16?v+1:v;p();}while(v!=n || b!=m);}static void p(){System.out.println();for(int y=0;y<5;y++){for(int x=0;x<16;x++){if(x==z && y==x)System.out.print('@');else if(x==n && y==m)System.out.print('"');else System.out.print('.');}System.out.println();}}}

```

Basically the same as the C# version, except obfuscated & minimized.

# Answer
> 5 votes
# Julia, 161 bytes

Uses `w`, `a`, `s`, and `d` to move up, left, down, and right, respectively.

Full code, including printing (330 bytes):

```
B=fill('.',5,16)
a=[rand(1:5),rand(1:16)]
B[a[1],a[2]]='"'
c=[1,a==[1,1]?2:1]
B[c[1],c[2]]='@'
for i=1:5 println(join(B[i,:]))end
while c!=a
B[c[1],c[2]]='.'
m=readline()[1]
c[2]+=m=='a'&&c[2]>1?-1:m=='d'&&c[2]<16?1:0
c[1]+=m=='w'&&c[1]>1?-1:m=='s'&&c[1]<5?1:0
m∈"wasd"&&(B[c[1],c[2]]='@')
for i=1:5 println(join(B[i,:]))end
end

```

---

Scored code, excludes printing (161 bytes):

```
a=[rand(1:5),rand(1:16)]
c=[1,a==[1,1]?2:1]
while c!=a
m=readline()[1]
c[2]+=m=='a'&&c[2]>1?-1:m=='d'&&c[2]<16?1:0
c[1]+=m=='w'&&c[1]>1?-1:m=='s'&&c[1]<5?1:0
end

```

The difference here is that we don't save the game state as a matrix; all relevant information is contained in the arrays `c` and `a`. And, of course, nothing is printed. The user will no longer be prompted for input once the player reaches the amulet.

---

Ungolfed + explanation (full code):

```
# Initialize a 5x16 matrix of dots
B = fill('.', 5, 16)

# Get a random location for the amulet
a = [rand(1:5), rand(1:16)]

# Put the amulet in B
B[a[1], a[2]] = '"'

# Start the player in the upper left unless the amulet is there
c = [1, a == [1,1] ? 2 : 1]

# Put the player in B
B[c[1], c[2]] = '@'

# Print the initial game state
for i = 1:5 println(join(B[i,:])) end

# Loop until the player gets the amulet
while c != a

    # Put a dot in the player's previous location
    B[c[1], c[2]] = '.'

    # Read a line from STDIN, take the first character
    m = readline()[1]

    # Move the player horizontally within the bounds
    if m == 'a' && c[2] > 1
        c[2] -= 1
    elseif m == 'd' && c[2] < 16
        c[2] += 1
    end

    # Move the player vertically within the bounds
    if m == 'w' && c[1] > 1
        c[1] -= 1
    elseif m == 's' && c[1] < 5
        c[1] += 1
    end

    # Set the player's new location in B
    if m ∈ "wasd"
        B[c[1], c[2]] = '@'
    end

    # Print the game state
    for i = 1:5 println(join(B[i,:])) end

end

```

# Answer
> 3 votes
# Batch, 329 Bytes

```
@echo off
set e=goto e
set f= set/a
%f%a=0
%f%b=0
%f%c=%random%*3/32768+1
%f%d=%random%*16/32768+1
:et
call:p %a% %b% %c% %d%
if %a%%b% EQU %c%%d% exit/b
choice/C "wasd"
goto %errorlevel%
:1
%f%a-=1
%e%
:2
%f%b-=1
%e%
:3
%f%a+=1
%e%
:4
%f%b+=1
:e
if %a% GTR 4%f%a=4
if %a% LSS 0%f%a=0
if %b% GTR 15%f%b=15
if %b% LSS 0%f%b=0
%e%t

:p
setlocal enabledelayedexpansion
::creating a new line variable for multi line strings
set NL=^

:: Two empty lines are required here
cls
set "display="
for /l %%r in (0,1,4) do (
    set "line="
    for /l %%c in (0,1,15) do (
        set "char=."
        if %3 EQU %%r (
            if %4 EQU %%c (
                set char="
            )
        )
        if %1 EQU %%r (
            if %2 EQU %%c (
                set "char=@"
            )
        )
        set "line=!line!!char!"
    )
    set "display=!display!!line!!NL!"
)
echo !display!
exit /b

```

# Answer
> 3 votes
# Perl, ~~228~~ 222 characters (not counting the newlines that are not integral to the working of the code) — 207 if not counting the `print` and `print if` statement parts which are used for printing, but don't add to the game logic; 144 if also considering the field representation generation code as part of printing, as suggested by Yakk in the comments)

This code uses lowercase wasd for control; input must be confirmed with Enter. Tested with Perl 5.14.2.

```
($a=$==rand(79))+=($a>=($==rand(80)));
print $_=("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr;
%r=qw(w s/.(.{16})@/@\1./s a s/.@/@./ s s/@(.{16})./.\1@/s d s/@./.@/);
while(/"/){print if eval $r{getc STDIN}}

```

Note that for this code, it is impossible to separate calculation and printing, since the operations are done directly on the printed representation using regular expressions.

Explanation:

```
($a=$==rand(79))+=($a>=($==rand(80)));

```

This line determines the position of the player and the amulet. The player position is determined by `$==rand(80)` and is actually easy to understand: On a 5×16 board, there are 80 distinct positions where the player can be. The position is stored in the `$=` variable which forces the stored value into integer; this saves a few bytes for not needing to explicitly cast the result to integer (`rand` delivers a floating point value).

Since one of the positions is already occupied by the player, there are only 79 positions left for the amulet, therefore for the amulet's position, `$a=$==rand(79)` is used. Again, the assignment to `$=` forces a conversion to integer, however I further assign it to `$a` in order to reuse `$=` for the player's position.

Now to avoid the amulet to occupy the same position as the player, it is advanced by one position if its position is at least as large as the player's, giving an uniform distribution on the places not occupied by the player. This is achieved by `$a = ($a >= $=)` where `$=` here holds the player's position. Now the first line is generated by inserting the two initial assignments instead of the first `$a$ and the only`$=\` in this expression.

```
print $_=("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr;

```

This generates the initial field, and afterwards prints is. `("."x80)` just generates a string of 80 dots. `=~s/(.{$=})./\1@/r` then replaces the `$=`th character with `@`, and `=~s/(.{$=})./\1@/r` the `$a`th character with `"`. Due to the `r` modifier they don't try to modify in place, but return the modified string, that's why they can be applied to the previous expressions. Finally, `=~s/(.{16})/\1\n/gr` inserts a newline every 16 characters. Note that the field is stored in the special variable `$_` which can be used implicitly in later statements.

```
%r=qw(w s/.(.{16})@/@\1./s a s/.@/@./ s s/@(.{16})./.\1@/s d s/@./.@/);

```

This creates a hash containing the replacement rules for the different moves. A more readable version of this is

```
%r = ( 'w' => 's/.(.{16})@/@\1./s',
       'a' => 's/.@/@./',
       's' => 's/@(.{16})./.\1@/s',
       'd' => 's/@./.@/' );

```

The keys are the characters for the moves, and the values are strings containing the corresponding replacement rule.

```
while(/"/){print if eval"\$_=~$r{getc STDIN}"}

```

This is the main loop. `while(/"/)` checks if there is still a `"` character in `$_` (that is, in the field). If we move onto the amulet, its character gets replaced with the player character so it disappears from the field.

`eval $r{getc STDIN}` reads a character from standard input, looks up the corresponding replacement rule from the has `%r` and applies it to `$_`, that is, the field. This evaluates to true if a replacement was actually made (that is, the key was found in the hash *and* the move was possible; an impossible move won't match in the replacement rule). In that case `print` is executed. Since it is called without argument, it prints `$_`, that is, the modified field.

# Answer
> 2 votes
## C#, 256 248 234 227 226 225 bytes

Uses the NumPad arrows with NumLock turned on to move.

Indented and commented for clarity:

```
using System;
class P{
    static void Main(){
        int a=0,b=0,c,d,e;
        var r=new Random();
        while(0<((c=r.Next(16))&(d=r.Next(5))));
        Draw(a,b,c,d); // Excluded from the score.
        while(a!=c|b!=d){
            e=Console.ReadKey().KeyChar-48;
            a+=e==4&a>0?-1:e==6&a<15?1:0;
            b+=e==8&b>0?-1:e==2&b<4?1:0;
            Draw(a,b,c,d); // Excluded from the score.
        }
    }
    // The following method is excluded from the score.
    static void Draw(int a, int b, int c, int d){
        Console.Clear();
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                Console.Write(
                    x == a && y == b ? '@' :
                    x == c && y == d ? '"' :
                                       '.'
                );
            }
            Console.WriteLine();
        }
    }
}

```

# Answer
> 2 votes
# Html+JavaScript(ES6), score maybe 217

Too looong, but playable online in the snippets below.

Line 6 (T.value ...) is for output and not counted (but for simplicity I counted the textarea open and close tags, even if it's output too)

As for randomness: the amulet is always in the right half of the grid and the player always start in the left half.

Click on the textArea (after enlarging it) to start and restart the game.

```
<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>
<script>
R=n=>Math.random()*n|0,
s=e=>m(y=R(5),x=R(8),a=R(5)*17+R(8)+8),
m=k=>(x+=(x<15&k==39)-(x>0&k==37),y+=(y<4&k==40)-(y>0&k==38),p=y*17+x,
T.value=p-a?(t=[...('.'.repeat(16)+'\n').repeat(5)],t[a]='X',t[p]='@',t.join('')):t='Well done!'
)
</script>

```

EcmaScript 6 Snippet (Firefox only)

```
R=n=>Math.random()*n|0
s=e=>m(y=R(5),x=R(8),a=R(5)*17+R(8)+8)
m=k=>(
  x+=(x<15&k==39)-(x>0&k==37),
  y+=(y<4&k==40)-(y>0&k==38),
  p=y*17+x,
  T.value=p-a?(t=[...('.'.repeat(16)+'\n').repeat(5)],t[a]='"',t[p]='@',t.join('')):t='Well done!'
)
```

```
<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>
```

EcmaScript 5 snippet (tested in Chrome)

```
function R(n) { return Math.random()*n|0 }

function s() { m(y=R(5),x=R(8),a=R(5)*17+R(8)+8) }

function m(k) {
  x+=(x<15&k==39)-(x>0&k==37)
  y+=(y<4&k==40)-(y>0&k==38)
  p=y*17+x
  T.value=p-a?(t=('.'.repeat(16)+'\n').repeat(5).split(''),t[a]='"',t[p]='@',t.join('')):t='Well done!'
}
```

```
<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>
```

# Answer
> 2 votes
# Actionscript 3: 267 bytes

A working example is online

`var a:int,p:int,t;function g(){var r=Math.random;while(p==a){a=r()*80;p=r()*80}addEventListener("keyDown",function(e){if(a==p)return;if(e.keyCode==87&&p>15)p-=16if(e.keyCode==83&&p<64)p+=16if(e.keyCode==65&&p%16>0)p--if(e.keyCode==68&&(p+1)%16>0)p++print()});print()}`

Here's a complete (whitespaces included for readability) program using the game function:

```
package
{
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFormat;

    public class MiniRogue extends Sprite
    {
        var a:int, p:int, t;

        public function MiniRogue()
        {
            g();
        }

        function g(){
            var r=Math.random;
            while(p==a){
                a=r()*80;
                p=r()*80
            }
            addEventListener("keyDown",function(e){
                if(a==p)
                    return;
                if(e.keyCode==87&&p>15)
                    p-=16
                if(e.keyCode==83&&p<64)
                    p+=16
                if(e.keyCode==65&&p%16>0)
                    p--
                if(e.keyCode==68&&(p+1)%16>0)
                p++
                print()
            });
            print()
        }

        var old:int = -1;
        private function print():void {
            if (!t) {
                t = new TextField()
                t.defaultTextFormat = new TextFormat("_typewriter", 8)
                t.width=500;
                t.height=375;
                addChild(t)
            }
            var board:String = "";
            for (var i:int=0; i<80;i++) {
                if (i == p) {
                    board += "@";
                } else if (i == a) {
                    board += '"';
                } else {
                    board += ".";
                }
                if ((i + 1) % 16 == 0) {
                    board += "\n";
                }
            }
            if (a==p) {
                board += "Win!";
            }
            if (p == old) {
                board += "Bump!";
            }
            old = p;
            t.text = board;
        }
    }
}

```

# Answer
> 2 votes
# Javascript: 307 216

You can play in the snippet below! The numbers on the left are just so the console (chrome one at least) doesn't merge the rows.

To run the code:

1. hit "run code snippet"
2. hit ctrl-shift-j to open the console
3. click in the result section
4. use arrow keys and play

```
var x=y=2,m=Math,b=m.floor(m.random()*5),a=14,i,j,t,c=console,onload=d;function d(){c.clear();for(i=0;i<5;i++){t=i;for(j=0;j<16;j++){t+=(i==y&&j==x)?"@":(i==b&&j==a)?'"':".";if(a==x&&b==y)t=":)";}c.log(t);}}onkeydown=function(){switch(window.event.keyCode){case 37:if(x>0)x--;break;case 38:if(y>0)y--;break;case 39:if(x<15)x++;break;case 40:if(y<4)y++;break;}d();};
```

Un-golfed:

```
var px=py=2,m=Math,ay=m.floor(m.random()*5),ax=14,i,j,t,c=console,onload=draw;
function draw() {
  c.clear();
  for(i=0;i<5;i++) {
    t=i;
    for(j=0;j<16;j++) {
      t+=(i==py&&j==px)?"@":
         (i==ay&&j==ax)?'"':".";
      if(ax==px&&ay==py)t=":)";
    }
    c.log(t);
  }
}
onkeydown=function() {
  switch (window.event.keyCode) {
    case 37:
      if(px>0)px--;
      break;
    case 38:
      if(py>0)py--;
      break;
    case 39:
      if(px<15)px++;
      break;
    case 40:
      if(py<4)py++;
      break;
  }
  draw();
};

```

**Edit 1:** Read rules more carefully and rewrote my code accordingly

* amulet y value is now randomized
* player can no longer escape room
* I no longer count the characters in the draw function or calls to it

# Answer
> 1 votes
# SpecBAS - ~~428~~ 402 (excluding printing, ~~466~~ 425 when counted)

Uses Q/A/O/P to move up/down/left/right respectively.

The line to print the dungeon at line 1 is the only line that can be ignored, but have golfed that down a bit as well.

```
1 PRINT ("."*16+#13)*5
2 LET px=8: LET py=3
3 LET ax=INT(RND*16): LET ay=INT(RND*5): IF ax=px AND ay=py THEN GO TO 3
4 PRINT AT ay,ax;#34;AT py,px;"@": LET ox=px: LET oy=py: PAUSE 0: LET k$=INKEY$
5 LET px=px+(k$="p")-(k$="o")
6 IF px<0 THEN LET px=0
7 IF px>15 THEN LET px=15
8 LET py=py+(k$="a")-(k$="q")
9 IF py<0 THEN LET py=0
10 IF py>4 THEN LET py=4
11 PRINT AT oy,ox;"."
12 IF SCREEN$(px,py)<>#34 THEN GO TO 4

```

The reference to #34 is just a short-hand way of putting CHR$(34) in the code.

Thanks @Thomas Kwa, I hadn't noticed player start position being random was optional. Also used separate IF statements to shave off a few characters.

# Answer
> 1 votes
## Another C#, ~~221~~ ~~171~~ 170

Here is another way in C# with both positions random. Wanted to show this even if this part is 7 bytes longer than Hand-E-Food's solution.
Hand-E-Food's answer will be shorter of course as soon as he will use Console.Read().
The downside of Consol.Read is, that pressing the needed Enter causes the field to be printed 2 more times.
But I don't think there is a requirement to print just on (real) input.
Navigation is done by 8426 as in Hand-E-Foods solution.

```
using System;
class P
{
static void Main()
{
Func<int> n=new Random().Next;
int x=n()%16,y=n()%5,a=n()%16,b,m;
while(y==(b=n()%5));

while(x!=a|y!=b)
{
Printer.Print(a, b, x, y);  // Excluded from the score.
m=Console.Read()-48;
y+=m==8&y>0?-1:m==2&y<4?1:0;
x+=m==4&x>0?-1:m==6&x<15?1:0;
}
}
}

```

**Edit:** (added new solution and moved PrinterClass to the end)
**Edit2:** (changed a 14 to a 15 and saved the byte by starting on right-bottom)
Adapting the technique of Mauris it is possible to melt it down to 171 bytes in C# (of course now without both positions random):

```
using System;
class P
{
static void Main()
{
int p=79,a=new Random().Next()%p,m;
while(p!=a){
Printer.Print(p,a);  // Excluded from the score.
m=Console.Read()-48;
p+=m==4&p/5>0?-5:m==6&p/5<15?5:m==8&p%5>0?-1:m==2&p%5<4?1:0;
}
}
}

```

The Printer Class is nearly the same, just a new overload of print...

```
class Printer
{
    public static void Print(int ax, int ay, int px, int py)
    {
        Console.Write('\n');
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                if (x == px && y == py)
                    Console.Write('@');
                else if (x == ax && y == ay)
                    Console.Write('"');
                else
                    Console.Write('.');
            }
            Console.Write('\n');
        }
    }

    public static void Print(int p, int a)
    {
        Print(p/5,p%5,a/5,a%5);
    }
}

```

# Answer
> 1 votes
## Ruby, 185

Here is a Ruby example too.
I'm very new to Ruby, maybe someone knows how to do that better :)

I have counted lineFeeds as 1 since the Program will crash otherwise...

Navigation is done by 8462. You need to send input each time with enter.

```
def display(ax,ay,px,py)
    puts
    for y in 0..4
        for x in 0..15
            if (x == px && y == py)
                print "@"
            elsif (x == ax && y == ay)
                print '"'
            else
                print '.'
            end
        end
        puts
    end
end

x=y=0
a=Random.rand(16) while y==(b=Random.rand(5))
while x!=a or y!=b
display(a,b,x,y)  # Excluded from the score.
m=gets.chomp.to_i
y-=m==8?1:0 if y>0
y+=m==2?1:0 if y<4
x-=m==4?1:0 if x>0
x+=m==6?1:0 if x<15
end

```

# Answer
> 1 votes
# QBasic, 103 bytes

Per the rules of the challenge, the `Show` subprogram is not included in the byte-count, nor is the `Show p, q, a, b` call (with the following newline).

```
b=1+TIMER MOD 9
1Show p, q, a, b
INPUT m
p=p-(m=2)*(p>0)+(m=4)*(p<4)
q=q-(m=1)*(q>0)+(m=3)*(q<15)
IF(p<>a)+(q<>b)GOTO 1

SUB Show (playerRow, playerCol, amuletRow, amuletCol)
CLS
FOR row = 0 TO 4
  FOR col = 0 TO 15
    IF row = playerRow AND col = playerCol THEN
      PRINT "@";
    ELSEIF row = amuletRow AND col = amuletCol THEN
      PRINT CHR$(34);    ' Double quote mark
    ELSE
      PRINT ".";
    END IF
  NEXT
  PRINT
NEXT
END SUB

```

To move, input a number and press Enter: `1` to go left, `2` to go up, `3` to go right, and `4` to go down.

This code does not output the game state at the end, when the player has found the amulet. To make it do so, add another `Show p, q, a, b` after the `IF` statement.

## Explanation

Let `a`, `b` represent the coordinates of the amulet and `p`, `q` the coordinates of the player. The player starts at (0, 0), and the amulet starts on row 0, with a column between 1 and 9, inclusive, based on the 1's digit of the current time.

The rest is just a bunch of math with conditionals. The important thing to remember is that conditionals in QBasic return `0` for false, `-1` for true. Let's look at the player row update statement:

```
p=p-(m=2)*(p>0)+(m=4)*(p<4)

```

If `m=2`, we want to move up by subtracting 1 from `p`, as long as `p>0`. Similarly, if `m=4`, we want to move down by adding 1 to `p`, as long as `p<4`. We can obtain the desired behavior by multiplying. If both factors are `-1`, their product will be `1`, which we can subtract from or add to `p`. If either conditional is `0`, the product will be `0`, with no effect.

Similarly, the condition to determine whether the player has found the amulet is:

```
IF(p<>a)+(q<>b)GOTO 1

```

If either of the conditionals is true, their sum will be nonzero (either `-1` or `-2`) and thus truthy, and the program returns to line 1. Once `p` equals `a` and `q` equals `b`, both conditionals will be `0`, so their sum will be `0` and control flow can reach the end of the program.

---
Tags: code-golf
---


title: There's no such thing as a free lunch

text:
# Question
Title: There's no such thing as a free lunch
...or is there?

Your challenge is to parse my lunch bill, which contains the base price, tips, discounts, coupons, and extras and **find out if my lunch was $0 or less**. If this is the input:

```
12.34
15 tip
25 discount
1.5 extra
2 coupon

```

Then the output might be `false`. Here's how it works:

`12.34` is the base price.

`15 tip` means to *add 15% to the total.*

`25 discount` means to *subtract 25% from the total.*

`1.5 extra` means to *add 1.5 to the total.*

`2 coupon` means to *subtract 2 from the total.*

There may be **any amount of** tips, discounts, coupons, and extras, but there will always be one base price.

Then we do `(12.34 * 1.15) * 0.75 + 1.5 - 2` for an output of 10.14. 10.14 is greater than 0, so we output false. My lunch was not free.

# Rules

*number* `tip` means to add *number* percent to the total.

*number* `discount` means to subtract *number* percent from the total

*number* `extra` means to add *number* to the total

*number* `coupon` means to subtract *number* from the total

# Another example:

```
10
20 tip
20 discount
2 coupon
2 coupon
1 coupon
50 discount
2.55 coupon

```

The price is `-0.24` ((10 * 1.20 * 0.80 - 2 - 2 - 1) * 0.5 - 2.55), so the output is true (my lunch was free.)

Notes:

* Precision must be at least 2 decimal places.
* You can take input as a string with newlines (trailing newline optional) or another separation character, or an array/list of the inputs.

# Answer
# 05AB1E, ~~37~~ ~~33~~ 34 bytes

```
I|vy#`0èÇ7%`">* - (>* +"#sè.V}î0›_

```

Try it online!

**Explanation**

Borrows the `mod 7` trick from Jonathan Allan's Jelly answer

```
I                                  # initialize stack with first input
 |v                                # loop over all other inputs
   y#`                             # split input on space as separate to stack
      0èÇ                          # get the character code of the first letter of the type
         7%`                       # mod by 7
            ">* - (>* +"#          # push the list ['>*','-','(>*','+'] where
                                   # '>*' =  increment and multiply
                                   # '-' =   subtract
                                   # '(>*' = negate, increment, multiply
                                   # '+' =   add
                         s         # swap the top 2 items on the stack
                          è        # use the mod result to index into the list
                           .V      # run as 05AB1E code
                             }     # end loop
                              î0›_ # check if the result rounded up to nearest integer
                                   # is less than or equal to 0

```
> 1 votes

# Answer
## JavaScript (ES6), ~~88~~ 85 bytes

Takes input as an array of strings. Returns `0` for not free or `1` for free.

```
a=>a.map(s=>([a,b]=s.split` `,t+={e:+a,c:-a,t:x=t*a/100,d:-x}[(b||'e')[0]]),t=0)|t<=0

```

### How it works

Each line is split on the space to get `a` = amount, `b` = type of operation. If there's no operation at all (which is the case on the first line), `b` is set by default to `"e"` for "extra".

To add the correct amount to the total `t`, we use an object whose keys are the first letter of the operation:

```
{
  e: +a,           // extra
  c: -a,           // coupon
  t: t * a / 100,  // tip
  d: -t * a / 100  // discount
}

```

**Note**: If the bill consisted of only one element, `map()` would return a single-element array which would be coerced to an integer when applied the `|` operator, making the final test fail. But the OP confirmed that this can't happen. (Arrays of 2 or more elements are coerced to 0.)

### Demo

```
let f =

a=>a.map(s=>([a,b]=s.split` `,t+={e:+a,c:-a,t:x=t*a/100,d:-x}[(b||'e')[0]]),t=0)|t<=0

console.log(f([
'12.34',
'15 tip',
'25 discount',
'1.5 extra',
'2 coupon'
]))

console.log(f([
'10',
'20 tip',
'20 discount',
'2 coupon',
'2 coupon',
'1 coupon',
'50 discount',
'2.55 coupon'
]))
```
> 8 votes

# Answer
# Jelly,  ~~42~~ 39 bytes

```
⁾_@
⁾C×
”+
⁾‘×
ḲµṪḢO%7µĿṭ
ḢW;Ç€j”µFV>0¬

```

Takes a list of strings with decimal formatted numbers
(Leading zeros *will* work, but have the side effect of printing zeros to STDOUT prior to the final result).

**Try it online!** \- not free; or free.

### How?

```
⁾_@ - Link 1: a coupon
⁾_@ - literal "_@" - the Jelly code for subtraction with reversed arguments

⁾C× - Link 2: a discount
⁾C× - literal "C×" - the Jelly code for complement (1-input) then multiply

”+ - Link 3: extra cost
”+ - literal '+' - the Jelly code for add

⁾‘× - Link 4: a tip
⁾‘× - literal "‘×" - the Jelly code for increment (input+1) then multiply

ḲµṪḢO%7µĿṭ - Link 5, switch: char list
Ḳ          - split on spaces (gives [amount, type] as char lists)
 µ     µ   - monadic chain separation to get a value, say v
  Ṫ        - tail (get the type: "coupon", "discount", "extra", or "tip")
   Ḣ       - head (get the first character: 'c', 'd', 'e' or 't')
    O      - cast to ordinal (99, 100, 101, or 116)
     %7    - mod 7 (1, 2, 3, or 4)
        Ŀ  - call link v as a monad
         ṭ - tack to the amount char list

ḢW;Ç€j”µFV>0¬ - Main link: list of strings (char lists)
Ḣ             - head - the base price char list
 W            - wrap in a list
   Ç€         - call the last link (5) as a monad for €ach of the rest
  ;           - concatenate
      ”µ      - literal 'µ' - Jelly's monadic chain separator
     j        - join all the parts with 'µ's             "10",".2 tip",".2 discount", "2 coupon","2 coupon","1 coupon",".5 discount","2.55 coupon":
        F     - flatten (makes a char list, for example: "10µ.20‘×µ.20C×µ2_@µ2_@µ1_@µ.50C×µ2.55_@")
         V    - evaluate as Jelly code (the above evaluates to -0.2499999999999991)
          >0  - greater than 0?
            ¬ - not

```
> 2 votes

# Answer
# CJam, ~~45~~ 42 bytes

```
q~Sf/(sd\{L(d\~ci6%"1\-* + )* -"S/=~}fL0>!

```

Take input as an array of strings, and takes the tip and discount as decimals.

Try it online!

**Explanation**

```
q~                e# Read and eval the input.
Sf/               e# Split each string by spaces.
(sd               e# Pull out the first element (base price) and cast it to a double.
\                 e# Bring the array back to the top.
{                 e# For each element L in the array:
 L                e#  Push L.
 (d               e#  Pop out the first element and cast it to a double.
 \~               e#  Bring the second element to the top of the stack.
 ci6%             e#  Mod its first character's ASCII value by 6. (c,d,e,t) -> (3,4,5,2)
 "1\-* + )* -"S/  e#  Push this string and split it on spaces.
 =                e#  Get the element given by number from the mod. CJam uses modular arrays,
                  e#    so 4 and 5 get elements 0 and 1 respectively.
 ~                e#  Eval whichever string was retrieved.
}fL               e# (end of loop)
0>!               e# Check if it's not greater than 0.

```

The code which is evaluated depending on the first letters:

```
t -> ")*"    Adds 1 to the tip amount and multiplies it by the current price.

d -> "1\-*"  Subtracts the discount amount from 1 and multiplies it by the current price.

e -> "+"     Adds the extra amount to the current price.

c -> "-"     Subtracts the coupon amount from the current price.

```
> 2 votes

# Answer
# GNU sed + dc, ~~117~~ ~~111~~ 107 bytes

Using `-z` interpreter flag (included in score as 1 byte):

```
s/discount/_tip/g
s/tip/.01*1+*/g
s/extra/+/g
s/coupon/-/g
s/.*/dc -e '& 0r-p'/e
s/[^-]*$/free/
s/-/not /

```

## Explanation

```
#!/bin/sed -fz

# Convert to dc expression (discount is just a negative tip)
s/discount/_tip/g
s/tip/.01*1+*/g
s/extra/+/g
s/coupon/-/g

# Run dc
s/.*/dc -e '& 0r-p'/e

# Convert to pretty output
s/[^-]*$/free/
s/-/not /

```

Since the input is already very close to Reverse Polish notation, it's a simple matter to transform `extra` and `coupon` to `+` and `-`, and not much more to change the percentages into multipliers. Then invoke `dc` and produce a readable result depending on whether `-` is found (we have to negate the result, so a `-` implies "not free", otherwise 0 would be a special case that would need its own handling).

## Example

The second case from the question is:

```
10
20 tip
20 discount
2 coupon
2 coupon
1 coupon
50 discount
2.55 coupon

```

That becomes this `dc` program:

```
10
20 .01*1+*
20 _.01*1+*
2 -
2 -
1 -
50 _.01*1+*
2.55 -
 0r-p

```

Resulting in:

```
free

```
> 2 votes

# Answer
# JavaScript, ~~173~~ ~~169~~ 145 bytes

```
i=>{w=i.split`\n`.map($=>$.split` `);t=+w.shift()[0];p=$=>t*$/100;w.map(x=>{k=+x[0];f=x[1][0];l={e:k,c:-k,t:p(k),d:-p(k)},t+=l[f]});return t<=0;}

```

There should still be plenty of golfing to do

Try it online! (145 bytes currently)

Try it out:

```
<script>var _=i=>{w=i.split('\n').map($=>$.split(' '));t=+w.shift()[0];p=$=>t*$/100;w.map(x=>{k=+x[0];f=x[1][0];t+=f=='e'&&k||f=='c'&&(-k)||f=='t'&&p(k)||f=='d'&&(-p(k))});return t<=0;}</script>
<textarea oninput="document.querySelector('pre').innerText=_(this.value)"></textarea>
<pre></pre>
```

Thanks to programmer5000 for all his golfing advice
> 1 votes

# Answer
# JavaScript (ES6), 97 ~~107~~

Input as a multiline string with a trailing newline.

```
t=>t.replace(/(\S+) ?(.*)?\n/g,(x,d,b)=>t-=b>'t'?-t*d/100:b>'e'?d:b>'d'?t*d/100:b?-d:d,t=0)&&t>=0

```

The regexp splits the numeric and optional text part for each line in *d* and *b*.
The calculations should be more or less obviuos. Just some note:
\- using `-=` to avoid problems mixing number with strings
\- the sum is negated to save 1 byte, so the last check is for `>= 0` instead of `<= 0`

PS still way longer than @Arnauld's. Rats.

**Test**

```
var f=
t=>t.replace(/(\S+) ?(.*)?\n/g,(x,d,b)=>t-=b>'t'?-t*d/100:b>'e'?d:b>'d'?t*d/100:b?-d:d,t=0)&&t>=0

a=`12.34
15 tip
25 discount
1.5 extra
2 coupon
`
b=`10
20 tip
20 discount
2 coupon
2 coupon
1 coupon
50 discount
2.55 coupon
`

console.log('Not free: '+a,f(a))
console.log('Free: '+b,f(b))
```
> 1 votes

# Answer
# Python 133 bytes

```
def f(b):
 t=float(b.pop(0))
 for l in b:
  v,a=l.split(' ');v=float(v);t+={'t':t*v/100,'d':-t*v/100,'c':-v,'e':v}[a[0]]
 return t<=0

```

Similar to the JavaScript ES6 version. But type conversion is required for `float` values in Python.

Explanation:

Extract the first value and convert it to float.

For each other line in the bill:

1. split and convert the value to `float`
2. Use a `dict` to select the right operation according to the first letter
3. Accumulate the value

Usage:

```
print(f([
'12.34',
'15 tip',
'25 discount',
'1.5 extra',
'2 coupon'
]))

print(f([
'10',
'20 tip',
'20 discount',
'2 coupon',
'2 coupon',
'1 coupon',
'50 discount',
'2.55 coupon'
]))

```
> 1 votes

# Answer
# PowerShell, 218 156 143 bytes

```
($n=$args)|%{[float]$v,$w=$_-split' ';switch -w($w){"t*"{$t+=$v}"d*"{$d+=$v}"e*"{$e+=$v}"c*"{$c+=$v}}};($n[0]*(1+$t/100)*(1-$d/100)+$e-$c)-lt 0

```

Try it online!

**EDIT** Saved bytes by splitting the piped variable beforehand

**EDIT 2** Stored second part of string so I could make better wildcard calls
> 0 votes

# Answer
# C# ~~324~~ 219 bytes

```
bool a(string[] l){var x=0f;foreach(var s in l){var b=float.Parse(s.Split(' ')[0]);if(s.EndsWith("p"))x*=b;else if(s.EndsWith("t"))x*=1-b;else if(s.EndsWith("n"))x-=b;else if(s.EndsWith("a"))x+=b;else x=b;}return x<=0;}

```

It's not pretty, and probably not the best way, but here it is. Requires input be passed as a string array, and tips/discounts passed as floats (`0.15 tip` instead of `15 tip`) as this has been clarified as acceptible in the comments of the spec.

Explaination:

```
bool a(string[] l){                         //Define method with input string array l and bool output
    var x=0f;                               //Initialize float x
    foreach(var s in l){                    //Iterate through lines
        var b=float.Parse(s.Split(' ')[0]); //Parse the number from the line and store it in float b
        if(s.EndsWith("p"))                 //If line ends with "p" then line is "tip"
            x*=b;                           //Parse number from line to float add 1 and multiply by x
        else if(s.EndsWith("t"))            //If line ends with "t" then line is "discount"
            x*=1-b;                         //Parse number from line to float, subtract from 1 and multiply by x
        else if(s.EndsWith("n"))            //If line ends with "n" then line is "coupon"
            x-=b;                           //Parse number from line to float and subtract from x
        else if(s.EndsWith("a"))            //If line ends with "a" then line is "extra"
            x+=b;                           //Parse number from line to float and add to x
        else x=b;                           //Line is base price
    }                                       //End foreach
    return x<=0;                            //Return x less than or equal to 0
}                                           //End method

```

There's gotta be a better way to do this, but this works at least
> 0 votes

# Answer
# Java 227 bytes

Been a while and still no Java answer that I can see, so here's my C# answer ported to Java, at the cost of 8 bytes

```
boolean a(String[] l){Float x=0f;for(String s:l){Float b=Float.parseFloat(s.split(" ")[0]);if(s.endsWith("p"))x*=b;else if(s.endsWith("t"))x*=1-b;else if(s.endsWith("n"))x-=b;else if(s.endsWith("a"))x+=b;else x=b;}return x<=0;}

```

For an explanation and such, see my C# answer

Like that answer, this answer expects that the tip and discount be passed as floats (`0.15` not `15`)
> 0 votes

# Answer
# Jq 1.5, ~~129~~ ~~119~~ ~~114~~ 112 bytes

```
reduce (.[]/" "|.[0]|=tonumber|.[1]|=length)as[$n,$c](0;[$n,0,0,.+.*($n/100),0,.+$n,.-$n,0,.-.*($n/100)][$c])<=0

```

Expanded

```
  reduce (
      .[]/" "             # split each element into [value,command]
    | .[0]|=tonumber      # convert value to number
    | .[1]|=length        # convert command to length
  ) as [$n,$c]
  (  0
   ; [ $n                 # "" -> set base
     , 0
     , 0
     , .+.*($n/100)       # "tip"
     , 0
     , .+$n               # "extra"
     , .-$n               # "coupon"
     , 0
     , .-.*($n/100)       # "discount"
     ][$c]                # ... depending on command length
  ) <=0                   # true if lunch was free

```

Try it online!
> 0 votes

---
Tags: code-golf, string, math, number
---