https://git.spwbk.site/swatson/battleship-perl/raw/master/battleship.pl
___________________________________
#!/usr/bin/perl

# TODO: More work on AI, make it smarter and less random
#       ** Keep track of where it's already missed and whether or not opponent moves
# TODO: Handle situation where player or AI can place ships that 'wrap' around the map, ie coordinates
#       like 20,21,22 which would place the end of a cruiser in the first row, and the next two sections of it
#       in the second row. This doesn't really break the game at all, but it does look weird on the map and doesn't seem
#       to be a mature implimentation if it exists
# TODO: Handle the fact that player can input random coordinates so that they could potentially have 1 third
#       of a ship in 3 different coordinates, or just have a ship occupy 1 tile by entering the same coordinate
# TODO: 'Productionize' the code: error handling, more input sanitation, etc
#       ** Optimze placement so we dont have to check it each time, ie check at placement
#       ** Consolidate redundant subs
# TODO: Improve readability, game play feel
#
# KNOWN BUGS:
# TODO: &clearUnocTiles issue -- see sub comment
#       ** Not sure this is really an issue, but leaving it here to remind myself anyways

# Basic implimentation of 'battleship' to teach myself more about programming
# I don't know the actual rules of the game, this is my stab at
# something in the 'spirit' of it
#
# Player takes turns against computer trying to hit one of their ships.
# Can only perform 1 action per turn:
#       - Move
#       - Attack
#
# Three types of ships:
#       * Cruiser
#               - Hull Points: 2
#               - Size: 3x1
#               - Attack Power: 1
#       * Carrier
#               - Hull Points: 3
#               - Size: 5x1
#               - Attack Power: 2
#       * Submarine
#               - Hull Points: 1
#               - Size 2x1
#               - Attack Power: 3
#
# 5x5 map grid for each player
# Cruiser = *
# Carrier = @
# Submarine = ~
# Ocean/Empty Space = .

use strict;
use warnings;
use lib "/home/swatson/Repos/battleship-perl";
#use MapTools;
use Term::ANSIColor qw(:constants);

my $version = 0.1;
if ( $ARGV[0] && $ARGV[0] =~ /version/ ) {
       print "$version\n";
       exit 0;
}

# Maps
my %p1map;
my %p2map;

# Stats trackers
my @p1Attacks;
my @p2Attacks;

# Ships - surely there is a better way to do this
my %p1cruiser = ( 'hp' => '2', 'size' => '3', 'ap' => '1', 'loc' => '', 'sym' => '*', 'mc' => 0 );
my %p1carrier = ( 'hp' => '3', 'size' => '5', 'ap' => '2', 'loc' => '', 'sym' => '@', 'mc' => 0 );
my %p1subm    = ( 'hp' => '1', 'size' => '2', 'ap' => '3', 'loc' => '', 'sym' => '~', 'mc' => 0 );

my %p1ships = ( 'cru' => \%p1cruiser, 'car' => \%p1carrier, 'subm' => \%p1subm );

my %p2cruiser = ( 'hp' => '2', 'size' => '3', 'ap' => '1', 'loc' => '', 'sym' => '*', 'mc' => 0 );
my %p2carrier = ( 'hp' => '3', 'size' => '5', 'ap' => '2', 'loc' => '', 'sym' => '@', 'mc' => 0 );
my %p2subm    = ( 'hp' => '1', 'size' => '2', 'ap' => '3', 'loc' => '', 'sym' => '~', 'mc' => 0 );

my %p2ships = ( 'cru' => \%p2cruiser, 'car' => \%p2carrier, 'subm' => \%p2subm );

sub initMap {

       foreach my $number ( 1 .. 50 ) {

               $p1map{$number} = ".";
               $p2map{$number} = ".";
       }

}

