aHHHH! The Beasts are HHHHere!

19

3

As we learned from the IBM PC AT, YouTube (see video), Wikipedia (see article), and Sesame Street:

The letter H is the most merciless letter of the alphabet!

(Even when actually composed from two elements in Code Page 437. In fact, it's even MORE merciless that way.)

Like the Aliens in, uhm...er... Aliens, Beasts relentlessly pursue all who would dare come near their eggs. There is no reasoning with them. You must squash them if not to perish.

A frightening encounter with the 4H Club

For this scenario we will assume you're down to your last life, and you've met plain Beasts in a terrain with no eggs (as in the Wikipedia screenshot). You don't have a numeric keypad and can only move directly up/down/left/right...but the beasts apparently have one, and can move diagonally on their turn.

A Beast's choice of move among its options will be the one that minimizes distance from the player. If the distances are equal then tie breaking is done favoring left+up over right+down, but here's the disambiguation matrix to be explicit about it...lowest number to tie-break:

1 3 4
2 H 5
6 8 7

A beast never sleeps, but they are fortunately a bit slower than the player. They move every other turn (giving the player a head start by beginning their alternations on the second turn). They must move if a move is possible, regardless of if that takes them further from the player.

You crush a beast if you move a train of movable walls where it was sitting in a closed gap. These plain beasts are worth 2 points a head.

Input

  1. A pair of integers indicating a map's size in columns then rows.

  2. Row count of lines of input, each of the column size...containing either a solid wall (#), a movable wall (~), a beast (H), the player (O) or just a space.

  3. Input that will be either U, D, L, R indicating an attempted move by the player... or W to just wait. Note that attempting to push a movable wall which is blocked is legal input, it just will result in no action.

Output

  1. aHHHH! if the beasts killed the player...or nothing if the player won with no beasts remaining

  2. The score

(Note: For debugging purposes and/or amusement, you'll probably want to be able to output the state at each step; but that's too long to post here.)

Clarifications

  • Maps are guaranteed to be bounded by solid walls.

  • The order of who moves in a turn matters for the outcome. Thus: The player always goes first, then the beasts are given an ordering based on their initial map position if you were sweeping across the screen top to bottom left to right. (A row 1 beast moves before a row 2 beast, and two beasts on the same row it would be the one with the lowest column number that would move before the other)

  • Diagonal moving beasts can move into any open adjacent diagonal space, regardless of if it requires squeezing between walls.

  • A player can push any number of movable walls in a line provided that there's a space or a beast on the other end. But trying to push a train of walls into a Beast that is not pinned between walls treats the Beast as a wall, and won't allow the move.

  • A Beast's move decision during a turn is based on the player's location at the beginning of the turn. Its desired optimization of "distance to player" is through an "as the crow flies" calculation. Any approximation which would give the same result as measured from the center of its square to the center of the player's square is fine.

  • If a Beast can't make what would have been its first preferred move in a turn because a higher priority Beast took its spot, it will take its next best choice as opposed to staying in place (if a move is still possible).

Sample Cases

Simple Crush

Input

5 3
#####
#O~H#
#####
R

Output

2

Preference Matrix -> Death

Input

5 5
#####
#O  #
# ~ #
#  H#
#####
WWDW

Output

aHHHH!
0

Preference Matrix -> Win

Input

5 5
#####
#O  #
# ~ #
#  H#
#####
WRD

Output

2

Waiting For the Reaper

Input

5 5
#####
#O  #
# ~ #
#  H#
#####
WWW

Output

aHHHH!
0

Successful Defeat in the Wikipedia Scenario

Input

40 23
########################################
#~      ~ ~~  ~  ~ ~~   ~ ~~    ~ ~ ~~ #
#~~ ~          ~~   ~   ~ ~~         ~ #
#~# ~~   ~~~~      ~  ~~~~  ~    ~~~  ~#
# ~        ~   ~ ~~ #~~       ~        #
#~~  ~~~   ~ ~ ~      ~ ~~ ~  ~  ~  ~  #
#     ~~  ~  ~ ~ ~~~       H    ~  #~  #
#  O~  ~  #  ~~~ ~      ~ ~~  ~  ~ ~~  #
#       ~ ~H~~   ~~ ~ #        ~~   ~  #
# ~~         ~ ~~~  ~~   ~~~~      ~  ~#
#~  ~    ~~~  ~   ~        ~   ~ ~~  ~~#
#     ~      # ~ ~~  ~~~   ~ ~ ~ #    ~#
#~ ~ ~~  ~  ~   H     ~~  ~~ ~ ~ ~~~   #
#       ~   ~   ~   ~  ~     ~~~ ~     #
# ~~  ~  ~ ~~   ~       ~ ~ ~     ~    #
#      ~~   ~   ~  ~         ~      ~~ #
#~ ~     #    ~~~~  ~    ~~~H   # ~    #
#  ~   ~ ~   ~        ~          ~~  ~ #
#  ~   ~     #~  ~   ~~  ~  ~         ~#
# ~~ ~ ~  ~~                ~   ~      #
#    ~~~        ~ ~~  ~  ~  ~   ~      #
# ~ ~     ~            ~~   ~   ~  ~   #
########################################
RRRUWWWRRRURWWWWRDRRWWRDWWWWD

Output

8

Map provided by me, moves and output by @bobbel, corroborated by myself and @Allbeert.

Winning Criteria

I think this is golfable, so I'll go with code golf rules unless people complain.

Extra Credit

Playable Unicode implementation with the double-wide characters to resemble the image!

HostileFork says dont trust SE

Posted 2014-04-09T07:27:10.000

Reputation: 2 292

Do diagonal movements jump over antidiagonal lines of walls? Given that a beast makes a move every turn, how does it break distance ties between two horizontal moves or two vertical moves? Does it move towards where the player was at the start of the turn, or after the player's movement? When you say "train of movable walls", does that mean that the player can push any number of movable walls in a line provided that there's a space or a beast on the other end? – Peter Taylor – 2014-04-09T08:59:57.973

@PeterTaylor Yes you can push any number of walls as long as it's a space or Beast on the other end. Though I had to watch the video again to make sure they could squeeze between walls, and they can. :-) Clarified. The distance calculation is "as the crow flies" and they decide their move on the position at the beginning of the turn. – HostileFork says dont trust SE – 2014-04-09T09:10:02.520

The point of the question about tie-breaking was that if you have O #H then the beast can't move towards the player so has to move either up or down, and the symmetry needs breaking. – Peter Taylor – 2014-04-09T09:30:42.583

@PeterTaylor Right... I thought that was clarified by the sample data and the "horizontal favoritism => death" vs "horizontal favoritism => win"... by the rule A Beast's choice of move among its options will be the one that minimizes distance from the player, favoring a horizontal move over a vertical one if both are equal. Er... or not? – HostileFork says dont trust SE – 2014-04-09T09:59:45.267

You've given the tie-breaker between a horizontal move and a vertical move. What is the tie-breaker between "move left" and "move right"? What is the tie-breaker between "move up" and "move down"? What is the tie-breaker between "move up-left" and "move up-right"? Etc. – Peter Taylor – 2014-04-09T10:33:07.287

@PeterTaylor Ah, it got more complicated with the diagonal moves, but yes. :-) Okay, a preference matrix added, but suggestions welcome if that's not a good one. – HostileFork says dont trust SE – 2014-04-09T10:52:18.217

Another question: what, if a Beast is directly to the right of the player, and the player moves one up? Should the Beast just move one to the left, because the Beast was calculating with the players start position of this turn? Or should the Beast move left-up? (question according to: *then the beasts are given an ordering based on their initial map position*) – bobbel – 2014-04-09T11:52:37.373

2

If I'm understanding correctly, the second example is wrong, because http://pastebin.com/raw.php?i=CqPJPjTR.

– Doorknob – 2014-04-09T12:25:44.407

@Doorknob: actually the player goes first. So the player moves down first, then the beast chooses it's move, which is to move left and eat the hapless hero. Hmm in that case the third example would be wrong ... Also in the reaper example it should only require three waits to get eaten I think – Claudiu – 2014-04-09T14:08:48.987

@Claudiu: the reaper example is in fact wrong... it's only 3 times W (for the beast: L, L-U, U). But the Win example is correct, since the player moves first! So before the beast can do it's second move, the player gooifies the beast! (http://pastebin.com/raw.php?i=47A8Hre7)

– bobbel – 2014-04-09T14:34:48.410

@bobbel: Why would the beast move left on its first move? Instead it would move up since that would bring it closer (sqrt 2 distance instead of 2 distance) – Claudiu – 2014-04-09T14:35:28.620

@Claudiu: because, like Doorknob also explained, the beast will decide it's next step according to the players initial position of the current turn. This is also, what I guessed that OP meant. – bobbel – 2014-04-09T14:39:18.220

@bobbel: Oh yes, I missed that, my mistake. – Claudiu – 2014-04-09T14:46:47.090

@Claudiu Yes, the beasts moving diagonal clarification changed the example... Just 3 waits! Tx, fixed. – HostileFork says dont trust SE – 2014-04-09T15:23:02.343

@bobbel Ah yes, sorry, editing on phone. That'd be correct. Changed to down-wait as better examples not feasible to type :) – HostileFork says dont trust SE – 2014-04-09T15:37:54.437

1

@Dr.Rebmu: generally I like your task very much, but there are many questions to ask for. Thanks for clarifying! So, next: what about this Two-Beast situation: http://pastebin.com/raw.php?i=FENVAkCH Is my assumption correct?

– bobbel – 2014-04-09T15:44:40.863

1

Another question: What if you move a train of walls into a beast that isn't 'pinned down'? http://pastebin.com/raw.php?i=isN4L6pJ

– Claudiu – 2014-04-09T16:01:42.703

@Claudiu Ahh...you're straining my memory, and the video can't really help with that one since there's no visual way to see the keystrokes. But I don't think you can push beasts, just crush them. Let's assume they are walls in that case...clarified. – HostileFork says dont trust SE – 2014-04-09T16:21:52.077

3@bobbel Man, writing questions is harder than solving them! :-) I say given the Beasts propensity for not staying still, they will take their next best move if available instead of foregoing their move that turn, if a higher priority Beast took their ideal spot. Clarified. – HostileFork says dont trust SE – 2014-04-09T16:26:33.510

Don't worry, to golf this puzzle is a big challenge too. Or who can beat currently about 2,050 bytes? :D By the way: the output of the last scenario is also: aHHHH!\n0 – bobbel – 2014-04-10T14:40:55.820

should 'We all know H is the most merciless letter of the alphabet' not be 'We all know ├┤ is the most merciless letter of the alphabet'? – kitcar2000 – 2014-05-03T12:41:43.527

Answers

3

Perl 6: 741 characters, 758 bytes

The golfed version is at the bottom, since it's basically linenoise. Above it is my pre-golfed version. Both are interactive (they'll read as many commands from the input file as they can and then move on to using STDIN to get commands). They try to use the original characters and colors.

