Here is a solution to the Rush Hour quiz using the Games::LMSolve module. It 
isn't golfized or anything, and was not too optimized - I just wanted to see 
if I can solve it using it.

Regards,

        Shlomi Fish

<<<
#!/usr/bin/perl -w
package RushHour;

use strict;

use base 'Games::LMSolve::Base';

sub input_board
{
    my $self = shift;
    my $packed = join("",<STDIN>);
    chomp($packed);
    return $self->unpack_state($packed); 
}

sub pack_state
{
    my $self = shift;
    my $unpacked = shift;
    return join("\n", map { join("", @$_) } @$unpacked);
}

sub unpack_state
{
    my $self = shift;
    my $packed = shift;
    my @lines = split(/\n/,$packed);
    chomp(@lines);
    return [map { [ split(//, $_) ] } @lines];
}

sub display_state
{
    my $self = shift;
    my $packed = shift;
    return $packed;
}

sub check_if_final_state
{
    my $self = shift;
    my $state = shift;
    foreach my $l (@$state)
    {
        if ($l->[-1] =~ /^[a-zA-Z]$/)
        {
            return 1;
        }
    }
    return 0;   
}

sub enumerate_moves
{
    my $self = shift;
    my $state = shift;
    my @moves;
    my %encountered_cars = ();

    my ($x,$y);
    for($y=0;$y<@$state;$y++)
    {
        my $line = $state->[$y];
        for($x=0;$x<@$line;$x++)
        {
            my $char = $line->[$x];
            if (exists($encountered_cars{$char}))
            {
                next;
            }
            $encountered_cars{$char} = 1;
            if ($char =~ /^[a-z]$/)
            {
                my $x_delta = 1;
                while (($x-$x_delta >= 0) && $line->[$x-$x_delta] eq " ")
                {
                    push @moves, +{ 'c' => $char, 'i' => (-$x_delta)};
                    $x_delta++;
                }
                $x_delta = 1;
                my $x_end = 1;
                while ($line->[$x+$x_end] eq $char)
                {
                    $x_end++;
                }
                $x_end--;
                $x_delta = 1;
                while (($x+$x_end+$x_delta < @$line) && 
                       ($line->[$x+$x_end+$x_delta] eq " "))
                {
                    push @moves, +{ 'c' => $char, 'i' => $x_delta};
                    $x_delta++;
                }
            }
            elsif ($char =~ /^[A-Z]$/)
            {
                my $y_delta = 1;
                while (($y-$y_delta >= 0) && $state->[$y-$y_delta]->[$x] eq " 
")
                {
                    push @moves, +{ 'c' => $char, 'i' => (-$y_delta)};
                    $y_delta++;
                }
                $y_delta = 1;
                my $y_end = 1;
                while ($state->[$y+$y_end]->[$x] eq $char)
                {
                    $y_end++;
                }
                $y_end--;
                $y_delta = 1;
                while (($y+$y_end+$y_delta < @$state) && 
                       ($state->[$y+$y_end+$y_delta]->[$x] eq " "))
                {
                    push @moves, +{ 'c' => $char, 'i' => $y_delta};
                    $y_delta++;
                }                
            }
        }
    }
    return (@moves);
}

sub perform_move
{
    my $self = shift;
    my $state = shift;
    my $move = shift;
    my $state_copy = $self->unpack_state($self->pack_state($state));
    my $c = $move->{c};
    my $increment = $move->{i};
    my ($len);
    my ($x, $y);
    my $horiz = (($c =~ /^[a-z]$/) ? 1 : 0);
    Y_LOOP: for($y=0;$y<@$state_copy;$y++)
    {
        my $line = $state_copy->[$y];
        for($x=0;$x<@$line;$x++)
        {
            if ($line->[$x] eq $c)
            {
                if ($horiz)
                {
                    for($len=0;;$len++)
                    {
                        if ($line->[$x+$len] ne $c)
                        {
                            last;
                        }
                    }
                    my $x_iter;
                    for($x_iter = 0;$x_iter<$len;$x_iter++)
                    {
                        $line->[$x+$x_iter] = " ";
                    }
                    for($x_iter = 0;$x_iter<$len;$x_iter++)
                    {
                        $line->[$x+$x_iter+$increment] = $c;
                    }
                }
                else
                {
                    for($len=0;;$len++)
                    {
                        if ($state_copy->[$y+$len]->[$x] ne $c)
                        {
                            last;
                        }
                    }
                    my $y_iter;
                    for($y_iter = 0;$y_iter<$len;$y_iter++)
                    {
                        $state_copy->[$y+$y_iter]->[$x] = " ";
                    }
                    for($y_iter = 0;$y_iter<$len;$y_iter++)
                    {
                        $state_copy->[$y+$y_iter+$increment]->[$x] = $c;
                    }
                }
                last Y_LOOP;
            }
        }
    }
    return $state_copy;
}

package main;
use strict;

my $self = RushHour->new();
my ($verdict, $final_state) = $self->solve_board("-");
if ($verdict eq "unsolved")
{
    exit;
}
my $key = $final_state;
my $state_collection = $self->{'state_collection'};
my $s = $state_collection->{$key};
my @moves = ();
my @states = ($key);

while ($s->{'p'})
{
    push @moves, $s->{'m'}->{c} . " " . $s->{m}->{i};
    $key = $s->{'p'};
    $s = $state_collection->{$key};
    push @states, $key;
}
@moves = reverse(@moves);
print map { "$_\n" } @moves;
>>>
-- 

---------------------------------------------------------------------
Shlomi Fish      [EMAIL PROTECTED]
Homepage:        http://shlomif.il.eu.org/

Knuth is not God! It took him two days to build the Roman Empire.

Reply via email to