Ever been a lone wanderer solely surviving in the Commonwealth Wasteland only to have some random asshole raider start taking potshots at you? Well I have!

To make matters worse Bon Jovi showed up out of nowhere at the most inopportune moment  seemingly just to mock my hasty strategic withdrawal!

I used my last stimpak as I staggered through the door of my Red Rocket workshop where Dogmeat and Codsworth were waiting for me.

I changed then ate some ramen, Takahashi always makes the best pulled noodles!

I stared into the radstorm raging outside my window and in that moment I vowed:

Never again would Bon Jovi mock my pain!”

~GeekGirlJoy

I needed to build a new kind of bot and this time “General Atomics Finest” just wouldn’t cut it!

No, I needed a neural network that could monitor my vitals and automatically heal me as soon as I started taking damage!

Brief Q&A

“Isn’t managing health kinda part of the game?”

~You

Normally, yes though as I have said I am committed to never experiencing shame at the hands of Bon Jovi again!

I needed a way to ensure that the next time I crossed paths with that raider the tables would be turned.

“OK?… But you realize there is “Legendary Armor” already available in game that has an “auto stim” effect, right? Why not use that? Is this just an indolent attempt to show off?”

~You

In order:

Yes I do.

Because… well to be honest I’ve never seen an item with that effect actually drop, I could use “console commands” but… that’s not fun!

And no… well okay maybe a little. 😛

The thing is, as cool as a proof of concept “auto doc” neural network that can auto heal your health and rads is (totally what we’re building today!)… it’s not really the “end goal” assuming you can say there is one… and assuming we even get there. 😛

Basically, It would amuse me to no end to see a bot emerge from Vault 111 and enter the Commonwealth as a blank slate, kinda like Nate/Nora.

Then using evolutionary algorithms, shape the bot as a result of it’s experiences in the Fallout 4 world.

Which leads me to ask:

  • Could we actually build a bot that can learn to play Fallout 4?
  • Which faction would it decide to align with?
  • Would it be able to learn how to use the merchants and manage it’s inventory?
  • Could it use the Settlement & Automatron systems?
  • If it chose to have a companion, would it always pick Nick Valentine out of solidarity?
  • Would it just randomly wander the wasteland murdering everything in it’s path?

Admit it, a little part of you would be tickled pink to see it do even just that last one, huh?! 😉 😛

I would love to explore the answers to these questions and more, so leave a like and comment on this post so I know this is the kind of thing you want me to work on otherwise I might just spend all my time telling stories and making art… the choice is up to you!

If there is enough interest from my readers we might try building something more complicated.

“Damn that’s wonderful Joy! So… you’re really going to release all this amazing code for free?”

~You

Yeah… I should probably just get on with it so you don’t convince me to charge you! 😛

By the end of this post you will have a neural network capable of:

  1. Monitoring your health from a screenshot.
  2. Evaluating the state of the health bar.
  3. Replying with a yes or no if a RadAway and or StimPak should be used.

The thing is, by itself this code does not directly interface with Fallout 4 and requires a “bridge” application.

Basically what the “bridge” does is handle communications between the game and the neural network.

Bridge Application Process:

  1. Take screenshot during game play on an interval.
  2. Upload the screenshot to the server running the neural network.
  3. Receive ANN response then decide if RadAway and StimPaks are needed.
  4. If yes, “send/press keys” that will activate hotkey bindings for each.
  5. Repeat until disabled.

Here’s a screenshot of my implementation of the bridge:

A screenshot of the Bridge Application
A screenshot of the Bridge Application

This is for my internal use and though I seriously considered it, I will not be releasing the bridge application with the neural network.

“Why not? Is this just so you can get people to signup on Patreon? ”

~You

No, my reasoning boils down to two considerations:

First, PLEASE, PLEASE, PLEASE BETHESDA… DON’T SUE ME! 😛

Which should need no further explanation though I will say this:

Todd Howard, you are not sponsoring this fine content but it’s totally positive fan generated advertising for the Fallout brand and it didn’t even cost you a cent… so um… I have a Patreon, just saying.

Send what you like Bethesda, cancel any time! 😉

 

Second, this neural network by itself is an excellent learning project and without the bridge application it operates in a harmless, sort of “one off” event where it evaluates a single screenshot and returns a couple of benign numbers as text that you can experiment with manually by comparing the output with the image and your own judgment if healing is required.

With the bridge it potentially becomes a “cheaters blunderbuss”, despite requiring a fairly high level of technical expertise to deploy and operate.

This is because I built and tested the neural network with Fallout 4, a single player game that I own, however Fallout 76 is an online multiplayer game which uses a similar if not identical health bar and it may be possible to use my Fallout 4 “AutoDoc” ANN with little to no modification on FO76.

This is NOT it’s intended purpose and obviously that would be cheating.

To be clear, I do not support cheating in multiplayer games!

The difference is very simple, using this bot with FO4 is a fun experiment. Using this bot with FO76 would be an unfair advantage and in my eyes is a legitimate reason for Bethesda to ban your cheating ass!

Though, it would likely be impossible for them to detect a bot like this on their end… well actually I can still think of a way that Bethesda could detect it, but none the less…

Out of respect for the Fallout 76 playerbase and as a professional courtesy to Bethesda I have decided not to release the bridge even to my paying Patreon subscribers.

I am sorry if this upsets you though I am publicly releasing everything else!

You will be able to test it with your own screenshots and even add more training if you want… or start over from scratch with your own dataset and images with some modification.

Besides, any sufficiently capable programmer can write a working version of the bridge though definitely not as elegantly as I have! 😉

Step 1 – Collecting The Raw Training Data

To get started, here is a screenshot of me playing Fallout 4, notice the healthbar in the bottom left corner of the screen.

Here is the full size healthbar extracted from this image:

The green represents your health.

If the entire bar is green then you are at 100% “max health”.

The red represents your “rad” (radiation) level and acts as a “debuff” preventing you from having max health.

The more radiation you receive the less health you can have and you are unable to restore your health fully until you deal with your radiation.

Left unchecked the red will fill up from right to left until you have no remaining ability to heal.

Player death occurs when the green health and or the red rads completely reach the left side of the bar.

Do you see a problem? I do!

See how Bethesda used a transparent space rather than an solid neutral color under the healthbar?

If Bethesda had used a single solid color underneath I could have easily taken a single screenshot and generated about a dozen training examples by hand and been done.

Because the area underneath and between health and “rad damage” is transparent, it is hypothetically possible to look at something green or red and confuse the neural network.

Additionally, there are screens and menus where the healthbar doesn’t show on screen at all or in a modified way and we want the ANN to figure out that just because there is no green healthbar on screen that it shouldn’t continuously spam the stimpak and radaway hotkeys.

Because of these complications… extra care had to be taken to create a training dataset (lots of running around in game while the bridge recorded me playing) that would include examples of as many of the different in game interior and exterior locations under various lighting and weather conditions while my character suffered various levels of health and radiation damage, which provides the bot (hopefully) better insight into how to distinguish red and green colors it should ignore in any of the “unhealed” transparent area.

Step 2 – Preparing The Screenshots

Once I had all my screenshots I wrote the ExtractHealthBars.php script.

It takes all the available full size screenshots and crops them to just the healthbar like the example above and saves them as a separate image.

ExtractHealthBars.php
<?php
// Input: Image is a screenshot 1280x800 px
// Output: Is cropped image 203x5 px
function ExtractHealthbarFromScreenshot(&$source_im){
    $x1 = 95;
    $y1 = 725;
    $x2 = 298 - $x1;
    $x2 = 298 - $x1;
    $y2 = 730 - $y1; // 733 whole thing
    return imagecrop($source_im, array('x' => 95, 'y' => 725, 'width' => $x2, 'height' => $y2));
}
$directory = "screenshots";
$screenshot_images = glob(__DIR__ . DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR . "*.jpg");
foreach($screenshot_images as $image)
{    
    $health_bar = imagecreatefromjpeg($image);
    $health_bar = ExtractHealthbarFromScreenshot($health_bar);
    imageJPEG($health_bar, "$image.HealthBar.jpg");
}

 

