AI-Pathfinding-OptimizeMultiple

 view release on metacpan or  search on metacpan

Build.PL  view on Meta::CPAN


# This file was automatically generated by Dist::Zilla::Plugin::ModuleBuild v6.024.
use strict;
use warnings;

use Module::Build 0.28;


my %module_build_args = (
  "build_requires" => {
    "Module::Build" => "0.28"
  },
  "configure_requires" => {
    "Module::Build" => "0.28"
  },
  "dist_abstract" => "optimize path finding searches for a large set of initial conditions (for better average performance).",
  "dist_author" => [
    "Shlomi Fish <shlomif\@cpan.org>"
  ],
  "dist_name" => "AI-Pathfinding-OptimizeMultiple",
  "dist_version" => "0.0.17",
  "license" => "mit",
  "module_name" => "AI::Pathfinding::OptimizeMultiple",
  "recursive_test_files" => 1,
  "requires" => {
    "Carp" => 0,
    "Exception::Class" => 0,
    "File::Path" => 0,
    "Getopt::Long" => 0,
    "IO::File" => 0,
    "MooX" => 0,
    "MooX::Types::MooseLike::Base" => 0,
    "MooX::late" => "0.007",
    "PDL" => 0,
    "PDL::IO::FastRaw" => 0,
    "Scalar::Util" => 0,
    "autodie" => 0,
    "perl" => "5.012",
    "strict" => 0,
    "vars" => 0,
    "warnings" => 0
  },
  "script_files" => [
    "bin/optimize-game-ai-multi-tasking"
  ],
  "test_requires" => {
    "File::Spec" => 0,
    "IO::Handle" => 0,
    "IPC::Open3" => 0,
    "Test::Differences" => 0,
    "Test::More" => "0.88"
  }
);


my %fallback_build_requires = (
  "File::Spec" => 0,
  "IO::Handle" => 0,
  "IPC::Open3" => 0,
  "Module::Build" => "0.28",
  "Test::Differences" => 0,
  "Test::More" => "0.88"
);


unless ( eval { Module::Build->VERSION(0.4004) } ) {
  delete $module_build_args{test_requires};
  $module_build_args{build_requires} = \%fallback_build_requires;
}

my $build = Module::Build->new(%module_build_args);


$build->create_build_script;

Changes  view on Meta::CPAN

0.0.17      2022-10-27
    - Fix tests with latest PDL.
        - https://rt.cpan.org/Ticket/Display.html?id=144651
        - Thanks to SREZIC

0.0.16      2020-10-20
    - dist.ini / weaver.ini / .tidyallrc / etc. cleanup
        - Move to @SHLOMIF
        - Inspired by Lady_Aleena.

v0.0.15     2017-05-01
    - Skip adding ~$ files to the MANIFEST.
        - See https://rt.cpan.org/Ticket/Display.html?id=121485 .
        - Thanks to Toby Inkster.

v0.0.14     2017-05-01
    - Convert dist.ini to use the @SHLOMIF bundle.
    - Fix a bug where a pdl was passed instead of an int.
        - See https://rt.cpan.org/Ticket/Display.html?id=121478
        - Thanks to Slaven Rezic and Toby Inkster.

v0.0.13     2016-04-20
    - Improve the exception handling due to a non-Exception::Class error:
        - http://www.cpantesters.org/cpan/report/f631b3e2-03b5-11e6-b1a3-5205ef11d1c8
        - Thanks also to the example code in
        https://metacpan.org/pod/Exception::Class .
    - Add Test::Kwalitee::Extra.

v0.0.12     2015-03-26
    - Add the stats_factors option to the
    lib/AI/Pathfinding/OptimizeMultiple.pm constructor.
        - Contains some factors to normalise the iters of specific scans.
    - Add the --stats-factors option to ::CmdLine.
    - Allow to customise the --total-iterations-limit using
    $ENV{FC_SOLVE_RANGE_ITERS_LIMIT} .

v0.0.11     2014-03-29
    - Move the external-deps-using release tests to xt/ instead of t/
        - Better Kwalitee.
        - Thanks to "ether" on #distzilla for the insights on fixing it.

v0.0.10     2014-03-28
    - Convert to the Test::CPAN::Changes Dist-Zilla plugin.

v0.0.9      2014-03-28
    - Add an explicit symbol import on "use PDL"/etc.
    - Add get_scan_ids_aref() and lookup_scan_idx_based_on_id() to
    AI::Pathfinding::OptimizeMultiple::DataInputObj .
    - Add the $args parameter with the 'chosen_scans' key to
    AI::Pathfinding::OptimizeMultiple::simulate_board() .
    - Add support for some extra required options in
    AI::Pathfinding::OptimizeMultiple::DataInputObj’s time-scan.pl.

v0.0.8      2014-02-02
    - Made sure the =encoding directive is on top of the file in
    bin/optimize-game-ai-multi-tasking .

v0.0.7      2014-01-26
    - Minimal version of perl - 5.012 in the prereqs (could be lower, possibly).
        - For Kwalitee.
    - Remove the Makefile.PL so we will have "metayml has provides".
        - Now it's Build.PL-only.
    - Add provides to the META.yml.

v0.0.6      2014-01-25
    - Add "use strict;" and "use warnings;" to MooX::late modules.
        - Kwalitee
    - Remove the ^Rejects and ^scripts sub-directories.
        - They were confusing CPANTS and reduced our Kwalitee.

v0.0.5      2013-01-22
    - skipping compile test for scripts/bump-version-number.pl .
        - it is for use by the module's maintainer and has
        non-essential prereqs.

v0.0.4      2013-01-20

    - Add missing Prerequisites
        - MooX::late
        - MooX::Types::MooseLike::Base

v0.0.3      2013-01-18

    - Fixed broken POD for hyperlinks.

v0.0.2      2013-01-17

    - Fixed the POD - removed extraneous sections and added a NAME handler.
        - Part of it was caused due to a Pod::Weaver misconfiguration

v0.0.1      2013-01-17

    - First version, released on an unsuspecting world.

    - Everything is still subject to change and break.

LICENSE  view on Meta::CPAN

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

The MIT License

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to
whom the Software is furnished to do so, subject to the

META.json  view on Meta::CPAN

