Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

You are a traveller crossing the desert between two towns. You cannot carry enough water to get across without stopping. This is a variation of a classic puzzle.

The Rules

A desert looks like this: a WxH grid of mostly empty space. The space marked S is where you start, E is where you want to end, and a square marked with the number N holds N units of water. Squares marked with a . hold zero water.

.....................................
........S............................
.....................................
.........7...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

You start at S with 5 units of water.

You can carry at most 5 units of water.

Each turn you

  1. move one square Up, Down, Left, or Right,
  2. consume 1 unit of water that you are carrying,
  3. pick up or drop some number of units of water.

A turn is notated thus: (direction)(+|-)(units of water), + indicates you are picking up water, - that you are dropping it.

Example turns:

D+0        Move Down
R+0        Move Right
D+2        Move Down, pick up two units of water.
U-1        Move Up, drop one unit of water.

If you perform these moves starting at S in the example above, the desert looks like this afterwards.

.....................................
........S............................
.........1...........................
.........5...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

You can pick up no more water than is already on your square. When you pick up the water, deduct that number of units from the tile's count.

You can only pick up water to hold a maximum of 5 units.

No tile can hold more than 9 units, except S which holds infinity units.

You can only drop as much water as you are currently holding.

Water on the ground remains unchanged until you pick it up again.

If you return to S you can pick up any quantity of water without depleting it.

If you reach E then you win. You still win if you consume your last unit of water on E.

If, after your turn, you have zero water and you are not on E, you die.

Input and Output

Your program will receive a starting map of arbitrary size on STDIN as ASCII art in the format above. You can assume it is rectangular i.e. all lines the same length, that there is exactly one S and one E square, all lines are terminated with \n, and the whole of STDIN will conform to this regex: /^[SE1-9\.\n]+$/

Your program will write the following output to STDOUT:

  1. the list of moves,
  2. the final state of the map.

You may output the list of moves in any convenient format.

The final state of the map will be printed in the same format as the input except that it will additionally show the route you took through the desert by marking all visited tiles with #, if that tile contains no water and is not S or E (i.e. it is .).

EXAMPLE input:

.....S.
.......
.......
E......
....8..

EXAMPLE winning output:

D+0
D+0
D+0
D+0
L+5
L+0
L+0
L+0
L+0
U+0
.....S.
.....#.
.....#.
E....#.
####3#.

Nontriviality

When you post your code, post a sample map input which your code finds a solution for which satisfies the following non-triviality conditions:

  • S and E are at least 10 moves apart.
  • Any square which initially contains N units of water must be surrounded by a N-width border in which all squares are . (no water, not S or E)

EXAMPLE

........2.
..........
..........
S.1..2....
..........
..........
........1.
..3.......
.........E

If you increase the amount of water on any tile, the above becomes trivial.

Requirements

Presumably your program will encounter a number of failed attempts before it finds a solution, if any.

  1. Your program must eventually solve any solvable input.
  2. I want to watch you die -- your program will output the moves and final map of the route to death for each and every failed attempt to find a solution.
  3. If you encounter a winning solution, print the full output for that and terminate.
  4. Run until a solution is found, but do not attempt the same solution twice -- all deaths should be by distinct routes.
  5. Use this a test input:

(it requires at least one move to drop a water cache at some midpoint).

 S........
 .........
 .........
 ........E

Shortest code which is posted with a non-trivial demonstration input which it solves wins.

share|improve this question
    
This needs to be clarified to specify whether the program needs to be able to solve any solvable map, or whether it only has to work for one map. I'd definitely encourage the former; in the case of one map, it'll be easier to hardcode the solution than to calculate it. – ais523 3 hours ago
    
Edited for clarity. Yes you win if you have more than zero water, and yes your program must solve all solvable inputs. – spraff 3 hours ago
    
What's stopping you to use an algorithm such as A* and dropping a path of 5 units on each tile you successively go to and go back to the start if you step onto a tile without 5 water? – BlueEyedBeast 1 hour ago
    
Nothing. Go ahead. – spraff 28 mins ago

Perl, 299 + 1 = 300 bytes