sub clearUnocTiles {

       # Bug where sometimes after a ship is moved one of the old tiles it was on
       # is not reset despite the &shipPosition function reporting that it is
       # Thus far, I've been unable to figure out why that is happening, so
       # for now am providing this function, which will check the location of all ships
       # and reset any incorrect tiles for both the player and the AI

       my @p1usedTiles;
       my @p2usedTiles;

       # Get in use tiles for ship hashes
       foreach my $ship ( keys %p1ships ) {

               if ( ! $p1ships{$ship} ) {
                       next;
               }
               my $shipRef = $p1ships{$ship};
               my $location = ${$shipRef}{loc};
               my @inUseTiles = split(",", $location);
               foreach my $iut ( @inUseTiles ) {
                       push(@p1usedTiles, $iut);
               }

       }

       # Clean the tiles
       foreach my $key ( keys %p1map ) {
               if ( grep { $_ eq $key } @p1usedTiles ) {
                       next;
               } else {
                       $p1map{$key} = ".";
               }

       }

       # Now the same for the AI map
       foreach my $ship ( keys %p2ships ) {

               if ( ! $p2ships{$ship} ) {
                       next;
               }
               my $shipRef = $p2ships{$ship};
               my $location = ${$shipRef}{loc};
               my @inUseTiles = split(",", $location);
               foreach my $iut ( @inUseTiles ) {
                       push(@p2usedTiles, $iut);
               }

       }

       # Clean the tiles
       foreach my $key ( keys %p2map ) {
               if ( grep { $_ eq $key } @p2usedTiles ) {
                       next;
               } else {
                       $p2map{$key} = ".";
               }
       }
}

sub printMap {

       my $count = 1;
       print "^ Player Map ^\n";
       foreach my $key ( sort { $a <=> $b } keys %p1map ) {
               # Probably a better way to do this
               if ( $count != 10 && $count != 20 && $count != 30 && $count != 40 && $count != 50 ) {
                       if ( $p1map{$key} eq "*" ) {
                               print YELLOW, "$p1map{$key}", RESET;
                       } elsif ( $p1map{$key} eq "@"  ) {
                               print RED, "$p1map{$key}", RESET;
                       } elsif ( $p1map{$key} eq "~"  ) {
                               print CYAN, "$p1map{$key}", RESET;
                       } else {
                               print "$p1map{$key}";
                       }
               } else {
                       if ( $p1map{$key} eq "*" ) {
                               print YELLOW, "$p1map{$key}\n", RESET;
                       } elsif ( $p1map{$key} eq "@"  ) {
                               print RED, "$p1map{$key}\n", RESET;
                       } elsif ( $p1map{$key} eq "~"  ) {
                               print CYAN, "$p1map{$key}\n", RESET;
                       } else {
                               print "$p1map{$key}\n";
                       }
               }
               $count++;

       }

}

sub printPlayerStats {

       # Print stats from main turn menu

       print "\n";

       foreach my $key ( keys %p1ships ) {
               my $shipHref = $p1ships{$key};
               if ( ! defined $p1ships{$key} ) {
                       print MAGENTA, "^^^ Ship: $key ^^^ \n", RESET;
                       print RED, "| SUNK! | \n", RESET;
               } else {
                       print MAGENTA, "^^^ Ship: $key ^^^ \n", RESET;
                       print RED, "| HP: ${$shipHref}{hp} | AP: ${$shipHref}{ap} | Location: ${$shipHref}{loc} |\n", RESET;
               }
       }

       print MAGENTA, "Coordinates attacked since last AI move:\n", RESET;
       my $atkArSize = scalar @p1Attacks;
       if ( $atkArSize > 0 ) {
               foreach my $coor ( @p1Attacks ) {
                       print RED, "$coor ", RESET;
               }
       } else {
               print "No attacks since last AI move";
       }

       print "\n";

}

sub shipPosition {

       # Map ship to position via grid mapping
       #   1  2  3  4  5  6  7  8  9  10
       #   .  .  .  .  .  .  .  .  .  .
       #   11 12 13 14 15 16 17 18 19 20
       #   .  .  .  .  .  .  .  .  .  .
       #   Etc.

       # Function should recieve ship hashRef and new grid location as input
       my $shipHref = shift;

       my $newLocation = shift;
       my $currentLocation = ${$shipHref}{loc};

       my @currentLoc = split(/,/, $currentLocation);
       my @newLoc = split(/,/, $newLocation);

       # This ended up working better than old loop
       &clearUnocTiles;


       # Now update new positon
       foreach my $tile ( @newLoc ) {
               $p1map{$tile} = ${$shipHref}{sym};
       }

       # Update shipHref with valid location
       ${$shipHref}{loc} = join(',', @newLoc);

       # Update move counter -- CANT DO THIS HERE AS WE USE THIS SUB IN INIT
       # ${$shipHref}{mc} = 1;


}