Usage is like perl6 beast.p6 beast-input:

use Term::ANSIColor;
class BeastGame {
    enum BeastParts <None Player Beast M-Wall S-Wall>;

    has @.board;
    has Int $.turn = 0;
    has Int $.score = 0;

    method indices (\matcher) {
        @.board.pairs.map: {
            .key*i X+ .value[].pairs.map: {
                .key if .value ~~ matcher
            }
        }
    }
    multi postcircumfix:<[ ]> (BeastGame \SELF, Complex \c) is rw { SELF.board[c.im][c.re] }

    has Complex $!player;
    method player { $!player = $.indices(Player)[0] }
    method Bool { so $.indices(Player) & $.indices(Beast) }

    method new (@lines) {
        my @board = @lines.map:
            {[ %(' ',<O H ~ #> Z=> None, Player, Beast, M-Wall, S-Wall){ .comb } ]}

        self.bless: :@board
    }
    method gist {
        state @symbol-map = map {colored .key, .value~' on_black'},
            ('  ',<◄► ├┤ ▒▒ ██> Z=> <default cyan red green yellow>);

        @.board.map({ @symbol-map[@$_].join }).join("\n")
    }

    method step ($d) {
        my $direction = %(:W(0), :L(-1+0i), :R(1+0i), :U(-1i), :D(1i)){$d};
        $direction // return self;
        self.move($.player,$direction);

        if ++$!turn %% 2 {
            for $.indices(Beast).eager -> $c {
                for (-1-1i,-1+0i,-1i,1-1i,1+0i,-1+1i,1+1i,1i,0i)\
                        .sort({abs $c + $^d - $!player})
                {
                    last if self.move($c, $_).defined;
                }
            }
        }

        self;
    }
    method move ($cur, $by) {
        return $cur if $by == 0;

        my $to = $cur + $by;
        my &cur-is  = { self[$cur] ~~ $^o }
        my &next-is = { self[$to]  ~~ $^o }
        return if cur-is S-Wall;
        (self[$to], self[$cur]) = (self[$cur], None)
            if next-is None
            # Move wall
            or cur-is Player | M-Wall and next-is M-Wall and self.move($to, $by)
            # Kill Player
            or cur-is Beast  and next-is Player
            # Squish Beast
            or cur-is M-Wall and next-is Beast  and self[$to+$by] ~~ M-Wall|S-Wall and $!score += 2
    }
}
my $width = get.words[1];
my $game  = BeastGame.new(lines[^$width]);
my @commands = '',lines.comb,{$*IN.get.comb}...*;

while $game {
    $game.step: @commands.shift;
    print "\e[2J";
    print "\e[H";
    say $game;
}

say "aHHHH!" unless $game.player;
say $game.score;

The golfed version:

my ($u,$s,$m)=0,0;my@b=lines[^get.words[1]].map:{[%(' ',<O H ~ #>Z=>^5){.comb}]}
my@a='',lines.comb,{$*IN.get.comb}...*;sub g(\c)is rw {@b[c.im][c.re]}
my&n=->\o{@b.kv.map:{$^k*i X+$^v[].kv.map:{$^l if $^w==o}}}
my&p={$m=n(1)[0]}
my&M=->$c,$b{my$t=$c+$b;my&c={$^o==g $c}
my&x={$^o==g $t}
c(4)??0!!$b??(($c,$t)».&g=(0,g $c)
if x(0)||c(1|3)&&x(3)&&M($t,$b)||c(2)&&x(1)||c(3)&&x(2)&&2 <g($t+$b)&&($s+=2))!!1}
while n(1)&n(2) {for 1
{M p,%(:W(0),:L(-1),:R(1),:U(-1i),:D(1i)){@a.shift}//last;if $u++%2
{for n(2).eager ->$c{last if M $c,$_
for(-1-1i,-1+0i,-1i,1-1i,1+0i,-1+1i,1+1i,1i,0i).sort({abs $c+$_-$m})}}}
say "\e[2J\e[H",join "\n",map {[~]
(map {"\e[$^v;40m$^k\e[0m"},'  ',<39 ◄► 36 ├┤ 31 ▒▒ 32 ██ 33>)[@$_]},@b}
say "aHHHH!" if !p;say $s;

Happy Easter!

Mouq

Posted 2014-04-09T07:27:10.000

Reputation: 906

It's code golf rules, so given that, your solution wins...even if I don't myself like Perl very much. ;-) Good work with the console and color! – HostileFork says dont trust SE – 2014-04-30T01:35:34.073

14

Java, 1,843

My first try of solving this puzzle with Java. I know, that there are a lot of improvements to make it shorter. But in the end it works for now.

To try it, you have to create a class C and paste the code. args[0] (strictly speaking a[0]) is for input. The print method of the map is not included since it's not necessary for the puzzle output.

class C{static char                    [][]C;static int A=
0,B=0,D=0,E=0,F=0,G                    = 0 ; public static
void main(String[]a                    ){String []b= a[0].
split("\n");int c =                    Byte. decode(b [0].
split(" ")[1]); G=a                    [ 0 ] . replaceAll(
"[^H]","").length()                    ; String d = b [ b.
length - 1 ] ;C=new                    char[c][];for(int e
=1;e<b.length-1;e++                    ) C [ e - 1 ]=b[e].
toCharArray ( ) ; f                    ();boolean X= 0> 1;
for ( char  g : d .                    toCharArray ( ) ) {
switch(g){case 'U':                    h(0,-1);break; case
'D':h(0, 1); break;                    case 'L':h( -1, 0);
break;case'R':h(1,0                    );}if(X)i();X=!X;f(
);}System.out.print                    (D);}static void f(
){for(int a= 0;a<C.                    length;a++)for( int
b=0;b<C[a].length;b                    ++)if(C[a][b]=='O')
{A=b;B= a;}}static void h(int x,int y){E =x;F =y;switch(C[
B +y][A +x]){case 'H':g();break;case ' ':j(A,B);break;case
'~':k();}}static void i(){if(G<1){return;}int[][]l=new int
[G][];int m=0;for(int r=0;r<C.length;r++){for(int c=0;c<C[
r].length; c++){if(C[r][c]=='H'){l[m++]=new int[]{c,r};}}}
for(int[]n:l){o(n[0],n[1]);}} static void o(int a, int b){
int[]c=d (a,b);E=c[0];F =c[1];if(E !=0||F !=0){ j(a,b);} }
static int[]d(int a,int b){int[][]d={{1,3,4},{2,0,5},{6,8,
7},};int[]e=new int[]{0,0};double f=999;for(int r=-1;r<2;r
++){for(int c=-1;c<2;c++){if(C[b+r][a+c]==' '||C[b+r][a+c]
=='O'){int g=a+c-A;                    int h=b+r-B; double
i=Math.sqrt(g*g+h*h                    );if(i<f){e=new int
[]{ c,r};f =i;}else                    if(i==f){if(d[r+1][
c+1]<d[e[1]+1][e[0]                    +1]){e=new int[]{c,
r};}}} }}return e;}                    static void k(){if(
p(E,F,false)){q(E,F                    );} }static void q(
int x,int y){switch                    (C[B+y][A+x]){ case
'~':q(x+E,y+F);case                    'H':case ' ':j(A+x-
E,B+y- F);}} static                    boolean p(int x,int
y,boolean h){switch                    (C[B+y][ A+x]){case
' ':return !h; case                    '~':return h?h:p(x+
E,y +F, false);case                    'H':return h?!h:p(x
+E , y+ F, true) ;}                    return h&&C[B+y][A+
x] == '#' ; }static                    void j(int a,int b)
{char c=C[b][a];if(                    C[b+F][a+E]=='O'){g
();}else if(C[b+F][                    a+E]=='H'){D+=2;G--
;c=C[b][a];C[b][a]=                    ' ';}else{C[b][a]=C
[b+F][a+E];}C[b+F][                    a+E]=c;}static void
g () { System .out.                    print("aHHHH!\n"+D)
;     System      .                    exit  ( 0  ) ;  } }

To run it, try for example:

root@host:/cygdrive/c/workspace/project/bin> java C "5 5
> #####
> #O  #
> # ~ #
> #  H#
> #####
> WWDW"
aHHHH!
0
root@host:/cygdrive/c/workspace/project/bin>

Output of the last big scenario one turn before a beast eats the player:

████████████████████████████████████████████████████████████████████████████████
██▓▓            ▓▓  ▓▓▓▓    ▓▓    ▓▓  ▓▓▓▓      ▓▓  ▓▓▓▓        ▓▓  ▓▓  ▓▓▓▓  ██
██▓▓▓▓  ▓▓                    ▓▓▓▓      ▓▓      ▓▓  ▓▓▓▓                  ▓▓  ██
██▓▓██  ▓▓▓▓      ▓▓▓▓▓▓▓▓            ▓▓    ▓▓▓▓▓▓▓▓    ▓▓        ▓▓▓▓▓▓    ▓▓██
██  ▓▓                ▓▓      ▓▓  ▓▓▓▓  ██▓▓▓▓              ▓▓                ██
██▓▓▓▓    ▓▓▓▓▓▓      ▓▓  ▓▓  ▓▓            ▓▓  ▓▓▓▓  ▓▓    ▓▓    ▓▓    ▓▓    ██
██          ▓▓▓▓    ▓▓    ▓▓  ▓▓  ▓▓▓▓▓▓                        ▓▓    ██▓▓    ██
██          ▓▓▓▓    ██    ▓▓▓▓▓▓  ▓▓            ▓▓  ▓▓▓▓    ▓▓    ▓▓  ▓▓▓▓    ██
██              ▓▓  ▓▓  ▓▓▓▓      ▓▓▓▓  ▓▓  ██                ▓▓▓▓      ▓▓    ██
██  ▓▓▓▓                  ▓▓  ▓▓▓▓▓▓    ▓▓▓▓  ├┤  ▓▓▓▓▓▓▓▓            ▓▓    ▓▓██
██▓▓    ▓▓    ├┤◄►▓▓▓▓▓▓├┤  ▓▓      ▓▓                ▓▓      ▓▓  ▓▓▓▓    ▓▓▓▓██
██          ▓▓            ██  ▓▓  ▓▓▓▓    ▓▓▓▓▓▓      ▓▓  ▓▓  ▓▓  ██        ▓▓██
██▓▓  ▓▓  ▓▓▓▓    ▓▓    ▓▓                  ▓▓▓▓    ▓▓▓▓  ▓▓  ▓▓  ▓▓▓▓▓▓      ██
██              ▓▓      ▓▓      ▓▓      ▓▓    ▓▓├┤        ▓▓▓▓▓▓  ▓▓          ██
██  ▓▓▓▓    ▓▓    ▓▓  ▓▓▓▓      ▓▓              ▓▓  ▓▓  ▓▓          ▓▓        ██
██            ▓▓▓▓      ▓▓      ▓▓    ▓▓                  ▓▓            ▓▓▓▓  ██
██▓▓  ▓▓          ██        ▓▓▓▓▓▓▓▓    ▓▓        ▓▓▓▓▓▓        ██  ▓▓        ██
██    ▓▓      ▓▓  ▓▓      ▓▓                ▓▓                    ▓▓▓▓    ▓▓  ██
██    ▓▓      ▓▓          ██▓▓    ▓▓      ▓▓▓▓    ▓▓    ▓▓                  ▓▓██
██  ▓▓▓▓  ▓▓  ▓▓    ▓▓▓▓                                ▓▓      ▓▓            ██
██        ▓▓▓▓▓▓                ▓▓  ▓▓▓▓    ▓▓    ▓▓    ▓▓      ▓▓            ██
██  ▓▓  ▓▓          ▓▓                        ▓▓▓▓      ▓▓      ▓▓    ▓▓      ██
████████████████████████████████████████████████████████████████████████████████

Without silly line spaces: http://pastebin.com/raw.php?i=QhpxKcCT

So the players way is ending after the moves RRDDDRRRWW, because on the last Wait, the beast to the left will go to the right to eat the player.


Another example of the original big map but different moves:

http://pastebin.com/raw.php?i=nBWjC3PZ

See this animation: http://youtu.be/0DIhEhjWd6s


And the last example with original map and different moves (according to the new beast movement rules):

http://pastebin.com/raw.php?i=NNmgzx7U

See on youtube: http://youtu.be/jXPzL88TU2A

bobbel

Posted 2014-04-09T07:27:10.000

Reputation: 1 037

1HHHa! :-) Very cool. So long as you've gotten it, care to play a few games and give more test case data on that map? – HostileFork says dont trust SE – 2014-04-11T01:43:26.370

I've added a new scenario with original map and different moves. But you can't really follow the steps, because I didn't want to paste all 75 steps to pastebin :) – bobbel – 2014-04-11T08:50:49.117

So, I added a video to see the result as an animation! – bobbel – 2014-04-11T11:29:22.197

Good video...though it seems to show the beasts move too quickly to be any fun! Should we change the rule so they move every other turn instead of every turn? – HostileFork says dont trust SE – 2014-04-11T17:57:07.210

I don't mind. About ten bytes more for me! But I totally agree. It's hard to win like it is now :) – bobbel – 2014-04-11T18:15:39.907

Okay, I slowed them down in the spec. They start on the second turn and move on alternating turns after that... oops, now I have to fix the examples :-) – HostileFork says dont trust SE – 2014-04-11T18:54:26.083

Great! Just one little thing: the win example should be WWRD instead of WRD, because the beast should decide it's next step from each initial position of the second turn of the player, shouldn't it? So the beast will move to the left instead of moving up! – bobbel – 2014-04-11T19:18:45.610

The player's "initial position" on the second turn will still be in the upper left, right? So the beast's decision is based on where the player was before the R is executed on the same turn it moves on. – HostileFork says dont trust SE – 2014-04-11T19:31:29.583

Ah.... yes.... you're right! Unbelievable how this makes me crazy :D – bobbel – 2014-04-11T19:39:15.427

Next edit to come up to the new beast movement rules. Also the extra credit change is done ;) Edit: oh, playable! Okay, I have to go back to my basement ;D – bobbel – 2014-04-11T20:40:34.297

I love the shape -- so great! – ProgrammerDan – 2014-04-12T01:14:37.287

Big points here on creativity, the video, and your help in making the question better! But I did say "code golf rules", so the "accepted" answer needs to be golfed. :-) Nevertheless, I've opened a bounty to award you extra points for being awesome... have to wait 24 hours though... – HostileFork says dont trust SE – 2014-04-30T01:36:58.050

@Dr.Rebmu: Thank you very much for the bounty!! It was a pleasure for me! :) It's really nice that you dug out this cool old game!! I'm sure I would have forgotten this game forever :) – bobbel – 2014-05-03T16:42:20.527

@bobbel I'm very happy you got the bounty, you deserve it :) – Mouq – 2014-05-04T16:33:06.847

5

C - 1004 984 917

Ahh, the beauty of C. Following the spirit of the other answer, I tried to format mine as well :)

I imagine there are still some improvements here and there, but this was really fun to write and golf. The character count includes all necessary spaces and new lines.

#define M(y,x,c) {t[y][x]=32;t[p][q]=c;y=p;x=q;}
   #define E {printf("aHHHH!\n%d",Z);exit(0);}
    #define A sqrt(pow(X-Q,2)+pow(Y-P,2))*30
           #define L (char)(m[s]>>8)
            #define G (char)(m[s])
             #define B(b) if(T==b)
              #define J M(Y,X,79)
               #define T t[P][Q]

r,c,X,Y,H,i,j,k,Z,p,q,P,Q,u,v,s,w,m[99],b[8]={
-1,255,65280,65281,1,511,257,256},t[999][999],
x[99],y[99];main(){char N[99];m[85]=b[2];m[68]
=256;m[76]=255; m[82]=1; scanf("%d %d",&c,&r);
for(;P<r;P++)                    for(Q=0;Q<c&&
scanf("%c",&T                    );T-10&&T-13?
Q++:Q){B(79){                    Y=P;X=Q;}B(72
){y[H]=P ;x[H                    ++]=Q;}}scanf
("%s",N);for(                    ;i<strlen(N);
i++){s=N[i];P                    =p=Y+L;Q=q=X+
G;B(32)J B('~')                  {while(P+=L,Q
+=G,T=='~');B                    (72){u=P+L;v=
Q+G;if(t[u][v]                   ==35||t[u][v]
=='~'){Z+=2;T=                   '~';J}}B(32){
T='~';J}}else                    B(72)E if(r=!r)
for(j=0;j<H;j                    ++){P=y[j];Q=
x[j];if(T-72)continue;v=A;s=0;for(k=0;k<8;k++)
{P=y[j]+(char)(b[k]>>8);Q=x[j]+(char)(b[k]);u=
A;B(32)if((c=v-u+99)>s){s=c;q=Q;p=P;}B(79)E}if
(s)M(y[j],x[j],72)}}printf("%d",Z);}//////////