Step 3 – Tagging The Data

Once I had all my raw screenshots converted into healthbar images, I wrote TagHealthBars.php as a a tool to help tag the data easily.

This script can be run on a standard LAMP/WAMP server (no MySQL required).

It is a dynamically generated HTML form.

A screenshot of TagHealthBars.php
A screenshot of TagHealthBars.php

 

You check Stimpack and or Radaway if you believe either is appropriate for that healthbar image and at the very end you click submit.

TagHealthBars.php
<?php
$directory = "screenshots";
$screenshot_images = glob(__DIR__ . DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR . "*.HealthBar.jpg");
$output = '';
foreach($screenshot_images as $imgnum=>$image){
    $output .= "<h4>$imgnum</h4>";
    $output .= "<img src='$directory/" . basename($image) . "'><br>";
    $output .= "<input type='checkbox' name='$imgnum-stim' value='1'> Stimpack<br>";
    $output .= "<input type='checkbox' name='$imgnum-rad' value='1'> Radaway<br>";
    $output .= "<hr/>";
}
?>
<html>
<head>
</head>
<body>
    <form action="LogHealthbarTags.php" method="post">
      <?php echo $output; ?>
      <input type="submit" value="Submit">
    </form> 
</body>
</html>

 

Once you click submit the form posts your answers to LogHealthbarTags.php which saves all your answers to a file named HealthBar_Raw_States.txt.

The format is: ImageName Stimpak RadAway

As for the tag states, Yes is recorded as a 1 and No as a -1

Example:

image_1.jpg -1 -1
image_2.jpg -1 1
image_3.jpg 1 -1
image_4.jpg 1 1

LogHealthbarTags.php
<?php
$directory = "screenshots";
$screenshot_images = glob(__DIR__ . DIRECTORY_SEPARATOR . $directory . DIRECTORY_SEPARATOR . "*.HealthBar.jpg");
$output = '';
foreach($screenshot_images as $imgnum=>$image){        
    // Post data and determine values
    if(isset($_POST["$imgnum-stim"])){
        $stim = $_POST["$imgnum-stim"];
    }
    else{
        $stim = -1;
    }
    if(isset($_POST["$imgnum-rad"])){
       $rad = $_POST["$imgnum-rad"];
    }
    else{
       $rad = -1;
    }
    // Generate states output e.g.:
    // image.jpg -1 -1
    // image.jpg -1 1
    // image.jpg 1 -1
    // image.jpg 1 1
    $states = '';
    if ($stim == '1'){
        $states .= '1 ';
    }
    else{
        $states .= '-1 ';
    }
    if($rad == '1'){
        $states .= '1';
    }
    else{
        $states .= '-1';
    }
    $output .= basename($image) . " $states" . PHP_EOL;
}
$file = fopen('HealthBar_Raw_States.txt', 'w');
fwrite($file, $output);
fclose($file);
echo "All Done!";

 

Step 4 – Merge Pixel Data With Training Data

Here’s were things start getting serious. Basically what this step does is complete the process of generating a .data training file for our screenshots and after this point we’ll be elbow deep inside a bot! 😛

The basic process is:

  1. Using HealthBar_Raw_States.txt generated in the last step as a reference… Load each image.
  2. Split RGB Color Channels into separate image resources.
  3. Convolve using an image “kernel filter” to “detect the edges” on each channel.
  4. “Max Pool” (selectively down-sample) the image to find the “most important/brightest” pixels which reduces the image size leading to a bot that requires less resources to work.
  5. “Flatten” the images by converting the 2 dimensional image from Width x Height to an 1 dimensional array of floating point values.
  6. Merge the image data with the tag data and concatenate onto a string called $training_data.
  7. Once steps 1-6 have been completed for all the images, save the training data as a .data file.

I will likely cover “pooling” and image “kernel convolution” in greater depth in future posts separately so I’ve neglected to cover the details and reasoning for these processes here due to length and complexity.