{
   "abstract" : "optimize path finding searches for a large set of initial conditions (for better average performance).",
   "author" : [
      "Shlomi Fish <shlomif@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.024, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "mit"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "AI-Pathfinding-OptimizeMultiple",
   "prereqs" : {
      "build" : {
         "requires" : {
            "Module::Build" : "0.28"
         }
      },
      "configure" : {
         "requires" : {
            "Module::Build" : "0.28"
         }
      },
      "develop" : {
         "requires" : {
            "Pod::Coverage::TrustPod" : "0",
            "Test::CPAN::Changes" : "0.19",
            "Test::EOL" : "0",
            "Test::More" : "0.96",
            "Test::NoTabs" : "0",
            "Test::Pod" : "1.41",
            "Test::Pod::Coverage" : "1.08",
            "Test::TrailingSpace" : "0.0203"
         }
      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Exception::Class" : "0",
            "File::Path" : "0",
            "Getopt::Long" : "0",
            "IO::File" : "0",
            "MooX" : "0",
            "MooX::Types::MooseLike::Base" : "0",
            "MooX::late" : "0.007",
            "PDL" : "0",
            "PDL::IO::FastRaw" : "0",
            "Scalar::Util" : "0",
            "autodie" : "0",
            "perl" : "5.012",
            "strict" : "0",
            "vars" : "0",
            "warnings" : "0"
         }
      },
      "test" : {
         "requires" : {
            "File::Spec" : "0",
            "IO::Handle" : "0",
            "IPC::Open3" : "0",
            "Test::Differences" : "0",
            "Test::More" : "0.88"
         }
      }
   },
   "provides" : {
      "AI::Pathfinding::OptimizeMultiple" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::App::CmdLine" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::DataInputObj" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::IterState" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/IterState.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::PostProcessor" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::Scan" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/Scan.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::ScanRun" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm",
         "version" : "v0.0.17"
      },
      "AI::Pathfinding::OptimizeMultiple::SimulationResults" : {
         "file" : "lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm",
         "version" : "v0.0.17"
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/shlomif/fc-solve/issues"
      },
      "homepage" : "http://metacpan.org/release/AI-Pathfinding-OptimizeMultiple",
      "repository" : {
         "type" : "git",
         "url" : "ssh://git@github.com/shlomif/fc-solve.git",
         "web" : "http://github.com/shlomif/fc-solve"
      }
   },
   "version" : "0.0.17",
   "x_Dist_Zilla" : {
      "perl" : {
         "version" : "5.034001"
      },
      "plugins" : [
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "test",
                  "type" : "requires"
               }
            },
            "name" : "@Filter/TestMoreDoneTesting",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "@Filter/AutoPrereqs",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::ExecDir",
            "name" : "@Filter/ExecDir",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::GatherDir",
            "config" : {
               "Dist::Zilla::Plugin::GatherDir" : {
                  "exclude_filename" : [],
                  "exclude_match" : [],
                  "follow_symlinks" : 0,
                  "include_dotfiles" : 0,
                  "prefix" : "",
                  "prune_directory" : [],
                  "root" : "."
               }
            },
            "name" : "@Filter/GatherDir",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::License",
            "name" : "@Filter/License",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::ManifestSkip",
            "name" : "@Filter/ManifestSkip",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaYAML",
            "name" : "@Filter/MetaYAML",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "@Filter/PruneCruft",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::Readme",
            "name" : "@Filter/Readme",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "4"
               }
            },
            "name" : "@Filter/RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Filter/ShareDir",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
            "name" : "@Filter/CheckChangesHasContent",
            "version" : "0.011"
         },
         {
            "class" : "Dist::Zilla::Plugin::ConfirmRelease",
            "name" : "@Filter/ConfirmRelease",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Filter/Manifest",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaConfig",
            "name" : "@Filter/MetaConfig",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaJSON",
            "name" : "@Filter/MetaJSON",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
            "config" : {
               "Dist::Zilla::Plugin::MetaProvides::Package" : {
                  "finder_objects" : [
                     {
                        "class" : "Dist::Zilla::Plugin::FinderCode",
                        "name" : "@Filter/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
                        "version" : "6.024"
                     }
                  ],
                  "include_underscores" : 0
               },
               "Dist::Zilla::Role::MetaProvider::Provider" : {
                  "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004",
                  "inherit_missing" : 1,
                  "inherit_version" : 1,
                  "meta_noindex" : 1
               },
               "Dist::Zilla::Role::ModuleMetadata" : {
                  "Module::Metadata" : "1.000037",
                  "version" : "0.006"
               }
            },
            "name" : "@Filter/MetaProvides::Package",
            "version" : "2.004003"
         },
         {
            "class" : "Dist::Zilla::Plugin::MetaResources",
            "name" : "@Filter/MetaResources",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::ModuleBuild",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "4"
               }
            },
            "name" : "@Filter/ModuleBuild",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PkgVersion",
            "name" : "@Filter/PkgVersion",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodCoverageTests",
            "name" : "@Filter/PodCoverageTests",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
            "name" : "@Filter/PodSyntaxTests",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::Compile",
            "config" : {
               "Dist::Zilla::Plugin::Test::Compile" : {
                  "bail_out_on_fail" : 0,
                  "fail_on_warning" : "author",
                  "fake_home" : 0,
                  "filename" : "t/00-compile.t",
                  "module_finder" : [
                     ":InstallModules"
                  ],
                  "needs_display" : 0,
                  "phase" : "test",
                  "script_finder" : [
                     ":PerlExecFiles"
                  ],
                  "skips" : [],
                  "switch" : []
               }
            },
            "name" : "@Filter/Test::Compile",
            "version" : "2.058"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes",
            "config" : {
               "Dist::Zilla::Plugin::Test::CPAN::Changes" : {
                  "changelog" : "Changes"
               }
            },
            "name" : "@Filter/Test::CPAN::Changes",
            "version" : "0.012"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::EOL",
            "config" : {
               "Dist::Zilla::Plugin::Test::EOL" : {
                  "filename" : "xt/author/eol.t",
                  "finder" : [
                     ":ExecFiles",
                     ":InstallModules",
                     ":TestFiles"
                  ],
                  "trailing_whitespace" : 1
               }
            },
            "name" : "@Filter/Test::EOL",
            "version" : "0.19"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::NoTabs",
            "config" : {
               "Dist::Zilla::Plugin::Test::NoTabs" : {
                  "filename" : "xt/author/no-tabs.t",
                  "finder" : [
                     ":InstallModules",
                     ":ExecFiles",
                     ":TestFiles"
                  ]
               }
            },
            "name" : "@Filter/Test::NoTabs",
            "version" : "0.15"
         },
         {
            "class" : "Dist::Zilla::Plugin::Test::TrailingSpace",
            "name" : "@Filter/Test::TrailingSpace",
            "version" : null
         },
         {
            "class" : "Dist::Zilla::Plugin::TestRelease",
            "name" : "@Filter/TestRelease",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PodWeaver",
            "config" : {
               "Dist::Zilla::Plugin::PodWeaver" : {
                  "finder" : [
                     ":InstallModules",
                     ":ExecFiles"
                  ],
                  "plugins" : [
                     {
                        "class" : "Pod::Weaver::Plugin::SingleEncoding",
                        "name" : "@SHLOMIF/SingleEncoding",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::WikiDoc",
                        "name" : "@SHLOMIF/WikiDoc",
                        "version" : "0.093004"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::EnsurePod5",
                        "name" : "@CorePrep/EnsurePod5",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::H1Nester",
                        "name" : "@CorePrep/H1Nester",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Name",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Version",
                        "name" : "@SHLOMIF/Version",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@SHLOMIF/Prelude",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Synopsis",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Description",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Usage",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Overview",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Generic",
                        "name" : "@SHLOMIF/Stability",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "Requirements",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "Attributes",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "Constructors",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "Methods",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Collect",
                        "name" : "Functions",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Leftovers",
                        "name" : "@SHLOMIF/Leftovers",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Region",
                        "name" : "@SHLOMIF/postlude",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Support",
                        "name" : "@SHLOMIF/Support",
                        "version" : "1.013"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Authors",
                        "name" : "@SHLOMIF/Authors",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Bugs",
                        "name" : "@SHLOMIF/Bugs",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Contributors",
                        "name" : "@SHLOMIF/Contributors",
                        "version" : "0.009"
                     },
                     {
                        "class" : "Pod::Weaver::Section::Legal",
                        "name" : "@SHLOMIF/Legal",
                        "version" : "4.018"
                     },
                     {
                        "class" : "Pod::Weaver::Plugin::Transformer",
                        "name" : "@SHLOMIF/List",
                        "version" : "4.018"
                     }
                  ]
               }
            },
            "name" : "@Filter/PodWeaver",
            "version" : "4.009"
         },
         {
            "class" : "Dist::Zilla::Plugin::UploadToCPAN",
            "name" : "@Filter/UploadToCPAN",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::AutoPrereqs",
            "name" : "AutoPrereqs",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::Prereqs",
            "config" : {
               "Dist::Zilla::Plugin::Prereqs" : {
                  "phase" : "runtime",
                  "type" : "requires"
               }
            },
            "name" : "Prereqs",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneCruft",
            "name" : "PruneCruft",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::PruneFiles",
            "name" : "PruneFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::RunExtraTests",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : "4"
               }
            },
            "name" : "RunExtraTests",
            "version" : "0.029"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":InstallModules",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":IncModules",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":TestFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExtraTestFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ExecFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":PerlExecFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":ShareFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":MainModule",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":AllFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : ":NoFiles",
            "version" : "6.024"
         },
         {
            "class" : "Dist::Zilla::Plugin::FinderCode",
            "name" : "@Filter/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
            "version" : "6.024"
         }
      ],
      "zilla" : {
         "class" : "Dist::Zilla::Dist::Builder",
         "config" : {
            "is_trial" : 0
         },
         "version" : "6.024"
      }
   },
   "x_generated_by_perl" : "v5.34.1",
   "x_serialization_backend" : "Cpanel::JSON::XS version 4.26",
   "x_spdx_expression" : "MIT"
}