I tested this with all the sample cases and a few more of mine, and it seems to be working properly. If anyone finds any situation in which it doesn't answer properly, please let me know.

Input is from stdin, and output to stdout. There are no checks for incorrect input. And, it returns the score if the player gets eaten, or if the player is alive after all movements are executed (even if there are still H's around.

Ungolfed version:

#define M(y,x,c) {t[y][x]=32;t[p][q]=c;y=p;x=q;}
#define E {printf("aHHHH!\n%d",Z);exit(0);}
#define A sqrt(pow(X-Q,2)+pow(Y-P,2))*30
#define L (char)(m[s]>>8)
#define G (char)(m[s])
#define B(b) if(T==b)
#define J M(Y,X,79)
#define T t[P][Q]

r, c, X, Y, H, i, j, k, Z, p, q, P, Q, u, v, s, w, m[99], b[8] = { -1, 255,
        65280, 65281, 1, 511, 257, 256 }, t[999][999], x[99], y[99];
main() {
    char N[99];
    m[85] = b[2];
    m[68] = 256;
    m[76] = 255;
    m[82] = 1;
    scanf("%d %d", &c, &r);
    for (; P < r; P++)
        for (Q = 0; Q < c && scanf("%c", &T);T-10&&T-13?Q++:Q) {
            B(79) {
                Y=P;
                X=Q;
            }
            B(72) {
                y[H]=P;
                x[H++]=Q;
            }
        }

    scanf("%s", N);
    for (; i < strlen(N); i++) {
        s = N[i];
        P = p = Y + L;
        Q = q = X + G;
        B(32)
            J
        B('~') {
            while (P += L, Q += G, T=='~');
            B(72) {
                u=P+L;
                v=Q+G;
                if(t[u][v]==35||t[u][v]=='~') {
                    Z+=2;
                    T='~';
                    J
                }
            }
            B(32) {
                T='~';
                J
            }
        } else B(72)E
        if (r = !r)
            for (j = 0; j < H; j++) {
                P = y[j];
                Q = x[j];
                if (T-72)
                continue;

                v = A;
                s = 0;

                for (k = 0; k < 8; k++) {
                    P = y[j] + (char) (b[k] >> 8);
                    Q = x[j] + (char) (b[k]);
                    u = A;
                    B(32)
                        if ((c = v - u + 99) > s) {
                            s = c;
                            q = Q;
                            p = P;
                        }

                    B(79)
                        E
                }
                if (s)
                    M(y[j], x[j], 72)
            }
    }
    printf("%d", Z);
}

Allbeert

Posted 2014-04-09T07:27:10.000

Reputation: 489

Nice!! Though on @bobbel's input RRRUWWWRRRURWWWWRDRRWWRDWWWWD on the big map, you get 6 while he gets 8. He made a video, you could perhaps print each step and look for any anomaly...

– HostileFork says dont trust SE – 2014-04-11T21:35:08.347

(noticing of course that I changed the rule to make beasts move every-other-turn when I saw how unplayable the beasts-move-every-turn was...!) – HostileFork says dont trust SE – 2014-04-11T21:42:25.427

To be honest: I'm not sure, if my solution works 100% properly, too. But it looks like to me :) – bobbel – 2014-04-11T21:46:12.010

@Dr.Rebmu I realized you edited the question around the same time I posted mine. So I just did a quick hack that seemingly worked. I'll re-check it this weekend and update it. I'll also post a "nice" version so that any errors could be easier to spot by other people as well :) – Allbeert – 2014-04-12T02:48:50.647

FWIW I solved this today in Rebol and am getting @bobbel's answer of 8 as well. – HostileFork says dont trust SE – 2014-04-12T22:40:10.587

@Dr.Rebmu Updated and fixed! :). I actually had two problems. My beasts were moving taking into account the position of the player after it had moved, and the calculation of the distance was just plain wrong! It's giving the proper answer of 8 on the large map, and I checked step by step and it follows the same path as Bobbel's answer – Allbeert – 2014-04-13T16:24:15.763