Skip to content

Instantly share code, notes, and snippets.

@naezith
Last active January 8, 2016 20:16
Show Gist options
  • Save naezith/016ead1f2dda2a80a41b to your computer and use it in GitHub Desktop.
Save naezith/016ead1f2dda2a80a41b to your computer and use it in GitHub Desktop.
Battleships Game against AI
// There are 5 ships for you and your enemy and their sizes are 1, 2, 3, 4, 5. Map is 10x10
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define GRID_SIZE 10
typedef struct POINT{ int i, j; } POINT; // Coordinate holder
typedef struct SHIP_PART {
POINT pos; // Position of the part
int hit; // This part hit or not
} SHIP_PART;
typedef struct SHIP {
SHIP_PART parts[5]; // Allocate for the biggest, aircraft carrier
int size; // Size of the ship, 1-5
} SHIP;
SHIP ships[2][5];
// Functions
int randPos(){ return rand() % GRID_SIZE; }; // Return a random position on field
void askForProceed(){
printf(" <Press a key to proceed>");
_getch();
}
void init();
int playerTurn();
int AITurn();
void printFields();
SHIP* getShip(int AI_field, int i, int j);
SHIP_PART* getPart(SHIP* ship, int i, int j);
int allShipsSunk(int AI_Field);
// Returns the ship if there is, in the position n, m
SHIP* getShip(int AI_field, int i, int j){
int k, l;
for(k = 0; k < 5; ++k){
SHIP* curr_ship = &ships[AI_field][k];
for(l = 0; l < curr_ship->size; ++l){
POINT* pos = &curr_ship->parts[l].pos;
if(pos->i == i && pos->j == j) return curr_ship; // Found ship
}
}
return NULL; // No ships in this position
}
// Returns the part of the ship for the given position
SHIP_PART* getPart(SHIP* ship, int i, int j){
int k;
for(k = 0; k < ship->size; ++k) {
POINT* pos = &ship->parts[k].pos;
if(pos->i == i && pos->j == j) return &ship->parts[k]; // Found part
} return NULL;
}
int difficulty; // Enemy's accuracy
int shot_before[GRID_SIZE][GRID_SIZE] = {0};
void init(){
// Get difficulty input from player
printf("\n BATTLESHIPS \n Enter difficulty(0-100): ");
scanf("%d", &difficulty);
if(difficulty > 100) difficulty = 100;
if(difficulty < 0) difficulty = 0;
// Clean parts
int k, i, j;
for(j = 0; j < 2; ++j){ // Loop player and AI fields
for(k = 0; k < 5; ++k){ // Loop all ships
SHIP* curr_ship = &ships[j][k];
curr_ship->size = k + 1; // Set current ship's size
// Reset all parts
for(i = 0; i < curr_ship->size; ++i){
curr_ship->parts[i].hit = 0;
curr_ship->parts[i].pos.i = curr_ship->parts[i].pos.j = -1;
}
}
}
// Randomly place ships
for(j = 0; j < 2; ++j){ // Loop player and AI fields
for(k = 0; k < 5; ++k){ // Loop all ships
SHIP* curr_ship = &ships[j][k];
int placed = 0; // Did we place the ship?
POINT part_coords[5]; // We will fill this with future ship part coordinates
int vertical = rand() % 2; // Is it vertically placed or not
while(!placed){
// Find an empty start coordinate
do { part_coords[0].i = randPos(); part_coords[0].j = randPos();
} while(getShip(j, part_coords[0].i, part_coords[0].j) != NULL);
// Put other ship parts
int i;
POINT start = part_coords[0];
for(i = 1; i < curr_ship->size; ++i){
// Place vertically if place is empty
if(vertical && getShip(j, start.i + i, start.j) == NULL){
part_coords[i].i = start.i + i;
part_coords[i].j = start.j;
}
// Place horizontally if place is empty
else if(!vertical && getShip(j, start.i, start.j + i) == NULL){
part_coords[i].i = start.i;
part_coords[i].j = start.j + i;
}
else break; // There is ship in this place, find another start position
// Out of the grid, find another start position
if(part_coords[i].i >= GRID_SIZE || part_coords[i].j >= GRID_SIZE) break;
}
// Place the ship if we found enough empty area
if(i == curr_ship->size){
for(i = 0; i < curr_ship->size; ++i) curr_ship->parts[i].pos = part_coords[i];
placed = 1;
}
}
}
}
}
int playerTurn(){
// Take coordinate to shoot torpedo at
int i, j;
printf("\n Your turn to attack, commander! Give me a coordinate to shoot at\n x << ");
scanf("%d", &j);
printf(" y << ");
scanf("%d", &i);
int hit = 0; // Did we hit?
SHIP* ship = getShip(1, i, j);
if(ship == NULL) hit = 0; // Miss
else{ // Hit
SHIP_PART* part = getPart(ship, i, j);
if(part->hit){ // Already hit this place
printf("\n ... We shot that coordinate before, commander!");
return playerTurn();
}
part->hit = hit = 1;
}
shot_before[i][j] = 1; // Mark this place
printFields(); // Refresh the map
if(hit) printf("\n We hit them, sir!");
else printf(" You missed, sir.");
if(allShipsSunk(1)){ // Did we win?
printf("\n Sir! We just destroyed all the enemy ships! We won this battle!");
return 1;
}
askForProceed();
return 0;
}
int allShipsSunk(int AI_Field){
int i, j;
for(i = 0; i < 5; ++i){
SHIP* ship = &ships[AI_Field][i];
for(j = 0; j < ship->size; ++j){
if(!ship->parts[j].hit) return 0;
}
}
return 1;
}
int AITurn(){
printf("\n It is their turn to attack, sir!");
askForProceed();
// Will the AI hit or not? This also depends on difficulty
if(rand() % 100 < difficulty){ // Hit
int will_hit = 1;
while(will_hit){ // Find a part we did not hit yet
SHIP* ship = &ships[0][rand() % 5];
SHIP_PART* part = &ship->parts[rand() % ship->size];
if(part->hit) will_hit = 1; // Shoot again
else{ // This is a non-hit part, hit it!
part->hit = 1;
will_hit = 0;
printFields();
printf("\n They hit our ship, sir!");
}
}
}
else printf("\n Enemy torpedo missed our ships!");
if(allShipsSunk(0)){ // Did AI win?
printf("\n ***ALL OF YOUR SHIPS ARE DESTROYED, YOU LOST!***");
return 1;
}
askForProceed();
return 0;
}
int main(){
srand(time(0)); // For better randomness
system("color 1F"); // Set background blue and text color white
init(); // Make the game ready to play
do{ printFields(); } while(!playerTurn() && !AITurn()); // Play until somebody wins
return 0;
}
void printFields(){
system("CLS");
int i, j;
printf("\n BATTLESHIPS GAME ");
printf("\n You Enemy\n ");
for(j = 0; j < GRID_SIZE; ++j) printf(" %d ", j);
printf(" ");
for(j = 0; j < GRID_SIZE; ++j) printf(" %d ", j);
printf("\n ");
for(j = 0; j < GRID_SIZE; ++j) printf(" _ ");
printf(" ");
for(j = 0; j < GRID_SIZE; ++j) printf(" _ ");
printf("\n");
for(i = 0; i < GRID_SIZE; ++i){
printf(" %d |", i);
// Your area
for(j = 0; j < GRID_SIZE; ++j){
SHIP* ship = getShip(0, i, j);
if(ship != NULL){
SHIP_PART* part = getPart(ship, i, j);
printf(" %c ", part->hit ? 'X' : '0' + ship->size);
}
else printf(" . ");
}
printf(" %d |", i);
// Enemy area
for(j = 0; j < GRID_SIZE; ++j){
SHIP* ship = getShip(1, i, j);
if(ship != NULL){
SHIP_PART* part = getPart(ship, i, j);
printf(" %c ", part->hit ? 'X' : '.');
}
else printf(" %c ", shot_before[i][j] ? 'O' : '.');
}
printf("\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment