learn-dlang/lesson#9.3/main.d

291 lines
6.6 KiB
D
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Finishing Battleship game
import std.stdio: writeln, write, readf;
import std.conv: to;
import std.random: uniform;
// game states
enum GameState {
MENU, PLAY, HELP, EXIT
}
/*
gameState = MENU; -> mainMenu(); // managing main menu
gameState = HELP; -> help(); // how to play
gameState = PLAY; -> play(); // game logic
gameState = EXIT; -> break out from the loop and quit
*/
immutable int NUM_SHIPS = 10;
void main() {
// gameState variable
GameState gameState = GameState.MENU;
// while gameState does not equal to EXIT, run the game
while(gameState != GameState.EXIT) {
if(gameState == GameState.MENU) {
mainMenu(gameState);
} else if(gameState == GameState.HELP) {
help(gameState);
} if(gameState == GameState.PLAY) {
gamePlay(gameState);
}
}
writeln("Thanks for playing!");
}
// print 30 empty lines (for formatting)
void clear() {
for(int i = 0; i < 30; i++) {
writeln();
}
}
// MENU state: the code for handling main menu
void mainMenu(ref GameState gameState) {
clear();
writeln("Hi and welcome!");
writeln();
writeln("(1) Play");
writeln("(2) Help");
writeln("(3) Exit");
writeln();
write("Choice >> :_");
char c;
readf(" %s", c);
if(c == '1' || c == 'p' || c == 'P') {
gameState = GameState.PLAY;
} else if(c == '2' || c == 'h' || c == 'H') {
gameState = GameState.HELP;
} else if(c == '3' || c == 'e' || c == 'E') {
gameState = GameState.EXIT;
} else {
writeln("\n\nError! Please try again!\n");
}
}
// HELP state: displaying helpful information
void help(ref GameState gameState) {
clear();
writeln("1. Each player must secretly place their ships on a grid \nof ten columns by ten rows.");
writeln("\n2. Each player will also be in possession of a second grid \nof the same size. Where the first grid is their own ships, \nthe second one (which is blank at the beginning of the game) \nis a mirror of their opponents battlefield.");
writeln("\n3. Players pick a square at random, calling it by its row and \ncolumn number. This represents their firing a missile \ndirectly at that square.");
writeln("\n4. The player who successfully locates all their opponents \nships first by hitting each square they occupy is the winner \nas all ships have been destroyed.");
write("\nChoice(2) >> :_");
char c;
readf(" %s", c);
gameState = GameState.MENU;
}
// PLAY state: game logic
void gamePlay(ref GameState gameState) {
clear();
// creating our maps
char[5][5] playerMap = ' ';
char[5][5] enemyMap = ' ';
char[5][5] territory = ' ';
// initializing ships
initShipPos(playerMap); // init player's ships (manually, by the player himself)
initEnemyShipPos(enemyMap); // init enemy's ships (randomization)
int player_ships_destroyed = 0;
int enemy_ships_destroyed = 0;
bool gameWon = false;
while(gameState != GameState.EXIT) {
// displaying player's map
writeln("Your MAP, Captain: ");
display(playerMap);
// displaying empty territory
writeln("\n", "Enemy's hiding somewhere, Captain: ");
display(territory);
writeln("Let's scout the area and attack (", player_ships_destroyed, " of ", NUM_SHIPS, " ships destroyed)!");
// reading user input
char x;
char y;
write("X coord to attack(e to exit): >>_"); readf(" %s", x);
if(x == 'e') { // if input = 'e', exit the game
gameState = GameState.EXIT;
}
write("Y coord to attack(e to exit): >>_"); readf(" %s", y);
if(y == 'e') { // if input = 'e', exit the game
gameState = GameState.EXIT;
}
// converting (x, y) coordinates to integers
int ix = to!int(x - '0');
int iy = to!int(y - '0');
clear(); // clearing the screen by inserting new lines
// if (x, y) coordinates are greater than the length of the map or negative, go to the begining
if(ix < 0 || ix > territory.length-1 || iy < 0 || iy > territory.length-1) {
continue;
}
// if the coordinate isn't empty, go to the begining
if(territory[ix][iy] != ' ') {
continue;
}
// if player hit enemy's ship, mark it with 'x', otherwise mark it with'o'
if(enemyMap[ix][iy] == '1') {
territory[ix][iy] = enemyMap[ix][iy] = 'x';
player_ships_destroyed++;
} else {
territory[ix][iy] = enemyMap[ix][iy] = 'o';
}
// if player destroyed all of the enemy's ships, exit
if(player_ships_destroyed >= NUM_SHIPS) {
gameState = GameState.EXIT;
gameWon = true; // the player has won
}
enemyAttack(playerMap, enemy_ships_destroyed);
// if enemy destroyed all of the player's ships, exit
if(enemy_ships_destroyed >= NUM_SHIPS) {
gameState = GameState.EXIT;
gameWon = false; // the player has lost
}
}
clear();
if(gameWon) {
writeln("YOU WON!");
} else {
writeln("Your MAP, Captain: ");
display(playerMap);
writeln("\nYOU LOST!");
}
}
// read the comments in the gamePlay function, the code is pretty much the same
void initShipPos(ref char[5][5] array) {
int i = 0;
while(i < NUM_SHIPS) {
display(array);
writeln("Enter your ship's position(", i, " of ", NUM_SHIPS," ships):");
char x;
char y;
write("X coord: >>_"); readf(" %s", x);
write("Y coord: >>_"); readf(" %s", y);
int ix = to!int(x - '0');
int iy = to!int(y - '0');
clear();
if(ix < 0 || ix > array.length-1 || iy < 0 || iy > array.length-1) {
writeln("\nERROR! TRY AGAIN!");
continue;
}
if(array[ix][iy] != ' ') {
writeln("\nERROR! SHIP (", ix, ", ", iy, ") ALREADY EXISTS!");
writeln("TRY AGAIN!\n");
continue;
}
array[ix][iy] = '1';
i++;
}
}
// randomizing enemy's ships
void initEnemyShipPos(ref char[5][5] array) {
int i = 0;
while(i < NUM_SHIPS) {
int x = uniform(0, array.length.to!int);
int y = uniform(0, array.length.to!int);
if(array[x][y] != ' ') {
continue;
}
array[x][y] = '1';
i++;
}
}
void enemyAttack(ref char[5][5] array, ref int ships_destroyed) {
while(true) {
int x = uniform(0, array.length.to!int);
int y = uniform(0, array.length.to!int);
// if enemy has already attacked this position, go to the beginig of the loop
if(array[x][y] == 'x' || array[x][y] == 'o') {
continue;
}
// if ship is found, destroy the ship
if(array[x][y] == '1') {
array[x][y] = 'x';
ships_destroyed++;
} else {
array[x][y] = 'o'; // otherwise, mark it with 'o'
}
break;
}
}
// printing the entire array in a table-like format
void display(char[5][5] array) {
write(" ");
for(int i = 0; i < array.length; i++) {
write(" ", i);
}
writeln();
writeln("_ _ _ _ _ _ _ _ _ _ _ _");
for(int i = 0; i < array.length; i++) {
write(i, " ");
for(int j = 0; j < array[i].length; j++) {
write(" | ", array[i][j]);
}
writeln();
writeln("_ _ _ _ _ _ _ _ _ _ _ _");
}
writeln();
writeln();
}