Games-LMSolve

 view release on metacpan or  search on metacpan

lib/Games/LMSolve/Plank/Base.pm  view on Meta::CPAN

            'type'     => "array(start_end(xy(integer)))",
            'required' => 1,
        },
        'layout' => { 'type' => "layout", 'required' => 1, },
    };

    my $input_obj = Games::LMSolve::Input->new();

    my $input_fields = $input_obj->input_board( $filename, $spec );
    my ( $width, $height ) =
        @{ $input_fields->{'dims'}->{'value'} }{ 'x', 'y' };
    my ( $goal_x, $goal_y );

    if ( scalar( @{ $input_fields->{'layout'}->{'value'} } ) < $height )
    {
        die
"Incorrect number of lines in board layout (does not match dimensions";
    }
    my @board;
    my $lines = $input_fields->{'layout'}->{'value'};
    for ( my $y = 0 ; $y < $height ; $y++ )
    {
        my $l = [];
        if ( length( $lines->[$y] ) < $width )
        {
            die "Too few characters in board layout in line No. "
                . ( $input_fields->{'layout'}->{'line_num'} + $y + 1 );
        }
        my $x = 0;
        foreach my $c ( split( //, $lines->[$y] ) )
        {
            push @$l, ( $c ne " " );
            if ( $c eq "G" )
            {
                if ( defined($goal_x) )
                {
                    die "Goal was defined twice!";
                }
                ( $goal_x, $goal_y ) = ( $x, $y );
            }
            $x++;
        }
        push @board, $l;
    }
    if ( !defined($goal_x) )
    {
        die "The Goal was not defined in the layout";
    }

    my $planks_in = $input_fields->{'planks'}->{'value'};

    my @planks;

    my $get_plank = sub {
        my $p = shift;

        my ( $start_x, $start_y ) =
            ( $p->{'start'}->{'x'}, $p->{'start'}->{'y'} );
        my ( $end_x, $end_y ) = ( $p->{'end'}->{'x'}, $p->{'end'}->{'y'} );

        my $check_endpoints = sub {
            if ( !$board[$start_y]->[$start_x] )
            {
                die "Plank cannot be placed at point ($start_x,$start_y)!";
            }
            if ( !$board[$end_y]->[$end_x] )
            {
                die "Plank cannot be placed at point ($end_x,$end_y)!";
            }
        };

        my $plank_str = "Plank ($start_x,$start_y) ==> ($end_x,$end_y)";

        if (   ( $start_x >= $width )
            || ( $end_x >= $width )
            || ( $start_y >= $height )
            || ( $end_y >= $height ) )
        {
            die "$plank_str is out of the boundaries of the board";
        }

        if ( $start_x == $end_x )
        {
            if ( $start_y == $end_y )
            {
                die "$plank_str has zero length!";
            }
            $check_endpoints->();
            if ( $start_y > $end_y )
            {
                ( $start_y, $end_y ) = ( $end_y, $start_y );
            }
            foreach my $y ( ( $start_y + 1 ) .. ( $end_y - 1 ) )
            {
                if ( $board[$y]->[$start_x] )
                {
                    die "$plank_str crosses logs!";
                }
            }
            return {
                'len'   => ( $end_y - $start_y ),
                'start' => { 'x' => $start_x, 'y' => $start_y },
                'dir'   => "S"
            };
        }
        elsif ( $start_y == $end_y )
        {
            $check_endpoints->();
            if ( $start_x > $end_x )
            {
                ( $start_x, $end_x ) = ( $end_x, $start_x );
            }
            foreach my $x ( ( $start_x + 1 ) .. ( $end_x - 1 ) )
            {
                if ( $board[$start_y]->[$x] )
                {
                    die "$plank_str crosses logs!";
                }
            }
            return {
                'len'   => ( $end_x - $start_x ),
                'start' => { 'x' => $start_x, 'y' => $start_y },
                'dir'   => "E"
            };
        }
        elsif ( ( $end_x - $start_x ) == ( $end_y - $start_y ) )
        {
            $check_endpoints->();
            if ( $start_x > $end_x )
            {
                ( $start_x, $end_x ) = ( $end_x, $start_x );
                ( $start_y, $end_y ) = ( $end_y, $start_y );
            }
            foreach my $i ( 1 .. ( $end_x - $start_x - 1 ) )
            {
                if ( $board[ $start_y + $i ]->[ $start_x + $i ] )
                {
                    die "$plank_str crosses logs!";
                }
            }
            if ( !grep { $_ eq "SE" } @{ $self->{'dirs'} } )
            {
                die "$plank_str is not aligned horizontally or vertically.";
            }
            return {
                'len'   => ( $end_x - $start_x ),
                'start' => {
                    'x' => $start_x,
                    'y' => $start_y,
                },
                'dir' => "SE",
            };
        }
        else
        {
            die "$plank_str is not aligned horizontally or vertically.";
        }
    };

    foreach my $p (@$planks_in)
    {
        push @planks, $get_plank->($p);
    }

    $self->{'width'}      = $width;
    $self->{'height'}     = $height;
    $self->{'goal_x'}     = $goal_x;
    $self->{'goal_y'}     = $goal_y;
    $self->{'board'}      = \@board;
    $self->{'plank_lens'} = [ map { $_->{'len'} } @planks ];

    my $state = [
        0,
        (
            map {
                (
                    $_->{'start'}->{'x'},
                    $_->{'start'}->{'y'},
                    (
                          ( $_->{'dir'} eq "E" )  ? 0
                        : ( $_->{'dir'} eq "SE" ) ? 2
                        :                           1
                    )
                )
            } @planks
        )
    ];
    $self->_process_plank_data($state);



( run in 1.498 second using v1.01-cache-2.11-cpan-39bf76dae61 )