META.yml  view on Meta::CPAN

---
abstract: 'optimize path finding searches for a large set of initial conditions (for better average performance).'
author:
  - 'Shlomi Fish <shlomif@cpan.org>'
build_requires:
  File::Spec: '0'
  IO::Handle: '0'
  IPC::Open3: '0'
  Module::Build: '0.28'
  Test::Differences: '0'
  Test::More: '0.88'
configure_requires:
  Module::Build: '0.28'
dynamic_config: 0
generated_by: 'Dist::Zilla version 6.024, CPAN::Meta::Converter version 2.150010'
license: mit
meta-spec:
  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: '1.4'
name: AI-Pathfinding-OptimizeMultiple
provides:
  AI::Pathfinding::OptimizeMultiple:
    file: lib/AI/Pathfinding/OptimizeMultiple.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::App::CmdLine:
    file: lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::DataInputObj:
    file: lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::IterState:
    file: lib/AI/Pathfinding/OptimizeMultiple/IterState.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::PostProcessor:
    file: lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::Scan:
    file: lib/AI/Pathfinding/OptimizeMultiple/Scan.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::ScanRun:
    file: lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm
    version: v0.0.17
  AI::Pathfinding::OptimizeMultiple::SimulationResults:
    file: lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm
    version: v0.0.17
requires:
  Carp: '0'
  Exception::Class: '0'
  File::Path: '0'
  Getopt::Long: '0'
  IO::File: '0'
  MooX: '0'
  MooX::Types::MooseLike::Base: '0'
  MooX::late: '0.007'
  PDL: '0'
  PDL::IO::FastRaw: '0'
  Scalar::Util: '0'
  autodie: '0'
  perl: '5.012'
  strict: '0'
  vars: '0'
  warnings: '0'
resources:
  bugtracker: https://github.com/shlomif/fc-solve/issues
  homepage: http://metacpan.org/release/AI-Pathfinding-OptimizeMultiple
  repository: ssh://git@github.com/shlomif/fc-solve.git
