view release on metacpan or search on metacpan
bin/optimize-game-ai-multi-tasking view on Meta::CPAN
#!/usr/bin/perl
# This is for Pod::Weaver:
# PODNAME: optimize-game-ai-multi-tasking
use strict;
use warnings;
use Carp qw/ confess /;
$SIG{__WARN__} = sub {
confess( $_[0] );
};
$SIG{__DIE__} = sub {
confess( $_[0] );
};
use AI::Pathfinding::OptimizeMultiple::App::CmdLine;
my $iface =
AI::Pathfinding::OptimizeMultiple::App::CmdLine->new(
{ argv => [@ARGV], } );
$iface->run();
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
use AI::Pathfinding::OptimizeMultiple::Scan ();
use AI::Pathfinding::OptimizeMultiple::ScanRun ();
use AI::Pathfinding::OptimizeMultiple::SimulationResults ();
use MooX qw/late/;
use PDL;
use Scalar::Util qw/ blessed /;
has chosen_scans => ( isa => 'ArrayRef', is => 'rw' );
has _iter_idx => ( isa => 'Int', is => 'rw', default => sub { 0; }, );
has _num_boards => ( isa => 'Int', is => 'ro', init_arg => 'num_boards', );
has _orig_scans_data => ( isa => 'PDL', is => 'rw' );
has _optimize_for => ( isa => 'Str', is => 'ro', init_arg => 'optimize_for', );
has _scans_data => ( isa => 'PDL', is => 'rw' );
has _selected_scans =>
( isa => 'ArrayRef', is => 'ro', init_arg => 'selected_scans', );
has _status => ( isa => 'Str', is => 'rw' );
has _quotas => ( isa => 'ArrayRef[Int]', is => 'ro', init_arg => 'quotas' );
has _total_boards_solved => ( isa => 'Int', is => 'rw' );
has _total_iters => ( is => 'rw' );
has _trace_cb =>
( isa => 'Maybe[CodeRef]', is => 'ro', init_arg => 'trace_cb' );
has _scans_meta_data => ( isa => 'ArrayRef', is => 'ro', init_arg => 'scans' );
has _scans_iters_pdls =>
( isa => 'HashRef', is => 'rw', init_arg => 'scans_iters_pdls' );
has _stats_factors => (
isa => 'HashRef',
is => 'ro',
init_arg => 'stats_factors',
default => sub { return +{}; },
);
sub BUILD
{
my $self = shift;
my $args = shift;
my $scans_data = PDL::cat(
map {
my $id = $_->id();
my $pdl = $self->_scans_iters_pdls()->{$id};
my $factor = $self->_stats_factors->{$id};
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$self->_orig_scans_data($scans_data);
$self->_scans_data( $self->_orig_scans_data()->copy() );
return 0;
}
my $BOARDS_DIM = 0;
my $SCANS_DIM = 1;
my $STATISTICS_DIM = 2;
sub _next_iter_idx
{
my $self = shift;
my $ret = $self->_iter_idx();
$self->_iter_idx( $ret + 1 );
return $ret;
}
sub _get_next_quota
{
my $self = shift;
my $iter = $self->_next_iter_idx();
if ( ref( $self->_quotas() ) eq "ARRAY" )
{
return $self->_quotas()->[$iter];
}
else
{
return $self->_quotas()->($iter);
}
}
sub _calc_get_iter_state_param_method
{
my $self = shift;
my $optimize_for = $self->_optimize_for();
my %resolve = (
len => "_get_iter_state_params_len",
minmax_len => "_get_iter_state_params_minmax_len",
speed => "_get_iter_state_params_speed",
);
return $resolve{$optimize_for};
}
sub _get_iter_state_params
{
my $self = shift;
my $method = $self->_calc_get_iter_state_param_method();
return $self->$method();
}
sub _my_sum_over
{
my $pdl = shift;
return $pdl->sumover()->slice(":,(0)");
}
sub _my_xchg_sum_over
{
my $pdl = shift;
return _my_sum_over( $pdl->xchg( 0, 1 ) );
}
sub _get_iter_state_params_len
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$num_solved_in_iter = $solved_moves_counts->at($selected_scan_idx);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter,
scan_idx => $selected_scan_idx,
};
}
sub _get_iter_state_params_minmax_len
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$num_solved_in_iter = $solved_moves_counts->at($selected_scan_idx);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter,
scan_idx => $selected_scan_idx,
};
}
sub _get_iter_state_params_speed
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter->at(0),
scan_idx => $selected_scan_idx->at(0),
};
}
sub _get_selected_scan
{
my $self = shift;
my $iter_state =
AI::Pathfinding::OptimizeMultiple::IterState->new(
$self->_get_iter_state_params(), );
$iter_state->attach_to($self);
return $iter_state;
}
sub _inspect_quota
{
my $self = shift;
my $state = $self->_get_selected_scan();
$state->register_params();
$state->update_total_iters();
if ( $self->_total_boards_solved() == $self->_num_boards() )
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$self->_status("solved_all");
}
else
{
$state->update_idx_slice();
}
$state->detach();
}
sub calc_meta_scan
{
my $self = shift;
$self->chosen_scans( [] );
$self->_total_boards_solved(0);
$self->_total_iters(0);
$self->_status("iterating");
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
{
die $err;
}
$err->rethrow;
}
}
return;
}
sub _get_num_scans
{
my $self = shift;
return ( ( $self->_scans_data()->dims() )[$SCANS_DIM] );
}
sub _calc_chosen_scan
{
my ( $self, $selected_scan_idx, $iters_quota ) = @_;
return AI::Pathfinding::OptimizeMultiple::ScanRun->new(
{
iters => (
$iters_quota * (
$self->_stats_factors->{
( $self->_selected_scans->[$selected_scan_idx]->id() ),
} // 1
)
),
scan_idx => $selected_scan_idx,
}
);
}
sub calc_flares_meta_scan
{
my $self = shift;
$self->chosen_scans( [] );
$self->_total_boards_solved(0);
$self->_total_iters(0);
$self->_status("iterating");
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$flares_num_iters->sum()
)->sum()
);
print "Finished ", $loop_iter_num++,
" ; #Solved = $num_solved ; Iters = $total_num_iters ; Avg = $min_avg\n";
STDOUT->flush();
}
}
sub calc_board_iters
{
my $self = shift;
my $board = shift;
my $board_iters = 0;
my @info = PDL::list( $self->_orig_scans_data()->slice("$board,:") );
my @orig_info = @info;
foreach my $s ( @{ $self->chosen_scans() } )
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$board_iters += $s->iters();
}
}
return {
'per_scan_iters' => \@orig_info,
'board_iters' => $board_iters,
};
}
sub get_final_status
{
my $self = shift;
return $self->_status();
}
sub simulate_board
{
my ( $self, $board_idx, $args ) = @_;
if ( $board_idx !~ /\A[0-9]+\z/ )
{
die "Board index '$board_idx' is not numeric!";
}
$args ||= {};
my $chosen_scans = ( $args->{chosen_scans} || $self->chosen_scans );
my @info = PDL::list( $self->_orig_scans_data()->slice("$board_idx,:") );
my $board_iters = 0;
my @scan_runs;
my $status = "Unsolved";
my $add_new_scan_run = sub {
my $scan_run = shift;
push @scan_runs, $scan_run;
$board_iters += $scan_run->iters();
return;
};
SCANS_LOOP:
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
return AI::Pathfinding::OptimizeMultiple::SimulationResults->new(
{
status => $status,
scan_runs => \@scan_runs,
total_iters => $board_iters,
}
);
}
sub _trace
{
my ( $self, $args ) = @_;
if ( my $trace_callback = $self->_trace_cb() )
{
$trace_callback->($args);
}
return;
}
sub get_total_iters
{
my $self = shift;
return $self->_total_iters();
}
sub _add_to_total_iters
{
my $self = shift;
my $how_much = shift;
$self->_total_iters( $self->_total_iters() + $how_much );
return;
}
sub _add_to_total_boards_solved
{
my $self = shift;
my $how_much = shift;
$self->_total_boards_solved( $self->_total_boards_solved() + $how_much );
return;
}
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
# TODO : restore later.
# use MyInput;
use Carp ();
has argv => ( isa => 'ArrayRef[Str]', is => 'ro', required => 1, );
has _arbitrator => ( is => 'rw' );
has _add_horne_prune => ( isa => 'Bool', is => 'rw' );
has _chosen_scans => ( isa => 'ArrayRef', is => 'rw' );
has _should_exit_immediately =>
( isa => 'Bool', is => 'rw', default => sub { 0; }, );
has input_obj_class => ( isa => 'Str', is => 'rw' );
has _input_obj => ( is => 'rw' );
has _is_flares => ( is => 'rw', isa => 'Bool', default => sub { 0; }, );
has _num_boards => ( isa => 'Int', is => 'rw' );
has _offset_quotas => ( isa => 'Int', is => 'rw' );
has _optimize_for => ( isa => 'Str', is => 'rw' );
has _output_filename => ( isa => 'Str', is => 'rw' );
has _post_processor => (
isa => 'Maybe[AI::Pathfinding::OptimizeMultiple::PostProcessor]',
is => 'rw'
);
has _quotas_are_cb => ( isa => 'Bool', is => 'rw' );
has _quotas_expr => ( isa => 'Maybe[Str]', is => 'rw' );
has _should_rle_be_done => ( isa => 'Bool', is => 'rw' );
has _should_trace_be_done => ( isa => 'Bool', is => 'rw' );
has _simulate_to => ( isa => 'Maybe[Str]', is => 'rw' );
has _start_board => ( isa => 'Int', is => 'rw' );
has _stats_factors =>
( isa => 'HashRef', is => 'rw', default => sub { return +{}; }, );
my $_component_re = qr/[A-Za-z][A-Za-z0-9_]*/;
my $_module_re = qr/$_component_re(?:::$_component_re)*/;
sub BUILD
{
my $self = shift;
# Command line parameters
my $_start_board = 1;
my $num_boards = 32000;
my $output_filename = "-";
my $should_trace_be_done = 0;
my $should_rle_be_done = 1;
my $_quotas_expr = undef;
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
{
do_rle => $self->_should_rle_be_done(),
offset_quotas => $self->_offset_quotas(),
}
)
);
return;
}
sub _selected_scans
{
my $self = shift;
return $self->_input_obj->selected_scans();
}
sub _map_all_but_last
{
my $self = shift;
my ( $cb, $arr_ref ) = (@_);
return [
( map { $cb->($_) } @$arr_ref[ 0 .. $#$arr_ref - 1 ] ),
$arr_ref->[-1]
];
}
sub _get_quotas
{
my $self = shift;
if ( $self->_quotas_are_cb() )
{
return scalar( eval( $self->_quotas_expr() ) );
}
elsif ( defined( $self->_quotas_expr() ) )
{
return [ eval $self->_quotas_expr() ];
}
else
{
return $self->_get_default_quotas();
}
}
sub _get_default_quotas
{
return [ (350) x 5000 ];
}
sub _get_script_fh
{
my $self = shift;
return IO::File->new(
( $self->_output_filename() eq "-" )
? ">&STDOUT"
: ( $self->_output_filename(), "w" )
);
}
sub _get_script_terminator
{
return "\n\n\n";
}
sub _out_script
{
my $self = shift;
my $cmd_line_string = shift;
$self->_get_script_fh()
->print( $cmd_line_string,
$self->_get_script_terminator($cmd_line_string) );
}
sub _get_line_of_command
{
my $self = shift;
my $args_string = join( " ",
$self->_start_board(),
$self->_start_board() + $self->_num_boards() - 1, 1 );
return "freecell-solver-range-parallel-solve $args_string";
}
sub _line_ends_mapping
{
my $self = shift;
return $self->_map_all_but_last( sub { "$_[0] \\\n" }, shift );
}
sub _get_used_scans
{
my $self = shift;
return [ grep { $_->is_used() } @{ $self->_selected_scans() } ];
}
sub _get_scan_line
{
my ( $self, $line ) = @_;
return
$line->{'cmd_line'}
. " -step 500 "
. join( " ",
map { $_, $line->{'id'} }
( "--st-name", ( $self->_is_flares() ? "--flare-name" : () ) ) );
}
sub _get_lines_of_scan_defs
{
my $self = shift;
return [ map { $self->_get_scan_line($_) } @{ $self->_get_used_scans() } ];
}
sub _scan_def_line_mapping
{
my ( $self, $lines_aref ) = @_;
return $self->_map_all_but_last(
sub {
my ($line) = @_;
return $line . ' ' . ( $self->_is_flares() ? "-nf" : "-nst" );
},
[
map {
my $line = $_;
# Add the -sp r:tf flag to each scan if specified - it enhances
# performance, but timing the scans with it makes the total
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
if ( $self->_add_horne_prune() )
{
$line =~ s/( --st-name)/ -sp r:tf$1/;
}
$line;
} @$lines_aref
],
);
}
sub _calc_iter_quota
{
my $self = shift;
my $quota = shift;
if ( $self->_offset_quotas() )
{
return $quota + 1;
}
else
{
return $quota;
}
}
sub _map_scan_idx_to_id
{
my $self = shift;
my $index = shift;
return $self->_selected_scans()->[$index]->id();
}
sub _format_prelude_iter
{
my $self = shift;
my $iter = shift;
return
( $self->_is_flares() ? "Run:" : "" )
. $iter->iters() . '@'
. $self->_map_scan_idx_to_id( $iter->scan_idx() );
}
sub _get_line_of_prelude
{
my $self = shift;
return
+( $self->_is_flares() ? "--flares-plan" : "--prelude" ) . qq{ "}
. join( ",",
map { $self->_format_prelude_iter($_) } @{ $self->_chosen_scans() } )
. "\"";
}
sub _calc_script_lines
{
my $self = shift;
return [
$self->_get_line_of_command(),
@{
$self->_scan_def_line_mapping( $self->_get_lines_of_scan_defs() )
},
$self->_get_line_of_prelude()
];
}
sub _calc_script_text
{
my $self = shift;
return join( "",
@{ $self->_line_ends_mapping( $self->_calc_script_lines() ) } );
}
sub _write_script
{
my $self = shift;
$self->_out_script( $self->_calc_script_text() );
}
sub _calc_scans_iters_pdls
{
my $self = shift;
my $method = (
( $self->_optimize_for() =~ m{len} )
? "get_scans_lens_iters_pdls"
: "get_scans_iters_pdls"
);
return $self->_input_obj->$method();
}
sub _arbitrator_trace_cb
{
my $args = shift;
printf( "%s \@ %s (%s solved)\n",
@$args{qw(iters_quota selected_scan_idx total_boards_solved)} );
}
sub _init_arbitrator
{
my $self = shift;
return $self->_arbitrator(
AI::Pathfinding::OptimizeMultiple->new(
{
'scans' => [
map { +{ name => $_->id() } }
@{ $self->_input_obj->_suitable_scans_list() },
],
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
'num_boards' => $self->_num_boards(),
'scans_iters_pdls' => $self->_calc_scans_iters_pdls(),
'trace_cb' => \&_arbitrator_trace_cb,
'optimize_for' => $self->_optimize_for(),
'stats_factors' => $self->_stats_factors(),
}
)
);
}
sub _report_total_iters
{
my $self = shift;
if ( $self->_arbitrator()->get_final_status() eq "solved_all" )
{
print "Solved all!\n";
}
printf( "total_iters = %s\n", $self->_arbitrator()->get_total_iters() );
}
sub _arbitrator_process
{
my $self = shift;
$self->_arbitrator()->calc_meta_scan();
my $scans =
$self->_post_processor->process( $self->_arbitrator->chosen_scans() );
$self->_chosen_scans($scans);
}
sub _do_trace_for_board
{
my $self = shift;
my $board = shift;
my $results = $self->_arbitrator()->calc_board_iters($board);
print "\@info=" . join( ",", @{ $results->{per_scan_iters} } ) . "\n";
print +( $board + $self->_start_board() ) . ": "
. $results->{board_iters} . "\n";
}
sub _real_do_trace
{
my $self = shift;
foreach my $board ( 0 .. $self->_num_boards() - 1 )
{
$self->_do_trace_for_board($board);
}
}
sub _do_trace
{
my $self = shift;
# Analyze the results
if ( $self->_should_trace_be_done() )
{
$self->_real_do_trace();
}
}
sub _get_run_string
{
my $self = shift;
my $results = shift;
return join(
"",
map {
sprintf( '%i@%i,',
$_->iters(), $self->_map_scan_idx_to_id( $_->scan_idx() ) )
} @{ $self->_post_processor->process( $results->scan_runs() ) },
);
}
sub _do_simulation_for_board
{
my ( $self, $board ) = @_;
my $results = $self->_arbitrator()->simulate_board($board);
my $scan_mapper = sub {
my $index = shift;
return $self->_map_scan_idx_to_id($index);
};
return sprintf( "%i:%s:%s:%i",
$board + 1,
$results->get_status(),
$self->_get_run_string($results),
$results->get_total_iters(),
);
}
sub _real_do_simulation
{
my $self = shift;
open my $simulate_out_fh, ">", $self->_simulate_to()
or Carp::confess( "Could not open " . $self->_simulate_to() . " - $!" );
foreach my $board ( 0 .. $self->_num_boards() - 1 )
{
print {$simulate_out_fh} $self->_do_simulation_for_board($board), "\n";
}
close($simulate_out_fh);
return;
}
sub _do_simulation
{
my $self = shift;
# Analyze the results
if ( defined( $self->_simulate_to() ) )
{
$self->_real_do_simulation();
}
return;
}
sub run
{
my $self = shift;
if ( $self->_should_exit_immediately() )
{
return 0;
}
$self->_init_arbitrator();
$self->_arbitrator_process();
$self->_report_total_iters();
$self->_write_script();
$self->_do_trace();
$self->_do_simulation();
return 0;
}
sub run_flares
{
my $self = shift;
$self->_optimize_for("len");
$self->_is_flares(1);
$self->_init_arbitrator();
$self->_arbitrator()->calc_flares_meta_scan();
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
use PDL (qw( pdl ));
use PDL::IO::FastRaw (qw( readfraw writefraw ));
has start_board => ( isa => 'Int', is => 'ro', required => 1 );
has num_boards => ( isa => 'Int', is => 'ro', required => 1 );
has selected_scans => (
isa => 'ArrayRef',
is => 'ro',
required => 1,
default => sub {
my ($self) = @_;
return $self->_calc_selected_scan_list();
},
lazy => 1,
);
has _scan_ids_to_indexes => (
isa => 'HashRef[Int]',
is => 'ro',
lazy => 1,
default => sub {
my ($self) = @_;
my $scan_ids = $self->get_scan_ids_aref;
return +{ map { $scan_ids->[$_] => $_ } 0 .. $#$scan_ids };
},
);
sub _slurp
{
my $filename = shift;
open my $in, "<", $filename
or die "Could not open $filename";
binmode $in;
local $/;
my $content = <$in>;
close($in);
return $content;
}
sub _read_text_ints_file
{
my $self = shift;
my $filename = shift;
my $text = _slurp($filename);
return [ split( /[\n\r]+/, $text ) ];
}
# Number of selected scans.
sub _num_sel_scans
{
my $self = shift;
return scalar( @{ $self->selected_scans() } );
}
sub _gen_initial_scans_tensor
{
my $self = shift;
my $extra_dims = shift || [];
return zeroes( $self->num_boards(), $self->_num_sel_scans, @$extra_dims );
}
sub _should_update
{
my ( $self, $src_path, $dest_path ) = @_;
my @orig_stat = stat($src_path);
my @proc_stat = stat($dest_path);
return ( ( !@proc_stat ) || ( $orig_stat[9] > $proc_stat[9] ) );
}
# Number of numbers in the header of the solutions' iteration counts
my $NUM_NUMBERS_IN_HEADER = 3;
my $HEADER_START_BOARD_IDX = 0;
my $HEADER_NUM_BOARDS = 1;
my $HEADER_ITERATIONS_LIMIT = 2;
sub _get_scans_data_helper
{
my $self = shift;
my $selected_scans = $self->selected_scans();
my $start_board = $self->start_board();
my $scans_data = {};
my $scans_lens_data = {};
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
( $start_board - 1 ),
( ( $self->num_boards() - 1 ) + ( $start_board - 1 ) ) )
)->xchg( 1, 2 );
}
}
}
return { 'scans' => $scans_data, 'with_lens' => $scans_lens_data };
}
sub _get_scans_data_generic
{
my ( $self, $id ) = @_;
return $self->_get_scans_data_helper()->{$id};
}
sub get_scans_iters_pdls
{
my $self = shift;
return $self->_get_scans_data_generic('scans');
}
sub get_scans_lens_iters_pdls
{
my $self = shift;
return $self->_get_scans_data_generic('with_lens');
}
sub _filter_scans_based_on_black_list_ids
{
my ( $scans, $black_list_ids ) = @_;
my %black_list = ( map { /(\d+)/ ? ( $1 => 1 ) : () } @$black_list_ids );
return [ grep { !exists( $black_list{ $_->id() } ) } @$scans ];
}
sub _is_scan_suitable
{
my ( $self, $scan ) = @_;
my @stat = stat( $scan->data_file_path() );
return (
scalar(@stat)
&& ( $stat[7] >=
12 + ( $self->num_boards() + $self->start_board() - 1 ) * 4 )
);
}
sub _get_scans_registry_file_path
{
return "scans.txt";
}
sub _get_all_scans_list_from_file
{
my $self = shift;
my @scans;
my $scans_fn = $self->_get_scans_registry_file_path;
open my $scans_fh, "<", $scans_fn
or die "Could not open '$scans_fn' - $!.";
while ( my $line = <$scans_fh> )
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
AI::Pathfinding::OptimizeMultiple::Scan->new(
id => $id,
cmd_line => $cmd_line
);
}
close($scans_fh);
return \@scans;
}
sub _black_list_ids_list
{
my $self = shift;
open my $black_list_fh, "<", "scans-black-list.txt"
or die "Could not open 'scans-black-list.txt'! $!.";
my @black_list_ids = <$black_list_fh>;
chomp(@black_list_ids);
close($black_list_fh);
return \@black_list_ids;
}
sub _suitable_scans_list
{
my $self = shift;
return [ grep { $self->_is_scan_suitable($_) }
@{ $self->_get_all_scans_list_from_file() } ];
}
sub _calc_selected_scan_list
{
my $self = shift;
return _filter_scans_based_on_black_list_ids(
$self->_suitable_scans_list(),
$self->_black_list_ids_list(),
);
}
sub _get_next_id_file_path
{
return "next-id.txt";
}
sub get_next_id
{
my ($self) = @_;
my $id;
my $fn = $self->_get_next_id_file_path;
use autodie;
open my $in, "<", $fn;
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
chomp($id);
close($in);
open my $out, ">", $fn;
print {$out} ( $id + 1 );
close($out);
return $id;
}
sub get_prev_scans
{
my ($self) = @_;
my @prev_scans;
my $scans_fn = $self->_get_scans_registry_file_path;
open my $in, "<", $scans_fn
or die "Could not open '$scans_fn' - $!.";
while ( my $line = <$in> )
{
chomp($line);
my ( $scan_id, $cmd_line ) = split( /\t/, $line );
push @prev_scans, { 'id' => $scan_id, 'cmd_line' => $cmd_line };
}
close($in);
return \@prev_scans;
}
sub _get_scan_cmd_line
{
my $self = shift;
my $args = shift;
my $min_board = $args->{'min'} || 1;
my $max_board = $args->{'max'} || 32_000;
my $id = $args->{'id'};
my $argv = $args->{'argv'};
my @fc_num = (
exists( $args->{'freecells_num'} )
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
@variant,
'--total-iterations-limit',
( $ENV{FC_SOLVE_RANGE_ITERS_LIMIT} // 100000 ),
'--binary-output-to',
"data/$id.data.bin",
@$argv,
@fc_num,
];
}
sub time_scan
{
my $self = shift;
my $args = shift;
my $min_board = $args->{'min'} || 1;
my $max_board = $args->{'max'} || 32_000;
my $id = $args->{'id'};
my $cmd_line = $self->_get_scan_cmd_line($args);
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
elsif ( $line =~ m{\A\[\[Num FCPro Moves\]\]=(.*)\z}o )
{
print {$fc_pro_out} "$1\n";
}
}
close($from_cmd);
close($fcs_out);
close($fc_pro_out);
}
sub get_scan_ids_aref
{
my $self = shift;
return [ map { $_->id() } @{ $self->selected_scans } ];
}
sub lookup_scan_idx_based_on_id
{
my ( $self, $scan_id ) = @_;
my $idx = $self->_scan_ids_to_indexes->{$scan_id};
if ( !defined($idx) )
{
die "Index '$idx' does not exist!";
}
return $idx;
lib/AI/Pathfinding/OptimizeMultiple/IterState.pm view on Meta::CPAN
has _main => ( is => 'rw' );
has _num_solved =>
( isa => 'Int', is => 'ro', init_arg => 'num_solved', required => 1 );
has _quota => ( isa => 'Int', is => 'ro', init_arg => 'quota', required => 1 );
has _scan_idx =>
( isa => 'Int', is => 'ro', init_arg => 'scan_idx', required => 1 );
use Exception::Class ('AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas');
sub attach_to
{
my $self = shift;
my $main_obj = shift;
$self->_main($main_obj);
return;
}
sub get_chosen_struct
{
my $self = shift;
return $self->_main->_calc_chosen_scan( $self->_scan_idx, $self->_quota );
}
sub detach
{
my $self = shift;
$self->_main(undef);
}
sub idx_slice
{
my $self = shift;
my $scans_data = $self->_main()->_scans_data();
my @dims = $scans_data->dims();
return $scans_data->slice(
join( ",", ":", $self->_scan_idx(), ( ("(0)") x ( @dims - 2 ) ) ) );
}
sub update_total_iters
{
my $state = shift;
# $r is the result of this scan.
my $r = $state->idx_slice();
# Add the total iterations for all the states that were solved by
# this scan.
$state->_main()
->_add_to_total_iters(
lib/AI/Pathfinding/OptimizeMultiple/IterState.pm view on Meta::CPAN
# yet.
$state->_main()
->_add_to_total_iters( $indexes->nelem() * $state->_quota() );
# Keep only the states that have not been solved yet.
$state->_main()
->_scans_data(
$state->_main()->_scans_data()->dice( $indexes, "X" )->copy() );
}
sub update_idx_slice
{
my $state = shift;
my $r = $state->idx_slice()->copy();
# $r cannot be 0, because the ones that were 0, were already solved
# in $state->update_total_iters().
my $idx_slice = $state->idx_slice();
$idx_slice .=
( ( $r > 0 ) * ( $r - $state->_quota() ) ) + ( ( $r < 0 ) * ($r) );
}
sub _mark_as_used
{
my $state = shift;
$state->_main()->_selected_scans()->[ $state->_scan_idx() ]->mark_as_used();
return;
}
sub _add_chosen
{
my $state = shift;
push @{ $state->_main()->chosen_scans() }, $state->get_chosen_struct();
return;
}
sub _update_total_boards_solved
{
my $state = shift;
$state->_main()->_add_to_total_boards_solved( $state->_num_solved() );
return;
}
sub _trace_wrapper
{
my $state = shift;
$state->_main()->_trace(
{
'iters_quota' => $state->_quota(),
'selected_scan_idx' => $state->_scan_idx(),
'total_boards_solved' => $state->_main()->_total_boards_solved(),
}
);
return;
}
sub register_params
{
my $state = shift;
$state->_add_chosen();
$state->_mark_as_used();
$state->_update_total_boards_solved();
$state->_trace_wrapper();
return;
}
lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm view on Meta::CPAN
has _should_do_rle =>
( isa => 'Bool', is => 'ro', init_arg => 'do_rle', required => 1 );
has _offset_quotas => (
isa => 'Bool',
is => 'ro',
init_arg => 'offset_quotas',
required => 1
);
sub scans_rle
{
my $self = shift;
my @scans_list = @{ shift() };
my $scan = shift(@scans_list);
my (@a);
while ( my $next_scan = shift(@scans_list) )
{
lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm view on Meta::CPAN
else
{
push @a, $scan;
$scan = $next_scan;
}
}
push @a, $scan;
return \@a;
}
sub process
{
my $self = shift;
my $scans_orig = shift;
# clone the scans.
my $scans = [ map { $_->clone(); } @{$scans_orig} ];
if ( $self->_offset_quotas )
{
lib/AI/Pathfinding/OptimizeMultiple/Scan.pm view on Meta::CPAN
$AI::Pathfinding::OptimizeMultiple::Scan::VERSION = '0.0.17';
use strict;
use warnings;
use 5.012;
use MooX qw/late/;
has cmd_line => ( isa => 'Str', is => 'ro', required => 1, );
has id => ( isa => 'Str', is => 'ro', required => 1, );
has used => ( isa => 'Bool', is => 'rw', default => sub { 0; } );
sub mark_as_used
{
my $self = shift;
$self->used(1);
}
sub is_used
{
my $self = shift;
return $self->used();
}
sub data_file_path
{
my $self = shift;
return "./data/" . $self->id() . ".data.bin";
}
1;
__END__
lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm view on Meta::CPAN
use strict;
use warnings;
use 5.012;
use MooX qw/late/;
has iters => ( isa => 'Int', is => 'rw', required => 1 );
has scan_idx => ( isa => 'Int', is => 'ro', required => 1 );
sub clone
{
my $self = shift;
return ref($self)->new(
{
iters => $self->iters(),
scan_idx => $self->scan_idx(),
}
);
}
lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm view on Meta::CPAN
use MooX qw/late/;
has status => ( isa => 'Str', is => 'ro', required => 1, );
has total_iters => ( isa => 'Int', is => 'ro', required => 1, );
has scan_runs => (
isa => 'ArrayRef[AI::Pathfinding::OptimizeMultiple::ScanRun]',
is => 'ro',
required => 1,
);
sub get_total_iters
{
return shift->total_iters();
}
sub get_status
{
return shift->status();
}
1;
__END__
=pod
t/cmdline-app.t view on Meta::CPAN
if ($@)
{
plan skip_all => "Test::Trap not found.";
}
plan tests => 6;
my @running_modes = (
{
blurb_base => 'modulino',
sub_ref => sub {
my ($flags) = @_;
AI::Pathfinding::OptimizeMultiple::App::CmdLine->new(
{
argv => [@$flags],
},
)->run();
},
},
{
blurb_base => 'cmd_line',
sub_ref => sub {
my ($flags) = @_;
system( $^X, "bin/optimize-game-ai-multi-tasking", @$flags );
},
},
);
# TEST:$num_subs=2;
foreach my $mode (@running_modes)
{
my $blurb_base = $mode->{blurb_base};
trap( sub { return $mode->{sub_ref}->( [qw(--help)] ); } );
# TEST*$num_subs
like( $trap->stdout(), qr/--output/,
"stdout matches --output flag. ($blurb_base)",
);
# TEST*$num_subs
like(
$trap->stdout(),
qr/--help[^\n]*-h[^\n]*displays this help screen/ms,
t/optimize-multiple-full-test.t view on Meta::CPAN
use Test::More tests => 4;
use Test::Differences qw(eq_or_diff);
use PDL (qw/ pdl /);
use AI::Pathfinding::OptimizeMultiple ();
# TEST:$c=0;
sub test_based_on_data
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ( $scans_aref, $quotas_aref, $want_results, $stats_factors, $blurb ) =
@_;
my $results_aref = [];
my $selected_scans = [
map {
xt/release/cpan-changes.t view on Meta::CPAN
use strict;
use warnings;
# this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012
use Test::More 0.96 tests => 1;
use Test::CPAN::Changes;
subtest 'changes_ok' => sub {
changes_file_ok('Changes');
};