This will almost certainly be beaten by one of the golfing languages when people see my algorithm :-)

Run with -n (1 byte penalty).

push@a,[split//];($s,$t)=(length$`,$.)if/S/;($e,$f)=(length$`,$.)if/E/;END{{$\.=y/LRUD/RLDU/r.X.reverse.$\;$a[$t-1][$s]=~y/./#/;$_.=L,$s++,redo if $s<$e;$_.=R,$s--,redo if $s>$e;$_.=U,$t++,redo if $t<$f;$_.=D,$t--,redo if $t>$f;$\=~s/(.)X/lc$1/eg;$_=reverse;$\=~s/$_.*//si;print map{join'',@$_}@a;}}

Example:

E.....
#.....
#.....
#.....
#####S
XlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLuDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLUuDDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLuDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLUUuDDDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLuDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLUuDDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLuDRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLlRRRRrlrLlRrlrLLlRRrlrLlRrlrLLLlRRRrlrLlRrlrLLlRRrlrLlRrlrLLLLLUUUu

The output always starts with an X, which represents starting with 5 units. The moves are:

  • LRUD: move left, right, up, or down (respectively), and pick up 1 unit of water
  • lrud: move left, right, up, or down (respectively), and pick up 4 units of water if on S, drop all but one unit of water if on E, and drop 2 units of water on any other square.

As you can see, it's possible to cross this (rather barren) map using no extra pools at all. In fact, it's possible to get any distance under these rules, on any map, without the help of any preplaced water. As such, this algorithm just ignores any preplaced water, meaning I don't have to waste characters worrying about it. This also means that you're not going to see the bot die, sorry. It never moves beyond the range in which it knows it's guaranteed to survive.

I'd recommend against running this on a large map, because it has O(2^n) performance (although the bot never dies of thirst, it's plausible to think it would die of hunger using a strategy like this.)

Readable version:

# implicit with -n: read a line of input into $_
push @a, [split //]; #/ split $_ into characters, store at the end of @a
($s,$t) = (length$`,$.) if /S/; # if we see S, store its coordinates
($e,$f) = (length$`,$.) if /E/; # if we see E, store its coordinates
END {{ # due to -n, loop back to start if there are more lines
# from here onwards, $\ stores the partial solution, $_ stores the path
# back from ($s, $t) to the oasis at S in reverse order; both are null
# strings on the first loop iteration
$\ .=            # keep the path so far, and add:
  y/LRUD/RLDU/r. # the path from S to ($s, $t)
  X.reverse.     # a marker X, then the path from ($s, $t) back to S
$\;              # another copy of the original path
# The loop invariant is that $\ holds a strategy for dropping 2 units of
# water on every square from S to ($s, $t); initially, ($s, $t) is S, and
# the path is empty, satisfying the invariant.
# To update the path for a new ($s, $t), we path to the square (picking up
# water as we go to replenish water lost to thirst), drop 2 units, then go
# back home (picking up water on the way back to break even). The drop is
# marked by placing an X immediately after it, at this point.
$a[$t-1][$s]=~y/./#/; # Mark ($s, $t) with a # sign on the map.
$_.=L,$s++,redo if $s<$e; # Extend the path east towards the goal, if we can.
$_.=R,$s--,redo if $s>$e; # Extend the path west towards the goal, if we can.
$_.=U,$t++,redo if $t<$f; # Extend the path south towards the goal, if we can.
$_.=D,$t--,redo if $t>$f; # Extend the path north towards the goal, if we can.
# The above four lines loop back to the {{ via "redo" if they match.
$\ =~ s/(.)X/lc$1/eg; # Change the notation MOE+X to move.
# (We could remove the previous line if it's deemed reasonable
# to use two characters for some moves and one for others.)
# At this point, we have a path from S to E and back again, dropping water
# on the way. We want to stop the path at E, so process a bit more:
$_ = reverse; # now $_ is the path back from E to S
$\=~s/$_.*//si; # delete everything from $_ onwards in $\
print map {join'',@$_} @a; # show the user the output
}} # and we're done.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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