version: 0.0.17
x_Dist_Zilla:
  perl:
    version: '5.034001'
  plugins:
    -
      class: Dist::Zilla::Plugin::Prereqs
      config:
        Dist::Zilla::Plugin::Prereqs:
          phase: test
          type: requires
      name: '@Filter/TestMoreDoneTesting'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::AutoPrereqs
      name: '@Filter/AutoPrereqs'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::ExecDir
      name: '@Filter/ExecDir'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::GatherDir
      config:
        Dist::Zilla::Plugin::GatherDir:
          exclude_filename: []
          exclude_match: []
          follow_symlinks: 0
          include_dotfiles: 0
          prefix: ''
          prune_directory: []
          root: .
      name: '@Filter/GatherDir'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::License
      name: '@Filter/License'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::ManifestSkip
      name: '@Filter/ManifestSkip'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::MetaYAML
      name: '@Filter/MetaYAML'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PruneCruft
      name: '@Filter/PruneCruft'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::Readme
      name: '@Filter/Readme'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::RunExtraTests
      config:
        Dist::Zilla::Role::TestRunner:
          default_jobs: '4'
      name: '@Filter/RunExtraTests'
      version: '0.029'
    -
      class: Dist::Zilla::Plugin::ShareDir
      name: '@Filter/ShareDir'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::CheckChangesHasContent
      name: '@Filter/CheckChangesHasContent'
      version: '0.011'
    -
      class: Dist::Zilla::Plugin::ConfirmRelease
      name: '@Filter/ConfirmRelease'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::Manifest
      name: '@Filter/Manifest'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::MetaConfig
      name: '@Filter/MetaConfig'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::MetaJSON
      name: '@Filter/MetaJSON'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::MetaProvides::Package
      config:
        Dist::Zilla::Plugin::MetaProvides::Package:
          finder_objects:
            -
              class: Dist::Zilla::Plugin::FinderCode
              name: '@Filter/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
              version: '6.024'
          include_underscores: 0
        Dist::Zilla::Role::MetaProvider::Provider:
          $Dist::Zilla::Role::MetaProvider::Provider::VERSION: '2.002004'
          inherit_missing: '1'
          inherit_version: '1'
          meta_noindex: '1'
        Dist::Zilla::Role::ModuleMetadata:
          Module::Metadata: '1.000037'
          version: '0.006'
      name: '@Filter/MetaProvides::Package'
      version: '2.004003'
    -
      class: Dist::Zilla::Plugin::MetaResources
      name: '@Filter/MetaResources'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::ModuleBuild
      config:
        Dist::Zilla::Role::TestRunner:
          default_jobs: '4'
      name: '@Filter/ModuleBuild'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PkgVersion
      name: '@Filter/PkgVersion'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PodCoverageTests
      name: '@Filter/PodCoverageTests'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PodSyntaxTests
      name: '@Filter/PodSyntaxTests'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::Test::Compile
      config:
        Dist::Zilla::Plugin::Test::Compile:
          bail_out_on_fail: '0'
          fail_on_warning: author
          fake_home: 0
          filename: t/00-compile.t
          module_finder:
            - ':InstallModules'
          needs_display: 0
          phase: test
          script_finder:
            - ':PerlExecFiles'
          skips: []
          switch: []
      name: '@Filter/Test::Compile'
      version: '2.058'
    -
      class: Dist::Zilla::Plugin::Test::CPAN::Changes
      config:
        Dist::Zilla::Plugin::Test::CPAN::Changes:
          changelog: Changes
      name: '@Filter/Test::CPAN::Changes'
      version: '0.012'
    -
      class: Dist::Zilla::Plugin::Test::EOL
      config:
        Dist::Zilla::Plugin::Test::EOL:
          filename: xt/author/eol.t
          finder:
            - ':ExecFiles'
            - ':InstallModules'
            - ':TestFiles'
          trailing_whitespace: 1
      name: '@Filter/Test::EOL'
      version: '0.19'
    -
      class: Dist::Zilla::Plugin::Test::NoTabs
      config:
        Dist::Zilla::Plugin::Test::NoTabs:
          filename: xt/author/no-tabs.t
          finder:
            - ':InstallModules'
            - ':ExecFiles'
            - ':TestFiles'
      name: '@Filter/Test::NoTabs'
      version: '0.15'
    -
      class: Dist::Zilla::Plugin::Test::TrailingSpace
      name: '@Filter/Test::TrailingSpace'
      version: ~
    -
      class: Dist::Zilla::Plugin::TestRelease
      name: '@Filter/TestRelease'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PodWeaver
      config:
        Dist::Zilla::Plugin::PodWeaver:
          finder:
            - ':InstallModules'
            - ':ExecFiles'
          plugins:
            -
              class: Pod::Weaver::Plugin::SingleEncoding
              name: '@SHLOMIF/SingleEncoding'
              version: '4.018'
            -
              class: Pod::Weaver::Plugin::WikiDoc
              name: '@SHLOMIF/WikiDoc'
              version: '0.093004'
            -
              class: Pod::Weaver::Plugin::EnsurePod5
              name: '@CorePrep/EnsurePod5'
              version: '4.018'
            -
              class: Pod::Weaver::Plugin::H1Nester
              name: '@CorePrep/H1Nester'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Name'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Version
              name: '@SHLOMIF/Version'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Region
              name: '@SHLOMIF/Prelude'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Synopsis'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Description'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Usage'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Overview'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Generic
              name: '@SHLOMIF/Stability'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Collect
              name: Requirements
              version: '4.018'
            -
              class: Pod::Weaver::Section::Collect
              name: Attributes
              version: '4.018'
            -
              class: Pod::Weaver::Section::Collect
              name: Constructors
              version: '4.018'
            -
              class: Pod::Weaver::Section::Collect
              name: Methods
              version: '4.018'
            -
              class: Pod::Weaver::Section::Collect
              name: Functions
              version: '4.018'
            -
              class: Pod::Weaver::Section::Leftovers
              name: '@SHLOMIF/Leftovers'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Region
              name: '@SHLOMIF/postlude'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Support
              name: '@SHLOMIF/Support'
              version: '1.013'
            -
              class: Pod::Weaver::Section::Authors
              name: '@SHLOMIF/Authors'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Bugs
              name: '@SHLOMIF/Bugs'
              version: '4.018'
            -
              class: Pod::Weaver::Section::Contributors
              name: '@SHLOMIF/Contributors'
              version: '0.009'
            -
              class: Pod::Weaver::Section::Legal
              name: '@SHLOMIF/Legal'
              version: '4.018'
            -
              class: Pod::Weaver::Plugin::Transformer
              name: '@SHLOMIF/List'
              version: '4.018'
      name: '@Filter/PodWeaver'
      version: '4.009'
    -
      class: Dist::Zilla::Plugin::UploadToCPAN
      name: '@Filter/UploadToCPAN'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::AutoPrereqs
      name: AutoPrereqs
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::Prereqs
      config:
        Dist::Zilla::Plugin::Prereqs:
          phase: runtime
          type: requires
      name: Prereqs
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PruneCruft
      name: PruneCruft
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::PruneFiles
      name: PruneFiles
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::RunExtraTests
      config:
        Dist::Zilla::Role::TestRunner:
          default_jobs: '4'
      name: RunExtraTests
      version: '0.029'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':InstallModules'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':IncModules'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':TestFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':ExtraTestFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':ExecFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':PerlExecFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':ShareFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':MainModule'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':AllFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: ':NoFiles'
      version: '6.024'
    -
      class: Dist::Zilla::Plugin::FinderCode
      name: '@Filter/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
      version: '6.024'
  zilla:
    class: Dist::Zilla::Dist::Builder
    config:
      is_trial: '0'
    version: '6.024'
x_generated_by_perl: v5.34.1
x_serialization_backend: 'YAML::Tiny version 1.73'
x_spdx_expression: MIT

README  view on Meta::CPAN

This archive contains the distribution AI-Pathfinding-OptimizeMultiple,
version 0.0.17:

  optimize path finding searches for a large set of initial conditions (for better average performance).

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License


This README file was generated by Dist::Zilla::Plugin::Readme v6.024.

bin/optimize-game-ai-multi-tasking  view on Meta::CPAN


# 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();

1;

__END__

=pod

=encoding UTF-8