# TODO: Consolidate with above sub
sub AiShipPosition {

       # Map ship to position via grid mapping
       #   1  2  3  4  5  6  7  8  9  10
       #   .  .  .  .  .  .  .  .  .  .
       #   11 12 13 14 15 16 17 18 19 20
       #   .  .  .  .  .  .  .  .  .  .
       #   Etc.

       # Function should recieve ship hashRef and new grid location as input
       my $shipHref = shift;

       my $newLocation = shift;
       my $currentLocation = ${$shipHref}{loc};

       my @currentLoc = split(/,/, $currentLocation);
       my @newLoc = split(/,/, $newLocation);

       # This ended up working better than old loop
       &clearUnocTiles;

       # Now update new positon
       foreach my $tile ( @newLoc ) {
               $p2map{$tile} = ${$shipHref}{sym};
       }

       # Update shipHref with valid location
       ${$shipHref}{loc} = join(',', @newLoc);

       # Update move counter -- CANT DO THIS HERE AS WE USE THIS SUB IN INIT
       # ${$shipHref}{mc} = 1;


}

sub updateMap {

       foreach my $key ( keys %p1ships ) {
               my $shipHref = $p1ships{$key};
               my @mapPoints = split(/,/, ${$shipHref}{loc});
               foreach my $mpoint ( @mapPoints ) {
                       my $symbol = ${$shipHref}{sym};
                       $p1map{$mpoint} = $symbol;

               }
       }

       foreach my $key ( keys %p2ships ) {
               my $shipHref = $p2ships{$key};
               my @mapPoints = split(/,/, ${$shipHref}{loc});
               foreach my $mpoint ( @mapPoints ) {
                       my $symbol = ${$shipHref}{sym};
                       $p1map{$mpoint} = $symbol;
               }
       }
}