HealthBarsPixelsToTraningData.php
<?php
define("RED",    0);
define("GREEN",    1);
define("BLUE",    2);
function MaxPool(&$img){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    // Determine the size of the pool image.
    $max_pool_img_width = $width / 2;
    while(($max_pool_img_width % 2)>0){ 
        $max_pool_img_width++;// if it wont evenly divide into 2... enlarge
    }
    $max_pool_img_height = $height / 2;
    while(($max_pool_img_height % 2)>0){
        $max_pool_img_height++;// if it wont evenly divide into 2... enlarge
    }
     
    // Allocate resource in memory for the image
    $max_pool_img = imagecreatetruecolor($max_pool_img_width, $max_pool_img_height);
    $background = imagecolorallocate($max_pool_img, 0, 0, 0);
    $max_row = 0;
    $max_col = 0;
    // Max Pooling
    for($row = 0; $row < $width; $row += 2){
        for($col = 0; $col < $height; $col+= 2){
            //    C0   C1   C2 
            //R0 [p1] [p2] [..]
            //R1 [p3] [p4] [..]
            //R2 [..] [..] [..]
            
            // Get color
            $p1 = @imagecolorat($img, $row, $col);
            // R+G+B
            $p1_r = ($p1 >> 16) & 0xFF;
            $p1_g = ($p1 >> 8) & 0xFF;
            $p1_b = $p1 & 0xFF;
            $p1_color = $p1_r + $p1_g + $p1_b;
            
            // Get color
            $p2 = @imagecolorat($img, $row, $col+1);
            // R+G+B
            $p2_r = ($p2 >> 16) & 0xFF;
            $p2_g = ($p2 >> 8) & 0xFF;
            $p2_b = $p2 & 0xFF;
            $p2_color = $p2_r + $p2_g + $p2_b;
            
            // Get color
            $p3 = @imagecolorat($img, $row+1, $col);
            // R+G+B
            $p3_r = ($p3 >> 16) & 0xFF;
            $p3_g = ($p3 >> 8) & 0xFF;
            $p3_b = $p3 & 0xFF;
            $p3_color = $p3_r + $p3_g + $p3_b;
            
            // Get color
            $p4 = @imagecolorat($img, $row+1, $col+1);
            // R+G+B
            $p4_r = ($p4 >> 16) & 0xFF;
            $p4_g = ($p4 >> 8) & 0xFF;
            $p4_b = $p4 & 0xFF;
            $p4_color = $p4_r + $p4_g + $p4_b;
            
            $color = $p1;
            // Find the brightest pixel
            $max_pixel = max($p1_color, $p2_color, $p3_color, $p4_color);
            if($max_pixel == $p1_color){
                $color = $p1;
            }
            elseif($max_pixel == $p2_color){
                $color = $p2;
            }
            elseif($max_pixel == $p3_color){
                $color = $p3;
            }
            else{
                $color = $p4;
            }
            // Paint pooled pixel
            imagesetpixel($max_pool_img, $max_row, $max_col, $color);
            $max_col++;
        }
        $max_col = 0;
        $max_row++;
    }
    return $max_pool_img;
}
function Monochrome(&$img, $color_channel){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    
    // Allocate resource in memory for the image
    $monochrome = imagecreatetruecolor($width, $height);
    $background = imagecolorallocate($monochrome, 0, 0, 0);
    
    // Loop through pixels
    for($row = 0; $row < $width; $row++){
        for($col = 0; $col < $height; $col++){
            
            // Get pixel color channels 
            $p = imagecolorat($img, $row, $col);
            $colors = imagecolorsforindex($img, $p);
            
            // Extract desired channel
            if($color_channel == RED){
                $pixelcolor = imagecolorallocate($monochrome, $colors['red'], 0, 0);
            }
            elseif($color_channel == GREEN){
                $pixelcolor = imagecolorallocate($monochrome, 0, $colors['green'], 0);
            }
            elseif($color_channel == BLUE){
                $pixelcolor = imagecolorallocate($monochrome, 0, 0, $colors['blue']);
            }
            else{
                 $pixelcolor = $background;
            }
            
            // Change pixel to contain pure channel
            imagesetpixel($monochrome, $row, $col, $pixelcolor);
        }
    }
    return $monochrome;
}
// Take an image with height and width and return 
// an array of floats for the desired color channel
function Flatten(&$img, $color_channel){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    // the flattened pixel data is stored here
    $pixels = array();
    
    // Loop through pixels
    for($row = 0; $row < $width; $row++){
        for($col = 0; $col < $height; $col++){
            
            // Get pixel color channels 
            $p = imagecolorat($img, $row, $col);
            $colors = imagecolorsforindex($img, $p);
            // Extract desired channel
            if($color_channel == RED){
                $pixels[] = ColorToFloat($colors['red']);
            }
            elseif($color_channel == GREEN){
                $pixels[] = ColorToFloat($colors['green']);
            }
            elseif($color_channel == BLUE){
                $pixels[] = ColorToFloat($colors['blue']);
            }
            else{
                 $pixels[] = 0.00;
            }
        }
    }
        
    return $pixels;
}
function ExtractHealthbarFromScreenshot(&$source_im){
    $x1 = 95;
    $y1 = 725;
    $x2 = 298 - $x1;
    $x2 = 298 - $x1;
    $y2 = 730 - $y1; // 733 whole thing
    return imagecrop($source_im, ['x' => 95, 'y' => 725, 'width' => $x2, 'height' => $y2]);
}
// example will echo 0 - 255
//for($i = 0; $i <= 255; $i++){
//    echo $i . ' ' . ColorToFloat($i) . PHP_EOL;
//}
function ColorToFloat($value)
{
    $max = 255;
    $increment = $max / 100;
    
    return ($value / $increment) / 100;
}
// example will echo 0 - 1
//for($i = 0; $i <= 1; $i+=0.01){
//    echo $i . ' ' . FloatToColor($i) . PHP_EOL;
//}
function FloatToColor($value)
{
    $max = 255;
    $increment = $max / 100;
    
    return round(($value * 100) * $increment);
}
$image_kernel = array(
        array(-1, -1, -1), 
        array(-1, 8, -1), 
        array(-1, -1, -1)
);
// Training batch number for data set
$training_set_batch = 4;
$screenshots = 'screenshots\\';
$filename = "HealthBar_Raw_States.txt"; // Generated by LogHealthbarTags.php
$file = fopen($filename, "r");
$screenshot_images = fread($file, filesize($filename));
fclose($file);
$screenshot_images = explode(PHP_EOL, $screenshot_images);
$i = 0;
foreach($screenshot_images as $data){
    $data = explode(' ', $data);
    @$screenshot_images[$i] = array();
    @$screenshot_images[$i]['file'] = $data[0];
    @$screenshot_images[$i]['stimpack'] = $data[1];
    @$screenshot_images[$i]['radaway'] = $data[2];
    $i++;
}
// Convert images to training data
$training_data = '';
foreach($screenshot_images as &$test_image){
    
    // Load image
    $health_bar_r = imagecreatefromjpeg($screenshots . $test_image['file']);
    
    // Get image size
    $width = imagesx($health_bar_r);
    $height = imagesy($health_bar_r);
    // Create image resources of the correct size
    $health_bar_g = imagecreatetruecolor($width, $height);
    $health_bar_b = imagecreatetruecolor($width, $height);
    // Copy the image to the new image resources
    imagecopy($health_bar_g, $health_bar_r, 0, 0, 0, 0, $width, $height);
    imagecopy($health_bar_b, $health_bar_r, 0, 0, 0, 0, $width, $height);
    // Extract healthbar if the image is full size
    if($width >= 1280 && $height >= 800){
        $health_bar_r = ExtractHealthbarFromScreenshot($health_bar_r);
        $health_bar_g = ExtractHealthbarFromScreenshot($health_bar_g);
        $health_bar_b = ExtractHealthbarFromScreenshot($health_bar_b);
    }
    
    // Split RGB Channels
    $health_bar_r = Monochrome($health_bar_r, RED);
    $health_bar_g = Monochrome($health_bar_g, GREEN);
    $health_bar_b = Monochrome($health_bar_b, BLUE);
    
    // Convolutions
    imageconvolution($health_bar_r, $image_kernel, 1, -1);
    imageconvolution($health_bar_g, $image_kernel, 1, -1);
    imageconvolution($health_bar_b, $image_kernel, 1, -1);
    
    // Pooling
    $health_bar_r = MaxPool($health_bar_r);
    $health_bar_g = MaxPool($health_bar_g);
    $health_bar_b = MaxPool($health_bar_b);
    
    // Save the split channel images if you want
    //imagejpeg($health_bar_r, $screenshots . $test_image . '.HealthBarRconvo.png');
    //imagejpeg($health_bar_g, $screenshots . $test_image . '.HealthBarGconvo.png');
    //imagejpeg($health_bar_b, $screenshots . $test_image . '.HealthBarBconvo.png');
    
    $red_inputs = Flatten($health_bar_r, RED);
    $green_inputs = Flatten($health_bar_g, GREEN);
    $blue_inputs = Flatten($health_bar_b, BLUE);
    
     // Destroy image resources
    imagedestroy($health_bar_r);
    imagedestroy($health_bar_g);
    imagedestroy($health_bar_b);
    
    
    $training_data .= implode(' ', array_merge($red_inputs, $green_inputs, $blue_inputs)) . PHP_EOL . $test_image['stimpack'] . ' ' . $test_image['radaway'] . PHP_EOL;
}
$number_of_training_examples = count($screenshot_images) - 2;
$number_of_inputs = 612;
$number_of_outputs = 2;
// Write Data
$filename = 'Fallout_Bot_HealthBar_Training_Data_' . $training_set_batch . '_Convolutions.data';
$file = fopen($filename, "w");
fwrite($file, "$number_of_training_examples $number_of_inputs $number_of_outputs" . PHP_EOL . $training_data);
fclose($file);

 

Step 5 – Train The Bot

This step is fairly self explanatory but it boils down to the bot learning the data and there really isn’t much to say about it.

I’ve made 2 training files available which contain a subset (2702 training examples) of my complete training set which is more than enough to create a bot that works.

I ran this code many times during my testing and on average it takes about 1000 epochs to learn the merged dataset but the fastest was 408 epochs and the longest was ~1700 epochs so it’s a fairly quick bot to train!

Train.php
<?php
// Training Variables
$desired_error = 0.0003;
$max_epochs = 500000;
$current_epoch = 0;
$epochs_between_saves = 5; // Minimum number of epochs between saves
$epochs_since_last_save = 0;

// Training Data
$data1 = dirname(__FILE__) . "/Fallout_Bot_HealthBar_Training_Data_1_Convolutions.data";
$data2 = dirname(__FILE__) . "/Fallout_Bot_HealthBar_Training_Data_2_Convolutions.data";

// Initialize pseudo mse (mean squared error) to a number greater than the desired_error
// this is what the network is trying to minimize.
$pseudo_mse_result = $desired_error * 10000; // 1
$best_mse = $pseudo_mse_result; // keep the last best seen MSE network score here

// Initialize ANN
$num_input = 612;
$num_output = 2;
$num_neurons_hidden_1 = 8;
$num_neurons_hidden_2 = 6;
$layers = array($num_input, $num_neurons_hidden_1, $num_neurons_hidden_2, $num_output);
$num_layers=count($layers);

// Create ANN
$ann = fann_create_standard_array ($num_layers , $layers);