bin/optimize-game-ai-multi-tasking  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple.pm  view on Meta::CPAN

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};
            (
                defined($factor)
                ? ( ( $pdl >= 0 ) * ( ( $pdl / $factor )->ceil() ) +
                        ( $pdl < 0 ) * $pdl )
                : $pdl
            );
        } @{ $self->_selected_scans() }
    );

    $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 )
    {
        my $q_more = $self->_get_next_quota();
        if ( !defined($q_more) )
        {
            AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
                error => "No q_more", );
        }

        $iters_quota += $q_more;

        my $iters        = $self->_scans_data()->slice(":,:,0");
        my $solved       = ( ( $iters <= $iters_quota ) & ( $iters > 0 ) );
        my $num_moves    = $self->_scans_data->slice(":,:,2");
        my $solved_moves = $solved * $num_moves;

        my $solved_moves_sums   = _my_sum_over($solved_moves);
        my $solved_moves_counts = _my_sum_over($solved);
        my $solved_moves_avgs   = $solved_moves_sums / $solved_moves_counts;

        ( undef, undef, $selected_scan_idx, undef ) =
            $solved_moves_avgs->minmaximum();

        $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 )
    {
        my $q_more = $self->_get_next_quota();
        if ( !defined($q_more) )
        {
            AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
                error => "No q_more", );
        }

        $iters_quota += $q_more;

        my $iters        = $self->_scans_data()->slice(":,:,0");
        my $solved       = ( ( $iters <= $iters_quota ) & ( $iters > 0 ) );
        my $num_moves    = $self->_scans_data->slice(":,:,2");
        my $solved_moves = $solved * $num_moves;

        my $solved_moves_maxima = $solved_moves->maximum()->slice(":,(0),(0)");
        my $solved_moves_counts = _my_sum_over($solved);

        ( undef, undef, $selected_scan_idx, undef ) =
            $solved_moves_maxima->minmaximum();

        $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 )
    {
        my $q_more = $self->_get_next_quota();
        if ( !defined($q_more) )
        {
            AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
                error => "No q_more" );
        }

        $iters_quota += $q_more;

        ( undef, $num_solved_in_iter, undef, $selected_scan_idx ) =
            PDL::minmaximum(
            PDL::sumover(
                ( $self->_scans_data() <= $iters_quota ) &
                    ( $self->_scans_data() > 0 )
            )
            );
    }

    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() )
    {
        $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");

    # $self->_inspect_quota() throws ::Error::OutOfQuotas if
    # it does not have any available quotas.
    eval {
        while ( $self->_status() eq "iterating" )
        {
            $self->_inspect_quota();
        }
    };
    if (
        my $err = Exception::Class->caught(
            'AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas')
        )
    {
        $self->_status("out_of_quotas");
    }
    else
    {
        $err = Exception::Class->caught();
        if ($err)
        {
            if ( not( blessed $err && $err->can('rethrow') ) )
            {
                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");

    my $iters_quota      = 0;
    my $flares_num_iters = PDL::Core::pdl( [ (0) x $self->_get_num_scans() ] );
    my $ones_constant =
        PDL::Core::pdl( [ map { [1] } ( 1 .. $self->_get_num_scans() ) ] );

    my $next_num_iters_for_each_scan_x_scan =
        ( ( $ones_constant x $flares_num_iters ) );

    my $num_moves = $self->_scans_data->slice(":,:,1");

    # The number of moves for dimension 0,1,2 above.
    my $num_moves_repeat = $num_moves->clump( 1 .. 2 )->xchg( 0, 1 )
        ->dummy( 0, $self->_get_num_scans() );

    my $selected_scan_idx;

    my $loop_iter_num = 0;

    my $UNSOLVED_NUM_MOVES_CONSTANT = 64 * 1024 * 1024;

    my $last_avg = $UNSOLVED_NUM_MOVES_CONSTANT;

FLARES_LOOP:
    while ( my $q_more = $self->_get_next_quota() )
    {
        $iters_quota += $q_more;

        # Next number of iterations for each scan x scan combination.
        my $next_num_iters = (
            ( $ones_constant x $flares_num_iters ) + (
                PDL::MatrixOps::identity( $self->_get_num_scans() ) *
                    $iters_quota
            )
        );

        # print "\$next_num_iters = $next_num_iters\n";

        my $iters = $self->_scans_data()->slice(":,:,0");

        my $iters_repeat =
            $iters->dummy( 0, $self->_get_num_scans() )->xchg( 1, 2 )
            ->clump( 2 .. 3 );

        # print "\$iters_repeat =", join(",",$iters_repeat->dims()), "\n";

        my $next_num_iters_repeat =
            $next_num_iters->dummy( 0, $self->_num_boards() )->xchg( 0, 2 );

# print "\$next_num_iters_repeat =", join(",",$next_num_iters_repeat->dims()), "\n";

        # A boolean tensor of which boards were solved:
        # Dimension 0 - Which scan is it. - size - _get_num_scans()
        # Dimension 1 - Which scan we added the quota to
        #   - size - _get_num_scans()
        # Dimension 2 - Which board. - size - _num_boards()
        my $solved =
            ( $iters_repeat >= 0 ) * ( $iters_repeat < $next_num_iters_repeat );

      # print "\$num_moves_repeat =", join(",",$num_moves_repeat->dims()), "\n";

        my $num_moves_solved =
            ( $solved * $num_moves_repeat ) +
            ( $solved->not() * $UNSOLVED_NUM_MOVES_CONSTANT );

        my $minimal_num_moves_solved =
            $num_moves_solved->xchg( 0, 1 )->minimum();

        my $which_minima_are_solved =
            ( $minimal_num_moves_solved != $UNSOLVED_NUM_MOVES_CONSTANT );

        my $minimal_with_zeroes =
            $which_minima_are_solved * $minimal_num_moves_solved;

        my $solved_moves_sums   = _my_xchg_sum_over($minimal_with_zeroes);
        my $solved_moves_counts = _my_xchg_sum_over($which_minima_are_solved);
        my $solved_moves_avgs   = $solved_moves_sums / $solved_moves_counts;

        # print join(",", $solved_moves_avgs->minmaximum()), "\n";

        my $min_avg;

        ( $min_avg, undef, $selected_scan_idx, undef ) =
            $solved_moves_avgs->minmaximum();

        $last_avg = $min_avg;

        push @{ $self->chosen_scans() },
            $self->_calc_chosen_scan( $selected_scan_idx, $iters_quota );

        $flares_num_iters->set( $selected_scan_idx,
            $flares_num_iters->at($selected_scan_idx) + $iters_quota );
        $self->_selected_scans()->[$selected_scan_idx]->mark_as_used();

        $iters_quota = 0;

        my $num_solved = $solved_moves_counts->at($selected_scan_idx);

        my $flares_num_iters_repeat =
            $flares_num_iters->dummy( 0, $self->_num_boards() );

        # A boolean tensor:
        # Dimension 0 - board.
        # Dimension 1 - scans.
        my $solved_with_which_iter =
            ( $flares_num_iters_repeat >= $iters->clump( 1 .. 2 ) ) &
            ( $iters->clump( 1 .. 2 ) >= 0 );

        my $total_num_iters = (
            ( $solved_with_which_iter * $flares_num_iters_repeat )->sum() + (
                $solved_with_which_iter->not()->andover() *
                    $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() } )
    {
        if (   ( $info[ $s->scan_idx() ] > 0 )
            && ( $info[ $s->scan_idx() ] <= $s->iters() ) )
        {
            $board_iters += $info[ $s->iters() ];
            last;
        }
        else
        {
            if ( $info[ $s->scan_idx() ] > 0 )
            {
                $info[ $s->scan_idx() ] -= $s->iters();
            }
            $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:
    foreach my $s (@$chosen_scans)
    {
        if (   ( $info[ $s->scan_idx() ] > 0 )
            && ( $info[ $s->scan_idx() ] <= $s->iters() ) )
        {
            $add_new_scan_run->(
                AI::Pathfinding::OptimizeMultiple::ScanRun->new(
                    {
                        iters    => $info[ $s->scan_idx() ],
                        scan_idx => $s->scan_idx(),
                    },
                )
            );

            $status = "Solved";
            last SCANS_LOOP;
        }
        else
        {
            if ( $info[ $s->scan_idx() ] > 0 )
            {
                $info[ $s->scan_idx() ] -= $s->iters();
            }

            $add_new_scan_run->(
                AI::Pathfinding::OptimizeMultiple::ScanRun->new(
                    {
                        iters    => $s->iters(),
                        scan_idx => $s->scan_idx(),
                    },
                )
            );
        }
    }

    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;
}

1;    # End of AI::Pathfinding::OptimizeMultiple

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple.pm  view on Meta::CPAN


AI::Pathfinding::OptimizeMultiple - optimize path finding searches for a large
set of initial conditions (for better average performance).

=head1 VERSION

version 0.0.17

=head1 SYNOPSIS

    use AI::Pathfinding::OptimizeMultiple

    my @scans =
    (
        {
            name => "first_search"
        },
        {
            name => "second_search",
        },
        {
            name => "third_search",
        },
    );

    my $obj = AI::Pathfinding::OptimizeMultiple->new(
        {
            scans => \@scans,
            num_boards => 32_000,
            optimize_for => 'speed',
            scans_iters_pdls =>
            {
                first_search => $first_search_pdl,
                second_search => $second_search_pdl,
            },
            quotas => [400, 300, 200],
            selected_scans =>
            [
                AI::Pathfinding::OptimizeMultiple::Scan->new(
                    id => 'first_search',
                    cmd_line => "--preset first_search",
                ),
                AI::Pathfinding::OptimizeMultiple::Scan->new(
                    id => 'second_search',
                    cmd_line => "--preset second_search",
                ),
                AI::Pathfinding::OptimizeMultiple::Scan->new(
                    id => 'third_search',
                    cmd_line => "--preset third_search",
                ),
            ],
        }
    );

    $obj->calc_meta_scan();

    foreach my $scan_alloc (@{$self->chosen_scans()})
    {
        printf "Run %s for %d iterations.\n",
            $scans[$scan_alloc->scan_idx], $scan_alloc->iters;
    }

=head1 DESCRIPTION

This CPAN distribution implements the algorithm described here:

=over 4

=item * L<https://groups.google.com/group/comp.ai.games/msg/41e899e9beea5583?dmode=source&output=gplain&noredirect>

=item * L<http://www.shlomifish.org/lecture/Perl/Lightning/Opt-Multi-Task-in-PDL/>

lib/AI/Pathfinding/OptimizeMultiple.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

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;
    my $quotas_are_cb        = 0;
    my $optimize_for         = "speed";
    my $offset_quotas        = 0;
    my $simulate_to          = undef;
    my $_add_horne_prune     = 0;
    my $input_obj_class = 'AI::Pathfinding::OptimizeMultiple::DataInputObj';
    my %stats_factors;

    my $help = 0;
    my $man  = 0;
    GetOptionsFromArray(
        $self->argv(),
        'help|h'          => \$help,
        man               => \$man,
        "o|output=s"      => \$output_filename,
        "num-boards=i"    => \$num_boards,
        "trace"           => \$should_trace_be_done,
        "rle!"            => \$should_rle_be_done,
        "start-board=i"   => \$_start_board,
        "quotas-expr=s"   => \$_quotas_expr,
        "quotas-are-cb"   => \$quotas_are_cb,
        "offset-quotas"   => \$offset_quotas,
        "opt-for=s"       => \$optimize_for,
        "simulate-to=s"   => \$simulate_to,
        "sprtf"           => \$_add_horne_prune,
        "input-class=s"   => \$input_obj_class,
        "stats-factors=f" => \%stats_factors,
    ) or die "Extracting options from ARGV array failed - $!";

    if ($help)
    {
        $self->_should_exit_immediately(1);
        print <<"EOF";
$0 - optimize a game AI multi-tasking configuration

--help | -h - displays this help screen
--output=[filename] | -o [filename] - output to this file instead of STDOUT.
EOF
        return;
    }

    $self->_start_board($_start_board);
    $self->_num_boards($num_boards);
    $self->_output_filename($output_filename);
    $self->_should_trace_be_done($should_trace_be_done);
    $self->_should_rle_be_done($should_rle_be_done);
    $self->_quotas_expr($_quotas_expr);
    $self->_quotas_are_cb($quotas_are_cb);
    $self->_optimize_for($optimize_for);
    $self->_offset_quotas($offset_quotas);
    $self->_simulate_to($simulate_to);
    $self->_add_horne_prune($_add_horne_prune);
    $self->_stats_factors( \%stats_factors );
    $self->input_obj_class($input_obj_class);

    {
        my $class = $self->input_obj_class();
        if ( $class !~ m{\A$_module_re\z} )
        {
            Carp::confess(
                "Input object class does not seem like a good class:"
                    . $self->input_obj_class() );
        }
        eval "require $class;";
        if ($@)
        {
            die "Could not load '$class' - <<$@>>";
        }

        # TODO : Restore later.
        $self->_input_obj(
            $class->new(
                {
                    start_board => $self->_start_board(),
                    num_boards  => $self->_num_boards(),
                }
            )
        );
    }

    $self->_post_processor(
        AI::Pathfinding::OptimizeMultiple::PostProcessor->new(
            {
                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
                # scan sub-optimal.
                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() },
                ],
                'quotas'           => $self->_get_quotas(),
                'selected_scans'   => $self->_selected_scans(),
                '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();

    my $scans =
        $self->_post_processor->process( $self->_arbitrator->chosen_scans() );

    $self->_chosen_scans($scans);
    $self->_report_total_iters();
    $self->_write_script();
    $self->_do_trace();
    $self->_do_simulation();

    return 0;
}

1;

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm  view on Meta::CPAN

use File::Path qw(mkpath);

use AI::Pathfinding::OptimizeMultiple::Scan ();

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 = {};

    my $data_dir = ".data-proc";
    my $lens_dir = ".data-len-proc";

    mkpath( [ $data_dir, $lens_dir ] );

    foreach my $scan (@$selected_scans)
    {
        {
            my $dest_path = $data_dir . "/" . $scan->id();
            {
                if (
                    $self->_should_update(
                        $scan->data_file_path(), $dest_path
                    )
                    )
                {
                    my $data_s = _slurp( $scan->data_file_path() );
                    my @array  = unpack( "l*", $data_s );
                    if (   ( $array[$HEADER_START_BOARD_IDX] != 1 )
                        || ( $array[$HEADER_NUM_BOARDS] < $self->num_boards ) )
                    {
                        die "Incorrect file format in scan "
                            . $scan->{'id'} . "!\n";
                    }

                    my $c = pdl( \@array );

                    writefraw( $c, $dest_path );
                }
            }
            {
                my $start_idx = $NUM_NUMBERS_IN_HEADER + ( $start_board - 1 );
                my $scan_vec  = readfraw($dest_path);
                $scans_data->{ $scan->id() } =
                    $scan_vec->slice( $start_idx . ":"
                        . ( $start_idx + $self->num_boards() - 1 ) );
            }
        }
        {
            my $src  = $scan->data_file_path();
            my $dest = "$lens_dir/" . $scan->id();

            if ( $self->_should_update( $src, $dest ) )
            {
                my $data_s = _slurp($src);

                my @iters = unpack( "l*", $data_s );
                if ( ( $iters[0] != 1 ) || ( $iters[1] < $self->num_boards() ) )
                {
                    die "Incorrect file format in scan " . $scan->id() . "!\n";
                }

                # Remove the header
                splice @iters, 0, $NUM_NUMBERS_IN_HEADER;

                my $c = pdl(
                    [
                        \@iters,
                        $self->_read_text_ints_file(
                            "data/" . $scan->id() . ".fcs.moves.txt"
                        ),
                        $self->_read_text_ints_file(
                            "data/" . $scan->id() . ".fcpro.moves.txt"
                        ),
                    ]
                );

                writefraw( $c, $dest );
            }
            {
                my $scan_vec = readfraw($dest);
                $scans_lens_data->{ $scan->id() } = $scan_vec->slice(
                    sprintf( "%d:%d,:,*",
                        ( $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> )
    {
        chomp($line);
        my ( $id, $cmd_line ) = split( /\t/, $line );
        push @scans,
            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;
    $id = <$in>;
    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'} )
        ? ( "--freecells-num", $args->{'freecells_num'} )
        : ()
    );
    my @variant = (
        exists( $args->{'variant'} )
        ? ( "--variant", $args->{'variant'} )
        : ()
    );

    return [
        qw(freecell-solver-fc-pro-range-solve),
        $min_board,
        $max_board,
        "20",
        @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);

    open my $from_cmd, "-|", @$cmd_line
        or die "Could not start '@$cmd_line'";
    open my $fcs_out,    ">", "data/$id.fcs.moves.txt";
    open my $fc_pro_out, ">", "data/$id.fcpro.moves.txt";
    $fcs_out->autoflush(1);
    $fc_pro_out->autoflush(1);
    while ( my $line = <$from_cmd> )
    {
        print $line;
        chomp($line);
        if ( $line =~ m{\A\[\[Num FCS Moves\]\]=(.*)\z}o )
        {
            print {$fcs_out} "$1\n";
        }
        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;
}

1;

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/IterState.pm  view on Meta::CPAN

use 5.012;

use MooX qw/late/;

use PDL ();

use vars (qw(@fields));

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(
        PDL::sum( ( ( $r <= $state->_quota() ) & ( $r > 0 ) ) * $r ) );

    # Find all the states that weren't solved.
    my $indexes = PDL::which( ( $r > $state->_quota() ) | ( $r < 0 ) );

    # Add the iterations for all the states that have not been solved
    # 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;
}

1;

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/IterState.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm  view on Meta::CPAN

package AI::Pathfinding::OptimizeMultiple::PostProcessor;
$AI::Pathfinding::OptimizeMultiple::PostProcessor::VERSION = '0.0.17';
use strict;
use warnings;

use 5.012;

use MooX qw/late/;

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) )
    {
        if ( $next_scan->scan_idx() == $scan->scan_idx() )
        {
            $scan->iters( $scan->iters() + $next_scan->iters() );
        }
        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 )
    {
        $scans = [
            map {
                my $ret = $_->clone();
                $ret->iters( $ret->iters() + 1 );
                $ret;
            } @$scans
        ];
    }

    if ( $self->_should_do_rle )
    {
        $scans = $self->scans_rle($scans);
    }

    return $scans;
}

1;

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/Scan.pm  view on Meta::CPAN

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__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/Scan.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm  view on Meta::CPAN


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(),
        }
    );
}

1;    # End of AI::Pathfinding::OptimizeMultiple::ScanRun;

__END__

=pod

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm  view on Meta::CPAN


AI::Pathfinding::OptimizeMultiple::ScanRun - running scan_idx for certain
iterations.

=head1 VERSION

version 0.0.17

=head1 SYNOPSIS

    printf "Run %s for %d iterations.\n",
        $scans[$scan_alloc->scan_idx], $scan_alloc->iters;

=head1 DESCRIPTION

A class for scan iterations.

=head1 SLOTS

=head2 $scan_run->scan_idx()

The index of the scan (not the ID/name).

lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm  view on Meta::CPAN

use strict;
use warnings;

use 5.012;

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

=encoding UTF-8

lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm  view on Meta::CPAN

progress on the request by the system.

=head2 Source Code

The code is open to the world, and available for you to hack on. Please feel free to browse it and play
with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
from your repository :)

L<http://github.com/shlomif/fc-solve>

  git clone ssh://git@github.com/shlomif/fc-solve.git

=head1 AUTHOR

Shlomi Fish <shlomif@cpan.org>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/shlomif/fc-solve/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2012 by Shlomi Fish.

This is free software, licensed under:

  The MIT (X11) License

=cut

rejects.pod  view on Meta::CPAN

=head1 BUGS

Please report any bugs or feature requests to C<bug-ai-pathfinding-optimizemultiple at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=AI-Pathfinding-OptimizeMultiple>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc AI::Pathfinding::OptimizeMultiple

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Games-AI-Pathfinding-OptimizeMultiple>

=item * CPAN Ratings

t/00-compile.t  view on Meta::CPAN

use strict;
use warnings;

# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.058

use Test::More;

plan tests => 9 + ($ENV{AUTHOR_TESTING} ? 1 : 0);

my @module_files = (
    'AI/Pathfinding/OptimizeMultiple.pm',
    'AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm',
    'AI/Pathfinding/OptimizeMultiple/DataInputObj.pm',
    'AI/Pathfinding/OptimizeMultiple/IterState.pm',
    'AI/Pathfinding/OptimizeMultiple/PostProcessor.pm',
    'AI/Pathfinding/OptimizeMultiple/Scan.pm',
    'AI/Pathfinding/OptimizeMultiple/ScanRun.pm',
    'AI/Pathfinding/OptimizeMultiple/SimulationResults.pm'
);

my @scripts = (
    'bin/optimize-game-ai-multi-tasking'
);

# no fake home requested

my @switches = (
    -d 'blib' ? '-Mblib' : '-Ilib',
);

use File::Spec;
use IPC::Open3;
use IO::Handle;

open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";

my @warnings;
for my $lib (@module_files)
{
    # see L<perlfaq8/How can I capture STDERR from an external command?>
    my $stderr = IO::Handle->new;

    diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} }
            $^X, @switches, '-e', "require q[$lib]"))
        if $ENV{PERL_COMPILE_TEST_DEBUG};

    my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-e', "require q[$lib]");
    binmode $stderr, ':crlf' if $^O eq 'MSWin32';
    my @_warnings = <$stderr>;
    waitpid($pid, 0);
    is($?, 0, "$lib loaded ok");

    shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/
        and not eval { +require blib; blib->VERSION('1.01') };

    if (@_warnings)
    {
        warn @_warnings;
        push @warnings, @_warnings;
    }
}