sub checkLocation {

       # Given a set of coordinates, determine if they are already occupied
       my $taken = 0;
       my $coordinates = shift;
       if ( $coordinates !~ /^[0-9]*,[0-9]*$/ && $coordinates !~ /^[0-9]*,[0-9]*,[0-9]*$/ && $coordinates !~ /^[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*$/ ) {
               print "These coordinates look incorrect, you shouldnt see this error...\n";
               $taken = $taken + 1;
       }

       my @coors = split(/,/, $coordinates);
       foreach my $coor ( @coors ) {
               if ( $p1map{$coor} ne "." ) {
                       print "coordinate $coor contains $p1map{$coor}\n";
                       $taken = $taken + 1;
               }
       }

       if ( $taken >= 1 ) {
               return 1;
       } else {
               return 0;
       }


}

sub placeShips {

       while() {

               # Init map at the top as failure will kick you back here
               &initMap;

               print "Where do you want to place your cruiser? : ";
               my $cruLoc = <STDIN>;
               chomp $cruLoc;

               ###
               ### TODO : Not actually checking location on any of the below blocks
               ### For whatever reason, it doesn't work as expected, and return coordinates that
               ### are taken despite them being empty. I don't understand the behavior, and need to revisit this
               ###

               if ( $cruLoc !~ /^[0-9]*,[0-9]*,[0-9]*$/ ) {
                       #|| ! eval &checkLocation($cruLoc) ) {
                       print "Input looks wrong, or coordinates are taken, try again\n";
                       next;
               }

               print "Where do you want to place your carrier? : ";
               my $carLoc = <STDIN>;
               chomp $carLoc;
               if ( $carLoc !~ /^[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*$/ ) {
                       # || ! eval &checkLocation($carLoc) ) {
                       print "Input looks wrong, or coordiantes are taken, try again\n";
                       next;
               }

               print "Where do you want to place your submarine? : ";
               my $submLoc = <STDIN>;
               chomp $submLoc;
               if ( $submLoc !~ /^[0-9]*,[0-9]*$/ ) {
                       # || ! eval &checkLocation($submLoc) ) {
                       print "Input looks wrong, I need 2 comma seperated coordinates, try again\n";
                       next;
               }

               print "Coordinates are:\n";
               print "Cruiser:   $cruLoc\n";
               print "Carrier:   $carLoc\n";
               print "Submarine: $submLoc\n";
               print GREEN, "Type yes to confirm or type redo to redo: ", RESET;
               my $confirm = <STDIN>;
               chomp $confirm;
               if ( $confirm eq "redo" ) {
                       next;
               } elsif ( $confirm eq "yes" ) {

                       my $cruRef = $p1ships{cru};
                       my $carRef = $p1ships{car};
                       my $submRef = $p1ships{subm};

                       if ( ! eval &checkLocation($cruLoc) ) {
                               &shipPosition($cruRef, $cruLoc);
                       } else {
                               print "Cruiser eval check failed\n";
                               &printMap;
                               next;
                       }
                       if ( ! eval &checkLocation($carLoc) ) {
                               &shipPosition($carRef, $carLoc);
                       } else {
                               print "Carrier eval check failed\n";
                               &printMap;
                               next;
                       }
                       if ( ! eval &checkLocation($submLoc) ) {
                               &shipPosition($submRef, $submLoc);
                       } else {
                               print "Submarine eval check failed\n";
                               &printMap;
                               next;
                       }

                       last;
               }
       }

}

sub randomLocation {

       # Used by AI
       # Pass in ship type and come up with a random location
       my $shipType = shift;
       my $size;
       if ( $shipType eq "cru" ) { $size = 3; }
       if ( $shipType eq "car" ) { $size = 5; }
       if ( $shipType eq "subm" ) { $size = 2; }

       # Where to randomly look in the map index ( keys %p2map ) - between 1 and 50
       my @fakeMap = ( 1 .. 50 );
       my $random_num = int(1 + rand(50 - 1));
       # Need to use splice so that numbers are sequential
       # TODO: Can still cause a situation where ships 'wrap' around edges of the map
       my @newLocs = splice(@fakeMap, $random_num, $size);
       # Make sure we don't end up with an empty/short location set
       while ( scalar(@newLocs) < $size ) {
               print "Re-rolling AI ship position due to conflict\n";
               $random_num = int(1 + rand(50 - 1));
               @newLocs = splice(@fakeMap, $random_num, $size);
       }

       my $newLocs = join(",", @newLocs);

       return $newLocs;

}

# TODO: This is stupid, main subroutine should be adjusted to take player map arg
sub checkAILocation {
       my $coor = shift;
       my @coors = split(/,/, $coor);
       my $taken = 0;
       foreach my $coor ( @coors ) {
               if ( $p2map{$coor} ne "." ) {
                       print "coordinate $coor contains $p2map{$coor}\n";
                       $taken = $taken + 1;
               }
       }
       if ( $taken >= 1 ) {
               return 1;
       } else {
               return 0;
       }
}


sub initAI {

       print MAGENTA, "Initialzing opponent..\n", RESET;
       # AI equivelant of placeShips()
       my $cruLoc = &randomLocation("cru");
       my $carLoc = &randomLocation("car");
       my $submLoc = &randomLocation("subm");

       #print "AI cru loc = $cruLoc\n";
       #print "AI car loc = $carLoc\n";
       #print "AI subm loc = $submLoc\n";

       # Hash refs for ships
       my $cruHref = $p2ships{cru};
       my $carHref = $p2ships{car};
       my $submHref = $p2ships{subm};

       # Update Locations with new locations
       if ( ! eval &checkAILocation($cruLoc) ) {
               ${$cruHref}{loc} = $cruLoc;
       } else { print "Something went wrong with AI init, exiting\n"; exit 0; }
       if ( ! eval &checkAILocation($carLoc) ) {
               ${$carHref}{loc} = $carLoc;
       } else { print "Something went wrong with AI init, exiting\n"; exit 0; }
       if ( ! eval &checkAILocation($carLoc) ) {
               ${$submHref}{loc} = $submLoc;
       } else { print "Something went wrong with AI init, exiting\n"; exit 0; }

       print "Done\n";

}

sub AiTurn {

       # General subroute to have the AI do something after the player takes their turn
       # Main AI turn logic lives here -- extremely basic to start
       # Should not take any arguments

       print MAGENTA, "Starting AI's turn\n", RESET;
       sleep 1;
       # This used to be 50/50, but testing has found having the AI
       # constantly moving around makes the game pretty boring, so make it less likely the AI will move
       my @outcomes = (0,1,2,3,4);
       my $randomNum = int(rand(@outcomes));
       #my $randomNum = 1;

       # Get random ship key and href
       my @availShips;
       foreach my $key ( keys %p2ships ) {
               if ( ! defined $p2ships{$key} ) {
                       next;
               } else {
                       push(@availShips,$key);
               }
       }
       my $randomShipKey = $availShips[rand @availShips];
       #print "AI's random ship is : $randomShipKey\n";
       my $shipHref = $p2ships{$randomShipKey};

       # Make sure AI doesn't try to 'move' if it has no available moves left
       print "Checking available AI moves\n";
       my @availMovers;
       foreach my $key ( keys %p2ships ) {
               my $shipRef = $p2ships{$key};
               if ( ! defined $p2ships{$key} ) {
                       next;
               } elsif ( ${$shipRef}{mc}  == 1 ) {
                       next;
               } else {
                       push(@availMovers, $key);
               }
       }

       my $availM = scalar @availMovers;
       if ( $availM == 0 ) {
               #print "Bumping random number because we're out of moves\n";
               $randomNum = 1;
       }

       if ( $randomNum == 0 ) {
               # Move
               print MAGENTA, "AI is moving!\n", RESET;

               # Get new random location
               my $newRandomLocation = &randomLocation($randomShipKey);
               while ( eval &checkAILocation($newRandomLocation) ) {
                       #print "Conflict in AI random location, rerolling\n";
                       $newRandomLocation = &randomLocation($randomShipKey);
               }

               #print "AI's new random location is : $newRandomLocation\n";

               # Move ship to that location
               if ( ! eval &checkAILocation($newRandomLocation) ) {
                       #print "Setting AI's new location to $newRandomLocation\n";
                       ${$shipHref}{loc} = $newRandomLocation;
                       ${$shipHref}{mc} = 1;
                       print "Updating/cleaning maps\n";
                       @p1Attacks = ("Coors: ");
                       &clearUnocTiles;
               }
       } else {
               # Attack
               # Same logic copy and pasted from player attack sub, with vars changed
               print RED, "AI is attacking!\n", RESET;
               my $randomCoor = int(1 + rand(50 - 1));
               print RED, "AI's chosen attack coordinate is $randomCoor\n", RESET;
               my $ap = ${$shipHref}{ap};
               foreach my $key ( keys %p1ships ) {
                       if ( ! $p1ships{$key} ) {
                               next;
                       }
                       my $playerShipRef = $p1ships{$key};
                       my $playerShipLocation = ${$playerShipRef}{loc};
                       my @playerShipCoors = split(",", $playerShipLocation);
                       if ( grep { $_ eq $randomCoor } @playerShipCoors ) {
                               # Hit !
                               print RED, "Hit!\n", RESET;
                               print RED, "The AI hit your $key for $ap !\n", RESET;
                               # Deterime damage to hull
                               my $playerShipHp = ${$playerShipRef}{hp};
                               my $newPlayerHullValue = $playerShipHp - $ap;
                               if ( $newPlayerHullValue <= 0 ) {
                                       print RED, "The AI sunk your $key !\n", RESET;
                                       # Clear player map of ship and then set ship key to undef
                                       my @sunkenLocation = split(",", ${$playerShipRef}{loc});
                                       foreach my $tile (@sunkenLocation) {
                                               $p1map{$tile} = ".";
                                       }
                                       $p1ships{$key} = undef;
                               } else {
                                       ${$playerShipRef}{hp} = $newPlayerHullValue;
                                       print RED, "Your $key now has ${$playerShipRef}{hp} hp !\n", RESET;
                               }

                               last;

                       } else {
                               # Miss
                               print GREEN, "AI Miss\n", RESET;
                       }
               }

       }
       print "\n";

}

sub playerAttackAI {

       # Perform attack against AI. Takes a coordinate, and ship hashRef as an arg
       # atkCoor is the coordinate to attack
       # $shipHref is a href to the ship that * is attacking *
       #
       # NOTE: This was a more generalized &attack subroutine, but perl
       # didn't like me trying to iterate over a scalar hash dereference, so
       # figured seperate subroutes for each player attack would be the 'easiest' way to
       # do this, as opposed to building a working hash and then repopulating
       # the real map/ships hashes with the updated values from the working hash
       # ... open to suggestions for better ways to do this
       #

       my $atkCoor = shift;
       my $shipHref = shift;

       # Grab attack power
       my $ap = ${$shipHref}{ap};

       # Look at opponents ships and figure out where they are --
       # if the supplied coordinate matches any ship location, start the 'hit' logic, else, miss
       foreach my $key ( keys %p2ships ) {
               if ( ! $p2ships{$key} ) {
                       next;
               }
               my $aiShipRef = $p2ships{$key};
               my $aiShipLocation = ${$aiShipRef}{loc};
               my @AiShipCoors = split(",", $aiShipLocation);
               if ( grep { $_ eq $atkCoor } @AiShipCoors ) {
                       # Hit !
                       print GREEN, "Hit!\n", RESET;
                       print "You hit the AI's $key for $ap !\n";
                       # Deterime damage to hull
                       my $aiShipHp = ${$aiShipRef}{hp};
                       my $newAiHullValue = $aiShipHp - $ap;
                       if ( $newAiHullValue <= 0 ) {
                               print "You sunk the AI's $key !\n";
                               $p2ships{$key} = undef;
                       } else {
                               ${$aiShipRef}{hp} = $newAiHullValue;
                               print "AI's $key now has ${$aiShipRef}{hp} hp !\n";
                       }

                       last;


               } else {
                       # Miss
                       print RED, "Player Miss\n", RESET;
               }
       }


}

sub printMenu {

       print <<EOF
Swatson Battleship
Type 'start','help', or 'quit'

EOF

}

sub printHelp {
       print <<EOF

How To Play:
This is a turn based battleship game. Your objective is to destory the AI ships.
Each turn you can either attack with 1 ship or move 1 ship.
To attack type: attack
To move type: move
To see stats type: stats
Press Ctrl+C to exit any time.

You have 3 ships:
* Cruiser   - Hull Points 2, Size 3, Attack Power 1
* Carrier   - Hull Points 3, Size 5, Attack Power 2
* Submarine - Hull Points 1, Size 2, Attack Power 3

Each turn you will be prompted to either move or attack.
* When attacking, provide a coordinate number ( 1 - 50 ) to fire at
* When moving, provide a comma seperated list of coordinates to move to
* * For cruiser,   provide 3 coordinates
* * For carrier,   provide 5 coordinates
* * For submarine, provide 2 coordinates

EOF

}


&initMap;
&printMap;
&updateMap;
&printMap;

# Menu loop
while () {

       my $count = 0;
       if ( $count == 0 ) {
               &printMenu;
       }
       print "Select option: ";
       my $input = <STDIN>;
       chomp $input;
       if ( $input eq "quit" ) {
               print "Quitting\n";
               exit 0;
       }
       if ( $input eq "help" ) {
               &printHelp;
       }
       if ( $input eq "start" ) {
               my $gameCounter = 0;
               my $aiCounter = 1;
               while () {
                       print "\n\n";
                       # Main game loop
                       if ( $gameCounter == 0 ) {
                               &initAI;
                               &placeShips;
                               &clearUnocTiles;
                               $gameCounter++;
                               next;
                       }

                       if ( ! defined $p2ships{cru} && ! defined $p2ships{subm} && ! defined $p2ships{car} ) {
                               print "You won! Exiting...\n";
                               exit 0;
                       } elsif ( ! defined $p1ships{cru} && ! defined $p1ships{subm} && ! defined $p1ships{car} ) {
                               print "The brain dead AI beat you! Exiting...\n";
                               exit 0;
                       }
                       print GREEN, "! TURN: $gameCounter !\n", RESET;
                       sleep 1;
                       my @opponentRemaining;
                       foreach my $key ( keys %p2ships ) {
                               if ( defined $p2ships{$key} )
                                       { push(@opponentRemaining, $key)
                               }
                       }

                       # Make sure the AI doesn't take an additional turn if
                       # the player makes a typing mistake or calls the stats sub
                       if ( $aiCounter == $gameCounter ) {
                               &AiTurn;
                               $aiCounter++;
                       }

                       my $opShipsLeft = scalar @opponentRemaining;
                       print "\n";
                       print GREEN, "--AI has $opShipsLeft ships left--\n", RESET;
                       &printMap;
                       print "Move or attack: ";
                       my $gameInput = <STDIN>;
                       chomp $gameInput;
                       if ( $gameInput eq "quit" ) {
                               print "Are you sure? : ";
                               my $answer = <STDIN>;
                               chomp $answer;
                               if ( $answer eq "yes" ) {
                                       exit 0;
                               } else {
                                       next;
                               }
                       }
                       if ( $gameInput eq "move" ) {
                               print "What ship do you want to move? : ";
                               my $shipInput = <STDIN>;
                               chomp $shipInput;

                               my @validInputs;
                               foreach my $key ( keys %p1ships ) {
                                       my $shipHref = $p1ships{$key};
                                       my $moveCounter = ${$shipHref}{mc};
                                       if ( ! defined $p1ships{$key} ) {
                                               next;
                                       } elsif ( $moveCounter == 1 ) {
                                               next;
                                       } else {
                                               push(@validInputs,$key);
                                       }
                               }
                               if ( ! grep { $_ eq $shipInput } @validInputs ) {
                                       print "That input looks wrong, try again\n";
                                       next;
                               } else {
                                       print "New coordinates: ";
                                       my $newCoor = <STDIN>;
                                       chomp $newCoor;
                                       if ( $shipInput eq "cru" && $newCoor !~ /^[0-9]*,[0-9]*,[0-9]*$/ ) {
                                               print "Bad coordinates, try again\n";
                                               next;
                                       } elsif ( $shipInput eq "car" && $newCoor !~ /^[0-9]*,[0-9]*,[0-9]*,[0-9]*,[0-9]*$/ ) {
                                               print "Bad coordiantes, try again\n";
                                               next;
                                       } elsif ( $shipInput eq "subm" && $newCoor !~ /^[0-9]*,[0-9]*$/ ) {
                                               print "Bad coordinates, try again\n";
                                               next;
                                       }
                                       if ( eval &checkLocation($newCoor) ) {
                                               print "Coordinates occupied, try again\n";
                                               next;
                                       }

                                       my $shipHref = $p1ships{$shipInput};
                                       &shipPosition($shipHref, $newCoor);
                                       ${$shipHref}{mc} = 1;
                                       &clearUnocTiles;
                                       print "\n";

                               }

                       } elsif ( $gameInput eq "attack" ) {
                               print "What ship do you want to attack with? : ";
                               my $attackShip = <STDIN>;
                               chomp $attackShip;

                               my @validInputs;
                               foreach my $key ( keys %p1ships ) {
                                       if ( ! defined $p1ships{$key} ) {
                                               next;
                                       } else {
                                               push(@validInputs,$key);
                                       }
                               }

                               if ( ! grep { $_ eq $attackShip } @validInputs ) {
                                       print "That input looks wrong, try again\n";
                                       next;
                               } else {
                                       print "Select a single coordinate to attack: ";
                                       my $atkCoor = <STDIN>;
                                       chomp $atkCoor;
                                       my @validCoors = ( 0 .. 50 );
                                       if ( ! grep { $_ eq $atkCoor } @validCoors ) {
                                               print "That doesn't look like a real coordinate, try again\n";
                                               next;
                                       } else {
                                               &playerAttackAI($atkCoor,$p1ships{$attackShip});
                                               push(@p1Attacks,$atkCoor);
                                               print "\n";
                                       }
                               }
                       } elsif ( $gameInput eq "stats" ) {
                               &printPlayerStats;
                               next;
                       } elsif ( $gameInput eq "help" ) {
                               &printHelp;
                               print "\n";
                               next;
                       } else {
                               next;
                       }
                       $gameCounter++;
               }
       }

       $count++;

}