if ($ann) {
  echo 'Training ANN... ' . PHP_EOL;
 
  // Configure the ANN
  fann_set_training_algorithm ($ann , FANN_TRAIN_RPROP);
  fann_set_activation_function_hidden($ann, FANN_SIGMOID_SYMMETRIC);
  fann_set_activation_function_output($ann, FANN_SIGMOID_SYMMETRIC);
 
  // Read training data
  $train_data_1 = fann_read_train_from_file($data1);
  $train_data_2 = fann_read_train_from_file($data2);
  
  // Merge into new data resource
  $train_data = fann_merge_train_data ($train_data_1, $train_data_2);
  // Remove the partial data resources from memory
  fann_destroy_train ($train_data_1);
  fann_destroy_train ($train_data_2);
 
 
  // Check if pseudo_mse_result is greater than our desired_error
  // if so keep training so long as we are also under max_epochs
  while(($pseudo_mse_result > $desired_error) && ($current_epoch <= $max_epochs)){
  $current_epoch++;
  $epochs_since_last_save++; 
 
  // See: http://php.net/manual/en/function.fann-train-epoch.php
  // Train one epoch
  //
  // One epoch is where all of the training data is considered
  // exactly once.
  //
  // This function returns the MSE error as it is calculated
  // either before or during the actual training. This is not the
  // actual MSE after the training epoch, but since calculating this
  // will require to go through the entire training set once more.
  // It is more than adequate to use this value during training.
  $pseudo_mse_result = fann_train_epoch ($ann , $train_data);
  echo 'Epoch ' . $current_epoch . ' : ' . $pseudo_mse_result . PHP_EOL; // report
   
  // If we haven't saved the ANN in a while...
  // and the current network is better then the previous best network
  // as defined by the current MSE being less than the last best MSE
  // Save it!
  if(($epochs_since_last_save >= $epochs_between_saves) && ($pseudo_mse_result < $best_mse)){
   
    $best_mse = $pseudo_mse_result; // we have a new best_mse
   
    // Save a Snapshot of the ANN
    fann_save($ann, dirname(__FILE__) . "/train.net");
    echo 'Saved ANN.' . PHP_EOL; // report the save
    $epochs_since_last_save = 0; // reset the count
  }
 
  } // While we're training
  echo 'Training Complete! Saving Final Network.'  . PHP_EOL;
 
  // Save the final network
  fann_save($ann, dirname(__FILE__) . "/finished.net"); 
  fann_destroy($ann); // free memory
}
echo 'All Done!' . PHP_EOL;

 

Step 6 – Test The Bot

All that is left to do now is test the bot.

As written the code will test the example image from above.

The result given should be some version of 1 -1, in my case the bot said: 0.99997746944427 -1 which is correct and means yes to a Stimpak and no to a RadAway.

To test your own screenshots you can change the $screenshot variable on line 197 to the name of your image.

Test.php
<?php
define("RED",    0);
define("GREEN",    1);
define("BLUE",    2);
function MaxPool(&$img){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    // Determine the size of the pool image.
    $max_pool_img_width = $width / 2;
    while(($max_pool_img_width % 2)>0){ 
        $max_pool_img_width++;// if it wont evenly divide into 2... enlarge
    }
    $max_pool_img_height = $height / 2;
    while(($max_pool_img_height % 2)>0){
        $max_pool_img_height++;// if it wont evenly divide into 2... enlarge
    }
     
    // Allocate resource in memory for the image
    $max_pool_img = imagecreatetruecolor($max_pool_img_width, $max_pool_img_height);
    $background = imagecolorallocate($max_pool_img, 0, 0, 0);
    $max_row = 0;
    $max_col = 0;
    // Max Pooling
    for($row = 0; $row < $width; $row += 2){
        for($col = 0; $col < $height; $col+= 2){
            //    C0   C1   C2 
            //R0 [p1] [p2] [..]
            //R1 [p3] [p4] [..]
            //R2 [..] [..] [..]
            
            // Get color
            $p1 = @imagecolorat($img, $row, $col);
            // R+G+B
            $p1_r = ($p1 >> 16) & 0xFF;
            $p1_g = ($p1 >> 8) & 0xFF;
            $p1_b = $p1 & 0xFF;
            $p1_color = $p1_r + $p1_g + $p1_b;
            
            // Get color
            $p2 = @imagecolorat($img, $row, $col+1);
            // R+G+B
            $p2_r = ($p2 >> 16) & 0xFF;
            $p2_g = ($p2 >> 8) & 0xFF;
            $p2_b = $p2 & 0xFF;
            $p2_color = $p2_r + $p2_g + $p2_b;
            
            // Get color
            $p3 = @imagecolorat($img, $row+1, $col);
            // R+G+B
            $p3_r = ($p3 >> 16) & 0xFF;
            $p3_g = ($p3 >> 8) & 0xFF;
            $p3_b = $p3 & 0xFF;
            $p3_color = $p3_r + $p3_g + $p3_b;
            
            // Get color
            $p4 = @imagecolorat($img, $row+1, $col+1);
            // R+G+B
            $p4_r = ($p4 >> 16) & 0xFF;
            $p4_g = ($p4 >> 8) & 0xFF;
            $p4_b = $p4 & 0xFF;
            $p4_color = $p4_r + $p4_g + $p4_b;
            
            $color = $p1;
            // Find the brightest pixel
            $max_pixel = max($p1_color, $p2_color, $p3_color, $p4_color);
            if($max_pixel == $p1_color){
                $color = $p1;
            }
            elseif($max_pixel == $p2_color){
                $color = $p2;
            }
            elseif($max_pixel == $p3_color){
                $color = $p3;
            }
            else{
                $color = $p4;
            }
            // Paint pooled pixel
            imagesetpixel($max_pool_img, $max_row, $max_col, $color);
            $max_col++;
        }
        $max_col = 0;
        $max_row++;
    }
    return $max_pool_img;
}
function Monochrome(&$img, $color_channel){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    
    // Allocate resource in memory for the image
    $monochrome = imagecreatetruecolor($width, $height);
    $background = imagecolorallocate($monochrome, 0, 0, 0);
    
    // Loop through pixels
    for($row = 0; $row < $width; $row++){
        for($col = 0; $col < $height; $col++){
            
            // Get pixel color channels 
            $p = imagecolorat($img, $row, $col);
            $colors = imagecolorsforindex($img, $p);
            
            // Extract desired channel
            if($color_channel == RED){
                $pixelcolor = imagecolorallocate($monochrome, $colors['red'], 0, 0);
            }
            elseif($color_channel == GREEN){
                $pixelcolor = imagecolorallocate($monochrome, 0, $colors['green'], 0);
            }
            elseif($color_channel == BLUE){
                $pixelcolor = imagecolorallocate($monochrome, 0, 0, $colors['blue']);
            }
            else{
                 $pixelcolor = $background;
            }
            
            // Change pixel to contain pure channel
            imagesetpixel($monochrome, $row, $col, $pixelcolor);
        }
    }
    return $monochrome;
}
// Take an image with height and width and return 
// an array of floats for the desired color channel
function Flatten(&$img, $color_channel){
    // Get the size info from the input image
    $width = imagesx($img);
    $height = imagesy($img);
    // the flattened pixel data is stored here
    $pixels = array();
    
    // Loop through pixels
    for($row = 0; $row < $width; $row++){
        for($col = 0; $col < $height; $col++){
            
            // Get pixel color channels 
            $p = imagecolorat($img, $row, $col);
            $colors = imagecolorsforindex($img, $p);
            // Extract desired channel
            if($color_channel == RED){
                $pixels[] = ColorToFloat($colors['red']);
            }
            elseif($color_channel == GREEN){
                $pixels[] = ColorToFloat($colors['green']);
            }
            elseif($color_channel == BLUE){
                $pixels[] = ColorToFloat($colors['blue']);
            }
            else{
                 $pixels[] = 0.00;
            }
        }
    }
        
    return $pixels;
}
function ExtractHealthbarFromScreenshot(&$source_im){
    $x1 = 95;
    $y1 = 725;
    $x2 = 298 - $x1;
    $x2 = 298 - $x1;
    $y2 = 730 - $y1; // 733 whole thing
    return imagecrop($source_im, ['x' => 95, 'y' => 725, 'width' => $x2, 'height' => $y2]);
}
// example will echo 0 - 255
//for($i = 0; $i <= 255; $i++){
//    echo $i . ' ' . ColorToFloat($i) . PHP_EOL;
//}
function ColorToFloat($value)
{
    $max = 255;
    $increment = $max / 100;
    
    return ($value / $increment) / 100;
}
// example will echo 0 - 1
//for($i = 0; $i <= 1; $i+=0.01){
//    echo $i . ' ' . FloatToColor($i) . PHP_EOL;
//}
function FloatToColor($value)
{
    $max = 255;
    $increment = $max / 100;
    
    return round(($value * 100) * $increment);
}
$image_kernel = array(
	array(-1, -1, -1), 
	array(-1, 8, -1), 
	array(-1, -1, -1)
);
$screenshots = 'screenshots';
$screenshot = '1025167102.81336.jpg'; // Change to your test image
    