foreach my $file (@scripts)
{ SKIP: {
    open my $fh, '<', $file or warn("Unable to open $file: $!"), next;
    my $line = <$fh>;

    close $fh and skip("$file isn't perl", 1) unless $line =~ /^#!\s*(?:\S*perl\S*)((?:\s+-\w*)*)(?:\s*#.*)?$/;
    @switches = (@switches, split(' ', $1)) if $1;

    close $fh and skip("$file uses -T; not testable with PERL5LIB", 1)
        if grep { $_ eq '-T' } @switches and $ENV{PERL5LIB};

    my $stderr = IO::Handle->new;

    diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} }
            $^X, @switches, '-c', $file))
        if $ENV{PERL_COMPILE_TEST_DEBUG};

    my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-c', $file);
    binmode $stderr, ':crlf' if $^O eq 'MSWin32';
    my @_warnings = <$stderr>;
    waitpid($pid, 0);
    is($?, 0, "$file compiled ok");

    shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/
        and not eval { +require blib; blib->VERSION('1.01') };

    # in older perls, -c output is simply the file portion of the path being tested
    if (@_warnings = grep { !/\bsyntax OK$/ }
        grep { chomp; $_ ne (File::Spec->splitpath($file))[2] } @_warnings)
    {
        warn @_warnings;
        push @warnings, @_warnings;
    }
} }



is(scalar(@warnings), 0, 'no warnings found')
    or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ) if $ENV{AUTHOR_TESTING};


t/cmdline-app.t  view on Meta::CPAN

use Test::More;
use AI::Pathfinding::OptimizeMultiple::App::CmdLine ();

use vars qw($trap);

eval
q{use Test::Trap qw( trap $trap :flow:stderr(systemsafe):stdout(systemsafe):warn );};

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,
        "stdout matches --output flag. ($blurb_base)",
    );

    # TEST*$num_subs
    ok( scalar( !$trap->die ), "No exception was thrown. ($blurb_base)", );
}

t/optimize-multiple-full-test.t  view on Meta::CPAN


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 {
            my $id = $_->{name};

            AI::Pathfinding::OptimizeMultiple::Scan->new(
                id       => $id,
                cmd_line => "-l $id",
            )
        } @{$scans_aref},
    ];

    my %num_boards = ( map { scalar( @{ $_->{data} } ) => 1 } @$scans_aref );

    my @nums = keys(%num_boards);
    if ( @nums != 1 )
    {
        Carp::confess("num is not 1.");
    }

    my $obj = AI::Pathfinding::OptimizeMultiple->new(
        {
            scans      => [ map { +{ name => $_->{name} } } @$scans_aref, ],
            num_boards => $nums[0],
            scans_iters_pdls =>
                { map { $_->{name} => pdl( $_->{data} ), } @$scans_aref, },
            quotas         => $quotas_aref,
            selected_scans => $selected_scans,
            optimize_for   => "speed",
            ( $stats_factors ? ( stats_factors => $stats_factors ) : () ),
        }
    );

    $obj->calc_meta_scan();

    my @have = (
        map {
            +{
                name  => $scans_aref->[ $_->scan_idx ]->{name},
                iters => $_->iters,
            }
        } @{ $obj->chosen_scans() }
    );

    # TEST:$c++;
    return eq_or_diff( \@have, $want_results, "$blurb - (eq_or_diff)", );
}

