#!/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++;

}