// Load image
$health_bar_r = imagecreatefromjpeg(__DIR__  . DIRECTORY_SEPARATOR . $screenshots . DIRECTORY_SEPARATOR . $screenshot);
// Get image size
$width = imagesx($health_bar_r);
$height = imagesy($health_bar_r);
// Create image resources of the correct size
$health_bar_g = imagecreatetruecolor($width, $height);
$health_bar_b = imagecreatetruecolor($width, $height);
// Copy the image to the new image resources
imagecopy($health_bar_g, $health_bar_r, 0, 0, 0, 0, $width, $height);
imagecopy($health_bar_b, $health_bar_r, 0, 0, 0, 0, $width, $height);
// Extract healthbar if the image is full size
if($width >= 1280 && $height >= 800){
    $health_bar_r = ExtractHealthbarFromScreenshot($health_bar_r);
    $health_bar_g = ExtractHealthbarFromScreenshot($health_bar_g);
    $health_bar_b = ExtractHealthbarFromScreenshot($health_bar_b);
}
// Split RGB Channels
$health_bar_r = Monochrome($health_bar_r, RED);
$health_bar_g = Monochrome($health_bar_g, GREEN);
$health_bar_b = Monochrome($health_bar_b, BLUE);
// Convolutions
imageconvolution($health_bar_r, $image_kernel, 1, -1);
imageconvolution($health_bar_g, $image_kernel, 1, -1);
imageconvolution($health_bar_b, $image_kernel, 1, -1);
// Pooling
$health_bar_r = MaxPool($health_bar_r);
$health_bar_g = MaxPool($health_bar_g);
$health_bar_b = MaxPool($health_bar_b);
$red_inputs = Flatten($health_bar_r, RED);
$green_inputs = Flatten($health_bar_g, GREEN);
$blue_inputs = Flatten($health_bar_b, BLUE);
 // Destroy image resources