# TEST:$test_based_on_data=$c;

{
    # TEST*$test_based_on_data
    test_based_on_data(
        [
            {
                name => "first",
                data => [ 200, 400, 500 ],
            },
            {
                name => "second",
                data => [ 300, 50, 1000 ],
            },
            {
                name => "third",
                data => [ 10, 10, 100000 ],
            },
        ],
        [ 200, 500, ],
        [
            {
                name  => "third",
                iters => 200,
            },
            {
                name  => "first",
                iters => 500,
            },
        ],
        undef(),
        'Basic test',
    );
}

{
    # TEST*$test_based_on_data
    test_based_on_data(
        [
            {
                name => "first",
                data => [ 50_000, 100_000, 100_000, 1_000_000, 2_000_000 ],
            },
            {
                name => "second",
                data => [ 100, 200, 200, 300, 300 ],
            },
            {
                name => "third",
                data => [ 2000, 2000, 2000, 2000, 2000 ],
            },
        ],
        [ 100, 300, ],
        [
            {
                name  => "first",
                iters => 100_000,
            },
            {
                name  => "second",
                iters => 300,
            },
        ],
        {
            first => 1000,
        },
        'Test the stats_factors',
    );
}

{
    # TEST*$test_based_on_data
    test_based_on_data(
        [
            {
                name => "first",
                data => [ 50_000, 99_500, 100_000, 1_000_000, 2_000_000 ],
            },
            {
                name => "second",
                data => [ 100, 200, 200, 300, 300 ],
            },
            {
                name => "third",
                data => [ 2000, 2000, 2000, 2000, 2000 ],
            },
        ],
        [ 100, 300, ],
        [
            {
                name  => "first",
                iters => 100_000,
            },
            {
                name  => "second",
                iters => 300,
            },
        ],
        {
            first => 1000,
        },
        'Test fractional stats due to stats_factors',
    );
}

{
    # TEST*$test_based_on_data
    test_based_on_data(
        [
            {
                name => "first",
                data => [ 50_000, 99_500, 100_000, -1, -1, ],
            },
            {
                name => "second",
                data => [ 100, 200, 200, 300, 300 ],
            },
            {
                name => "third",
                data => [ 2000, 2000, 2000, 2000, 2000 ],
            },
        ],
        [ 100, 300, ],
        [
            {
                name  => "first",
                iters => 100_000,
            },
            {
                name  => "second",
                iters => 300,
            },
        ],
        {
            first => 1000,
        },
        'Test negative stats due to stats_factors',
    );
}

t/style-trailing-space.t  view on Meta::CPAN

#!/usr/bin/perl

use strict;
use warnings;

use Test::More;

eval "use Test::TrailingSpace";
if ($@)
{
    plan skip_all => "Test::TrailingSpace required for trailing space test.";
}
else
{
    plan tests => 1;
}

my $finder = Test::TrailingSpace->new(
    {
        root           => '.',
        filename_regex =>
qr/(?:(?:\.(?:t|pm|pl|PL|yml|json|arc|vim))|README|Changes|LICENSE)\z/,
    },
);

# TEST
$finder->no_trailing_space("No trailing space was found.");

xt/author/eol.t  view on Meta::CPAN

use strict;
use warnings;

# this test was generated with Dist::Zilla::Plugin::Test::EOL 0.19

use Test::More 0.88;
use Test::EOL;

my @files = (
    'bin/optimize-game-ai-multi-tasking',
    'lib/AI/Pathfinding/OptimizeMultiple.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/IterState.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/Scan.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm',
    't/00-compile.t',
    't/cmdline-app.t',
    't/optimize-multiple-full-test.t',
    't/style-trailing-space.t'
);

eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files;
done_testing;

xt/author/no-tabs.t  view on Meta::CPAN

use strict;
use warnings;

# this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.15

use Test::More 0.88;
use Test::NoTabs;

my @files = (
    'bin/optimize-game-ai-multi-tasking',
    'lib/AI/Pathfinding/OptimizeMultiple.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/IterState.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/PostProcessor.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/Scan.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/ScanRun.pm',
    'lib/AI/Pathfinding/OptimizeMultiple/SimulationResults.pm',
    't/00-compile.t',
    't/cmdline-app.t',
    't/optimize-multiple-full-test.t',
    't/style-trailing-space.t'
);

notabs_ok($_) foreach @files;
done_testing;

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');
};

xt/release/trailing-space.t  view on Meta::CPAN

#!perl

use strict;
use warnings;

use Test::More;

eval "use Test::TrailingSpace";
if ($@)
{
   plan skip_all => "Test::TrailingSpace required for trailing space test.";
}
else
{
   plan tests => 1;
}

# TODO: add .pod, .PL, the README/Changes/TODO/etc. documents and possibly
# some other stuff.
my $finder = Test::TrailingSpace->new(
   {
       root => '.',
       filename_regex => qr#(?:\.(?:t|pm|pl|xs|c|h|txt|pod|PL)|README|Changes|TODO|LICENSE)\z#,
   },
);

# TEST
$finder->no_trailing_space(
   "No trailing space was found."
);



( run in 0.387 second using v1.01-cache-2.11-cpan-4d50c553e7e )