imagedestroy($health_bar_r);
imagedestroy($health_bar_g);
imagedestroy($health_bar_b);
// Load ANN
$train_file = (dirname(__FILE__) . "/finished.net");
if (!is_file($train_file)){
    die("The file finished.net has not been created!" . PHP_EOL);
}
$ann = fann_create_from_file($train_file);
if ($ann) {
    $input = array_merge($red_inputs, $green_inputs, $blue_inputs);
    $result = fann_run($ann, $input);
    echo $result[0] . ' ' . $result[1] . PHP_EOL;
    // Hardcoded tests (uncomment to run):
    /*
    $input = array(0.019607843137255, 0.043137254901961, 0.043137254901961, 0.058823529411765, 0.031372549019608, 0.035294117647059, 0.019607843137255, 0.031372549019608, 0.03921568627451, 0.027450980392157, 0, 0.003921568627451, 0.007843137254902, 0.015686274509804, 0.031372549019608, 0.03921568627451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007843137254902, 0.015686274509804, 0, 0.007843137254902, 0, 0.007843137254902, 0.007843137254902, 0.015686274509804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.035294117647059, 0.043137254901961, 0, 0.015686274509804, 0.019607843137255, 0.003921568627451, 0.023529411764706, 0.03921568627451, 0.023529411764706, 0.003921568627451, 0, 0.003921568627451, 0, 0, 0.011764705882353, 0.019607843137255, 0.007843137254902, 0.011764705882353, 0.56078431372549, 0.50588235294118, 0.77647058823529, 0.79607843137255, 0, 0, 0.95686274509804, 0.97647058823529, 0.14117647058824, 0.13725490196078, 0, 0, 0.019607843137255, 0.019607843137255, 0.043137254901961, 0.043137254901961, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0, 0.023529411764706, 0.007843137254902, 0.003921568627451, 0, 0.011764705882353, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007843137254902, 0.015686274509804, 0, 0.007843137254902, 0, 0.007843137254902, 0.007843137254902, 0.015686274509804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.015686274509804, 0.007843137254902, 0.023529411764706, 0, 0, 0.011764705882353, 0.007843137254902, 0.015686274509804, 0.019607843137255, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.007843137254902, 0.19607843137255, 0.18823529411765, 0.88235294117647, 0.89019607843137, 0, 0, 0.43137254901961, 0.4078431372549, 0, 0, 0.7921568627451, 0.79607843137255, 0.27058823529412, 0.25490196078431, 0.019607843137255, 0.019607843137255, 0.043137254901961, 0.043137254901961, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.031372549019608, 0.03921568627451, 0, 0.007843137254902, 0, 0.007843137254902, 0.007843137254902, 0.015686274509804, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.031372549019608, 0.027450980392157, 0.4078431372549, 0.3843137254902, 0, 0, 0.3921568627451, 0.35294117647059, 0.011764705882353, 0, 0, 0);
    $result = fann_run($ann, $input);
    echo "(-1, -1) : " . $result[0] . ' ' . $result[1] . PHP_EOL;
    $input = array(0, 0, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.031372549019608, 0.031372549019608, 0, 0, 0.043137254901961, 0.050980392156863, 0.011764705882353, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.007843137254902, 0.011764705882353, 0.019607843137255, 0.031372549019608, 0.011764705882353, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0, 0.003921568627451, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.015686274509804, 0, 0.007843137254902, 0.011764705882353, 0.003921568627451, 0.031372549019608, 0.03921568627451, 0.007843137254902, 0.007843137254902, 0, 0, 0.047058823529412, 0, 0.035294117647059, 0.007843137254902, 0.019607843137255, 0.007843137254902, 0.047058823529412, 0.007843137254902, 0.019607843137255, 0, 0.031372549019608, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.047058823529412, 0.015686274509804, 0, 0.003921568627451, 0.011764705882353, 0.007843137254902, 0.019607843137255, 0.031372549019608, 0.011764705882353, 0.019607843137255, 0, 0.003921568627451, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.015686274509804, 0.011764705882353, 0.019607843137255, 0.011764705882353, 0.019607843137255, 0.011764705882353, 0.023529411764706, 0, 0.003921568627451, 0.011764705882353, 0.019607843137255, 0.011764705882353, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.49803921568627, 0.47058823529412, 0, 0, 1, 1, 1, 1, 0, 0, 0.10588235294118, 0.12549019607843, 0, 0, 0.18823529411765, 0.21176470588235, 0.007843137254902, 0, 0.027450980392157, 0, 0.03921568627451, 0, 0.035294117647059, 0, 0.019607843137255, 0.007843137254902, 0.019607843137255, 0.007843137254902, 0.019607843137255, 0, 0.058823529411765, 0.03921568627451, 0, 0.015686274509804, 0.07843137254902, 0.043137254901961, 0.054901960784314, 0.066666666666667, 0, 0, 1, 1, 0.31372549019608, 0.27450980392157, 0.15294117647059, 0.16862745098039, 0.019607843137255, 0.023529411764706, 0.043137254901961, 0.015686274509804, 0.031372549019608, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.019607843137255, 0, 0.031372549019608, 0.007843137254902, 0.031372549019608, 0.007843137254902, 0.019607843137255, 0, 0.050980392156863, 0.03921568627451, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.25098039215686, 0.24705882352941, 0.16470588235294, 0.18823529411765, 0.44313725490196, 0.43529411764706, 0, 0, 0.78039215686275, 0.76862745098039, 0, 0, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.019607843137255, 0.019607843137255, 0, 0, 0.007843137254902, 0.007843137254902, 0, 0.003921568627451, 0.011764705882353, 0.007843137254902, 0.023529411764706, 0.019607843137255, 0.007843137254902, 0.011764705882353, 0.007843137254902, 0.015686274509804, 0.011764705882353, 0.007843137254902, 0.023529411764706, 0.019607843137255, 0.023529411764706, 0.031372549019608, 0, 0, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0, 0, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0, 0, 0.007843137254902, 0.003921568627451, 0.019607843137255, 0.015686274509804, 0, 0.011764705882353, 0.007843137254902, 0.007843137254902, 0, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0, 0, 0, 0.023529411764706, 0.007843137254902, 0.007843137254902, 0.011764705882353, 0.019607843137255, 0.019607843137255, 0.043137254901961, 0, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.007843137254902, 0.019607843137255, 0, 0.007843137254902, 0.031372549019608, 0.031372549019608, 0.011764705882353, 0.007843137254902, 0.023529411764706, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0, 0, 0, 0.003921568627451, 0, 0, 0.011764705882353, 0.019607843137255, 0.011764705882353, 0.023529411764706, 0, 0.003921568627451, 0.011764705882353, 0, 0.011764705882353, 0.007843137254902, 0.098039215686275, 0.098039215686275, 0, 0, 0.36862745098039, 0.35294117647059, 1, 1, 0.9843137254902, 0.97647058823529, 0.043137254901961, 0.066666666666667, 0, 0, 0.03921568627451, 0.054901960784314, 0.007843137254902, 0, 0.086274509803922, 0.070588235294118, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.003921568627451, 0.019607843137255, 0, 0, 0.019607843137255, 0, 0.007843137254902, 0, 0, 0, 0.011764705882353, 0.031372549019608, 0.047058823529412, 0, 0, 0.015686274509804, 0.015686274509804, 0.047058823529412, 0.047058823529412, 1, 1, 0.090196078431373, 0.12941176470588, 0.019607843137255, 0, 0.15686274509804, 0.17647058823529, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.015686274509804, 0.007843137254902, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.4, 0.40392156862745, 0.011764705882353, 0.011764705882353, 0.27058823529412, 0.27058823529412, 0, 0, 0.64705882352941, 0.63921568627451, 0.27058823529412, 0.27058823529412, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.015686274509804, 0.035294117647059, 0.019607843137255, 0.011764705882353, 0.007843137254902, 0.011764705882353, 0.023529411764706, 0, 0.003921568627451, 0.011764705882353, 0.031372549019608, 0.011764705882353, 0.007843137254902, 0.007843137254902, 0, 0.007843137254902, 0.015686274509804, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.043137254901961, 0.043137254901961, 0.007843137254902, 0.007843137254902, 0.031372549019608, 0.031372549019608, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.031372549019608, 0.031372549019608, 0, 0, 0.007843137254902, 0.015686274509804, 0.011764705882353, 0.007843137254902, 0.011764705882353, 0.007843137254902, 0.023529411764706, 0.031372549019608, 0, 0, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0, 0, 0.007843137254902, 0.015686274509804, 0.011764705882353, 0.007843137254902, 0.019607843137255, 0.031372549019608, 0.035294117647059, 0.043137254901961, 0, 0, 0.031372549019608, 0.031372549019608, 0.007843137254902, 0.007843137254902, 0, 0, 0.031372549019608, 0.03921568627451, 0.035294117647059, 0.019607843137255, 0.011764705882353, 0.007843137254902, 0.023529411764706, 0.035294117647059, 0, 0.003921568627451, 0.011764705882353, 0.031372549019608, 0.011764705882353, 0.007843137254902, 0.007843137254902, 0, 0.34901960784314, 0.34509803921569, 0, 0, 0.9921568627451, 0.93725490196078, 1, 1, 0.07843137254902, 0.094117647058824, 0.003921568627451, 0, 0.090196078431373, 0.10588235294118, 0.031372549019608, 0.047058823529412, 0.07843137254902, 0.031372549019608, 0.031372549019608, 0.031372549019608, 0.043137254901961, 0.027450980392157, 0.043137254901961, 0.023529411764706, 0.019607843137255, 0.043137254901961, 0.019607843137255, 0.023529411764706, 0.019607843137255, 0.019607843137255, 0.070588235294118, 0.035294117647059, 0, 0.015686274509804, 0.035294117647059, 0.035294117647059, 0.03921568627451, 0.058823529411765, 0.062745098039216, 0.066666666666667, 1, 1, 0.16470588235294, 0.13725490196078, 0.035294117647059, 0.054901960784314, 0, 0, 0.094117647058824, 0.050980392156863, 0.031372549019608, 0.019607843137255, 0.031372549019608, 0.019607843137255, 0.031372549019608, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.031372549019608, 0.019607843137255, 0.031372549019608, 0.019607843137255, 0.03921568627451, 0.027450980392157, 0.007843137254902, 0.007843137254902, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.17254901960784, 0.17254901960784, 0.17647058823529, 0.16470588235294, 0.28235294117647, 0.28627450980392, 0, 0, 0.29019607843137, 0.31764705882353, 0.058823529411765, 0.07843137254902, 0.11764705882353, 0.074509803921569);
    $result = fann_run($ann, $input);
    echo "(1, 1) : " . $result[0] . ' ' . $result[1] . PHP_EOL;
    $input = array(0.019607843137255, 0.019607843137255, 0.043137254901961, 0.043137254901961, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.007843137254902, 0.007843137254902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03921568627451, 0.019607843137255, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.03921568627451, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.16078431372549, 0.16862745098039, 0, 0, 0, 0, 0.03921568627451, 0.058823529411765, 0.086274509803922, 0.070588235294118, 0, 0, 0.49019607843137, 0.49411764705882, 0.27843137254902, 0.31764705882353, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0.003921568627451, 0.019607843137255, 0, 0.03921568627451, 0, 0.031372549019608, 0, 0.031372549019608, 0, 0.03921568627451, 0.003921568627451, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0.14509803921569, 0.12941176470588, 0, 0, 0.003921568627451, 0, 0.07843137254902, 0.070588235294118, 0.043137254901961, 0.058823529411765, 0, 0, 0.27058823529412, 0.28235294117647, 1, 1, 0.10980392156863, 0.086274509803922, 0.49411764705882, 0.26666666666667, 0.55686274509804, 0.13333333333333, 0.33333333333333, 0.074509803921569, 0.34509803921569, 0.3921568627451, 0.44313725490196, 0.52549019607843, 0.46666666666667, 0.53333333333333, 0.50588235294118, 0.42745098039216, 0.094117647058824, 0.12156862745098, 0.12156862745098, 0.13333333333333, 0, 0, 0.21176470588235, 0.03921568627451, 0.25490196078431, 0, 0.38823529411765, 0, 0, 0, 0.17647058823529, 0.18039215686275, 0.41176470588235, 0.44313725490196, 0.69019607843137, 0.69411764705882, 0, 0, 1, 1, 0.64313725490196, 0.70980392156863, 0, 0, 0.019607843137255, 0.019607843137255, 0.043137254901961, 0.043137254901961, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.019607843137255, 0.015686274509804, 0.007843137254902, 0, 0.011764705882353, 0, 0, 0, 0, 0.007843137254902, 0.007843137254902, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.019607843137255, 0.011764705882353, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0.019607843137255, 0.011764705882353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.043137254901961, 0.043137254901961, 0, 0.007843137254902, 0.031372549019608, 0.027450980392157, 0.031372549019608, 0.031372549019608, 0, 0, 0.054901960784314, 0.050980392156863, 0.13725490196078, 0.13725490196078, 0.69019607843137, 0.69019607843137, 0, 0, 0.090196078431373, 0.10196078431373, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0.015686274509804, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.007843137254902, 0.015686274509804, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.066666666666667, 0.070588235294118, 0, 0, 0.043137254901961, 0.058823529411765, 0.03921568627451, 0.047058823529412, 0, 0, 0.047058823529412, 0.054901960784314, 0.082352941176471, 0.12156862745098, 0.42745098039216, 0.41176470588235, 1, 1, 0.10980392156863, 0.086274509803922, 0.48235294117647, 0.23529411764706, 0.50980392156863, 0.15686274509804, 0.31764705882353, 0.031372549019608, 0.32941176470588, 0.38039215686275, 0.4, 0.48627450980392, 0.47450980392157, 0.52156862745098, 0.50588235294118, 0.4156862745098, 0.023529411764706, 0.066666666666667, 0.10196078431373, 0.16470588235294, 0.003921568627451, 0, 0.18823529411765, 0.031372549019608, 0.22745098039216, 0, 0.36078431372549, 0, 0, 0, 0.015686274509804, 0, 0.38039215686275, 0.3843137254902, 0.007843137254902, 0.090196078431373, 0.68235294117647, 0.68235294117647, 0.6, 0.58823529411765, 0.7843137254902, 0.8078431372549, 0.37254901960784, 0.36078431372549, 0.031372549019608, 0.015686274509804, 0.047058823529412, 0.058823529411765, 0.003921568627451, 0.023529411764706, 0.050980392156863, 0.003921568627451, 0.027450980392157, 0.015686274509804, 0.011764705882353, 0.027450980392157, 0, 0, 0.058823529411765, 0.019607843137255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.054901960784314, 0.062745098039216, 0, 0, 0.019607843137255, 0.027450980392157, 0.043137254901961, 0.054901960784314, 0.003921568627451, 0.023529411764706, 0, 0, 0, 0, 0.61960784313725, 0.61960784313725, 0.10980392156863, 0.14901960784314, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0.003921568627451, 0.019607843137255, 0, 0.03921568627451, 0, 0.031372549019608, 0, 0.031372549019608, 0, 0.03921568627451, 0.003921568627451, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0, 0.019607843137255, 0.21176470588235, 0.17647058823529, 0, 0, 0, 0, 0.12941176470588, 0.10196078431373, 0.031372549019608, 0.11764705882353, 0, 0, 0.27450980392157, 0.23529411764706, 1, 1, 0.10980392156863, 0.07843137254902, 0.48627450980392, 0.26274509803922, 0.54901960784314, 0.10980392156863, 0.32549019607843, 0.035294117647059, 0.32941176470588, 0.37647058823529, 0.41960784313725, 0.50588235294118, 0.47450980392157, 0.52156862745098, 0.50588235294118, 0.4156862745098, 0.14509803921569, 0.14901960784314, 0.11372549019608, 0.17254901960784, 0, 0.031372549019608, 0.23921568627451, 0.019607843137255, 0.28627450980392, 0, 0.36470588235294, 0, 0, 0, 0.25098039215686, 0.30588235294118, 0.28627450980392, 0.30588235294118, 0.35294117647059, 0.33725490196078, 0.058823529411765, 0.11764705882353, 1, 1, 0, 0, 0.10588235294118, 0.10196078431373);
    $result = fann_run($ann, $input);
    echo "(-1, -1) : " . $result[0] . ' ' . $result[1] . PHP_EOL;
    $input = array(0.007843137254902, 0.019607843137255, 0.031372549019608, 0.050980392156863, 0.031372549019608, 0.054901960784314, 0.031372549019608, 0.035294117647059, 0.007843137254902, 0.015686274509804, 0.007843137254902, 0.011764705882353, 0.019607843137255, 0.027450980392157, 0, 0, 0.03921568627451, 0.023529411764706, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.07843137254902, 0.066666666666667, 0.10196078431373, 0.062745098039216, 0.10980392156863, 0.12156862745098, 0.007843137254902, 0.011764705882353, 0.16862745098039, 0.17647058823529, 0, 0, 0.29019607843137, 0.30588235294118, 0, 0, 1, 1, 0.32941176470588, 0.33333333333333, 0, 0.03921568627451, 0.10588235294118, 0.13725490196078, 0.12941176470588, 0.10588235294118, 0.054901960784314, 0.007843137254902, 0.007843137254902, 0.003921568627451, 0.023529411764706, 0, 0.027450980392157, 0.003921568627451, 0.074509803921569, 0.070588235294118, 0, 0, 0.082352941176471, 0.015686274509804, 0.011764705882353, 0.019607843137255, 0, 0.047058823529412, 0.007843137254902, 0.019607843137255, 0.066666666666667, 0, 0.074509803921569, 0.027450980392157, 0.054901960784314, 0, 0.054901960784314, 0.047058823529412, 0.007843137254902, 0.027450980392157, 0.03921568627451, 0.12156862745098, 0.047058823529412, 0, 0.03921568627451, 0, 0.062745098039216, 0, 0.10588235294118, 0, 0.019607843137255, 0.03921568627451, 0, 0.003921568627451, 0.062745098039216, 0.043137254901961, 0.031372549019608, 0.027450980392157, 0.074509803921569, 0.015686274509804, 0.12941176470588, 0.058823529411765, 0.007843137254902, 0.035294117647059, 0.058823529411765, 0.043137254901961, 0.086274509803922, 0.090196078431373, 0.027450980392157, 0, 0, 0.098039215686275, 0.15686274509804, 0.090196078431373, 0.019607843137255, 0, 0, 0.003921568627451, 0.019607843137255, 0.003921568627451, 0.18039215686275, 0.16862745098039, 0.086274509803922, 0.15294117647059, 0, 0.058823529411765, 0.1921568627451, 0.15294117647059, 0.17647058823529, 0.094117647058824, 0.050980392156863, 0.007843137254902, 0.023529411764706, 0.019607843137255, 0.023529411764706, 0.043137254901961, 0.03921568627451, 0.12156862745098, 0.03921568627451, 0.011764705882353, 0.035294117647059, 0.043137254901961, 0.07843137254902, 0.050980392156863, 0.098039215686275, 0.07843137254902, 0.050980392156863, 0.12941176470588, 0.13333333333333, 0.03921568627451, 0.10196078431373, 0.023529411764706, 0.28627450980392, 0.1843137254902, 0.082352941176471, 0.10980392156863, 0.043137254901961, 0.11764705882353, 0.023529411764706, 0.07843137254902, 0.027450980392157, 0.090196078431373, 0.027450980392157, 0.027450980392157, 0.16862745098039, 0, 0.14117647058824, 0, 0.10980392156863, 0, 0.21960784313725, 0.1921568627451, 0.003921568627451, 0, 0.11372549019608, 0.17254901960784, 0.082352941176471, 0.13725490196078, 0, 0, 0.72549019607843, 0.72156862745098, 0.24313725490196, 0.21960784313725, 0.15294117647059, 0.12941176470588, 0.30980392156863, 0.28627450980392, 0.16078431372549, 0.14901960784314, 0, 0, 0.68235294117647, 0.64313725490196, 0.082352941176471, 0.082352941176471, 0, 0, 0.043137254901961, 0.043137254901961, 0.007843137254902, 0.003921568627451, 0.015686274509804, 0.003921568627451, 0.035294117647059, 0.027450980392157, 0, 0, 0, 0, 0.007843137254902, 0.011764705882353, 0.019607843137255, 0.011764705882353, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0, 0.007843137254902, 0.090196078431373, 0.074509803921569, 0.066666666666667, 0.062745098039216, 0.043137254901961, 0.043137254901961, 0.031372549019608, 0.031372549019608, 0.090196078431373, 0.090196078431373, 0, 0, 0.32549019607843, 0.31764705882353, 1, 1, 0.32549019607843, 0.36470588235294, 0, 0.03921568627451, 0.070588235294118, 0.14117647058824, 0.094117647058824, 0.10588235294118, 0.031372549019608, 0.007843137254902, 0, 0.003921568627451, 0.023529411764706, 0, 0, 0.015686274509804, 0.10588235294118, 0.10980392156863, 0, 0, 0.031372549019608, 0.023529411764706, 0, 0, 0, 0.050980392156863, 0.007843137254902, 0.007843137254902, 0.031372549019608, 0, 0.054901960784314, 0, 0.03921568627451, 0, 0.054901960784314, 0.023529411764706, 0.007843137254902, 0.003921568627451, 0.03921568627451, 0.098039215686275, 0.023529411764706, 0, 0.015686274509804, 0.003921568627451, 0.03921568627451, 0.003921568627451, 0.066666666666667, 0, 0.003921568627451, 0.035294117647059, 0, 0.011764705882353, 0.062745098039216, 0.031372549019608, 0, 0.011764705882353, 0.070588235294118, 0, 0.14509803921569, 0.047058823529412, 0, 0.015686274509804, 0.047058823529412, 0.043137254901961, 0.011764705882353, 0.027450980392157, 0.015686274509804, 0, 0, 0.098039215686275, 0.14509803921569, 0.070588235294118, 0, 0.015686274509804, 0, 0.003921568627451, 0, 0.007843137254902, 0.043137254901961, 0.062745098039216, 0.10196078431373, 0.13333333333333, 0, 0.10980392156863, 0.18823529411765, 0.11764705882353, 0.17647058823529, 0.094117647058824, 0.031372549019608, 0, 0.007843137254902, 0, 0, 0.011764705882353, 0.062745098039216, 0.086274509803922, 0.047058823529412, 0.035294117647059, 0.007843137254902, 0.027450980392157, 0.035294117647059, 0.015686274509804, 0.050980392156863, 0.027450980392157, 0.058823529411765, 0.090196078431373, 0.13725490196078, 0.094117647058824, 0.10196078431373, 0, 0.15294117647059, 0.086274509803922, 0.066666666666667, 0.13725490196078, 0.035294117647059, 0.10980392156863, 0, 0.066666666666667, 0.03921568627451, 0.066666666666667, 0.019607843137255, 0, 0.13725490196078, 0, 0.16470588235294, 0, 0.1843137254902, 0.07843137254902, 0.011764705882353, 0.003921568627451, 0.10588235294118, 0.10588235294118, 0.086274509803922, 0.07843137254902, 0.050980392156863, 0.10588235294118, 0.035294117647059, 0.2, 0.52156862745098, 0.49019607843137, 0, 0, 0.023529411764706, 0.043137254901961, 0.43529411764706, 0.38823529411765, 0, 0, 0.31372549019608, 0.27058823529412, 0, 0, 0.63921568627451, 0.63529411764706, 0.27843137254902, 0.27843137254902, 0.003921568627451, 0.019607843137255, 0.074509803921569, 0.035294117647059, 0.015686274509804, 0.027450980392157, 0.035294117647059, 0.015686274509804, 0, 0.003921568627451, 0.019607843137255, 0.027450980392157, 0, 0.003921568627451, 0.050980392156863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.07843137254902, 0.07843137254902, 0.090196078431373, 0.10588235294118, 0.14901960784314, 0.15686274509804, 0.019607843137255, 0.027450980392157, 0.23137254901961, 0.23921568627451, 0, 0, 0.33333333333333, 0.36862745098039, 0, 0, 1, 1, 0.36078431372549, 0.36470588235294, 0, 0.03921568627451, 0.10588235294118, 0.14117647058824, 0.12941176470588, 0.10588235294118, 0.054901960784314, 0.007843137254902, 0.007843137254902, 0.003921568627451, 0.023529411764706, 0, 0.043137254901961, 0.015686274509804, 0.062745098039216, 0.058823529411765, 0, 0, 0.043137254901961, 0.043137254901961, 0, 0.007843137254902, 0.035294117647059, 0.019607843137255, 0.03921568627451, 0.03921568627451, 0.043137254901961, 0, 0.043137254901961, 0, 0.10196078431373, 0.035294117647059, 0.07843137254902, 0.047058823529412, 0.031372549019608, 0.027450980392157, 0.062745098039216, 0.12156862745098, 0.023529411764706, 0.011764705882353, 0.015686274509804, 0.015686274509804, 0.03921568627451, 0.015686274509804, 0.066666666666667, 0, 0.027450980392157, 0.03921568627451, 0.031372549019608, 0.031372549019608, 0.082352941176471, 0.035294117647059, 0.019607843137255, 0.058823529411765, 0.086274509803922, 0.003921568627451, 0.16862745098039, 0.07843137254902, 0.015686274509804, 0.023529411764706, 0.07843137254902, 0.070588235294118, 0.011764705882353, 0.03921568627451, 0.007843137254902, 0.015686274509804, 0, 0.12549019607843, 0.17647058823529, 0.070588235294118, 0, 0.031372549019608, 0, 0.003921568627451, 0, 0.031372549019608, 0.047058823529412, 0.03921568627451, 0.14509803921569, 0.13333333333333, 0.003921568627451, 0.10196078431373, 0.2078431372549, 0.12156862745098, 0.19607843137255, 0.12156862745098, 0.023529411764706, 0, 0.035294117647059, 0, 0.015686274509804, 0.019607843137255, 0.03921568627451, 0.054901960784314, 0.082352941176471, 0.054901960784314, 0.003921568627451, 0.023529411764706, 0.011764705882353, 0, 0.015686274509804, 0.007843137254902, 0.11764705882353, 0.12156862745098, 0.17647058823529, 0.13725490196078, 0.094117647058824, 0.015686274509804, 0.047058823529412, 0.019607843137255, 0.13333333333333, 0.17647058823529, 0.066666666666667, 0.10588235294118, 0.054901960784314, 0.03921568627451, 0.023529411764706, 0.090196078431373, 0.035294117647059, 0.003921568627451, 0.16078431372549, 0, 0.14509803921569, 0, 0.086274509803922, 0.011764705882353, 0.14509803921569, 0.15686274509804, 0.047058823529412, 0.031372549019608, 0.070588235294118, 0.12549019607843, 0.2156862745098, 0.23137254901961, 0.098039215686275, 0.25882352941176, 0.45098039215686, 0.42352941176471, 0.003921568627451, 0, 0.35686274509804, 0.4078431372549, 0.094117647058824, 0.082352941176471, 0.32156862745098, 0.27450980392157, 0.003921568627451, 0, 0.29803921568627, 0.27058823529412, 0.11764705882353, 0.11764705882353, 0.082352941176471, 0.074509803921569);
    $result = fann_run($ann, $input);
    echo "(1, -1) : " . $result[0] . ' ' . $result[1] . PHP_EOL;
    */
    fann_destroy($ann);
} else {
    die("Invalid file format" . PHP_EOL);
}

 

Get The Code

All of this code is available under the MIT licence for free and you can download and use it however you wish but you must credit me as the original source.

GitHub: https://github.com/geekgirljoy/AutoDoc

 

So… What Happened?

That’s easy!

Empowered by my new AutoDoc prototype I tracked down that raider who shot at me at the beginning of my story!

I won’t say what I did to the raider because, well… it was incredibly heinous…


Fingers crossed this the weirdest educational shit you’ve read all week and if so, please support me over on Patreon for as little as $1 a month, cancel any time.

But, if all you can do is like, share, comment and subscribe… well, that’s cool too! 😉

Much Love,

~Joy