Advertisement
Guest User

Untitled

a guest
Jun 27th, 2017
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 43.14 KB | None | 0 0
  1. #include <cstdio>
  2. #include <iostream>
  3. #include <windows.h>
  4. #include <ctime>
  5.  
  6. using namespace std;
  7.  
  8. #define ROW 10
  9. #define COL 10
  10.  
  11. // The size of each type of ship
  12. #define S_CARRIER 5
  13. #define S_BATTLESHIP 4
  14. #define S_DESTROYER 3
  15. #define S_SUBMARINE 3
  16. #define S_PATROLBOAT 2
  17.  
  18. #define BOATCOUNT 5
  19.  
  20. #define UP 1
  21. #define DOWN 2
  22. #define RIGHT 3
  23. #define LEFT 4
  24.  
  25. // Defines for the deck in ai_attack_random();
  26. #define D_ROW 0
  27. #define D_COL 1
  28. #define D_SCORE 2
  29. #define D_SIZE 3 // col size in the 2d array
  30.  
  31. #define AI_ACCURACY_ADJACENT 50 // Modifier defining how likely the AI is to attack spaces adjacent to hits.  0 = never, 34 + 4 * AI_ACCURACY_DIAGONAL = always
  32. #define AI_ACCURACY_DIAGONAL 8 // Modifier that tweaks accuracy of AI attacking spaces adjacent to hits. 0 = inaccurate, AI_ACCURACY_ADJACENT / 4 makes AI dumb as a brick
  33.  
  34. enum hit {
  35.   BLANK = ' ',
  36.   MISS = '*',
  37.   HIT = 'x',
  38.   CARRIER = 'C',
  39.   BATTLESHIP = 'B',
  40.   DESTROYER = 'D',
  41.   SUBMARINE = 'S',
  42.   PATROLBOAT = 'P'
  43. };
  44.  
  45. // Various prototypes for the functions
  46. void welcome_display();
  47. bool play();
  48.  
  49. void player_populate(hit players_board_def[ROW][COL]);
  50. void boat_check(hit players_board_def[ROW][COL], int boat_type);
  51.  
  52. void board_display(hit board[ROW][COL]);
  53. void board_display(hit board[ROW][COL], const hit ref[ROW][COL]);
  54.  
  55. bool is_sunk(hit boat, hit board[ROW][COL], const hit ref[ROW][COL]);
  56. bool is_game_over(hit board[ROW][COL], const hit ref[ROW][COL]);
  57.  
  58. int hit2space(int space);
  59. int hit2string(int space);
  60.  
  61. void ai_attack(hit board[ROW][COL], int &x, int &y);
  62. void ai_attack_random(hit board[ROW][COL], int &col, int &row, int boats[BOATCOUNT], int boatsize);
  63. int ai_calculate_score(hit board[ROW][COL], int r, int c, const int boats[BOATCOUNT], const int boatsize);
  64. void ai_sort_deck(int scores[][D_SIZE], int rows);
  65.  
  66. void player_attack(const hit computer_const_board_ref[ROW][COL], hit player_board_off[ROW][COL], int &r, int &c);
  67. void process_attack_off(hit offense[ROW][COL], const hit reference[ROW][COL], int r, int c);
  68. void process_attack_def(hit defense[ROW][COL], const hit reference[ROW][COL], int r, int c);
  69.  
  70. void placeBoat(hit board[][COL]);
  71. void direction(hit board[][COL],int randDirection,int x, int y,int limit, hit boatType);
  72. bool checkBlank(hit board[][COL], const int x, const int y, const int limit, int direction);
  73.  
  74. /*********************************************************************************************************
  75. Purpose: This is the main function that continues while the user wants to start a new game and exits when
  76. the user no longer wants to play anymore games with our awesome AI
  77.  
  78. Input: Nothing
  79.  
  80. Returns: Nothing
  81. *********************************************************************************************************/
  82. int main()
  83. {
  84.     srand(time(NULL));
  85.     bool valid=true;
  86.  
  87.     // Clears the screen then displays a graphic for the startup of the program
  88.     welcome_display();
  89.    
  90.     do{
  91.         valid = play();
  92.     }while (valid);
  93.  
  94.     printf("\n ");
  95.     system("pause");
  96. }
  97.  
  98. /*********************************************************************************************************
  99. Purpose: This is where all of the gameplay happens, from getting the user to fill their board to the computer
  100. filling its board. To then playing the game until a winner is declared.
  101.  
  102. Input: Nothing
  103.  
  104. Returns: new_game - This determines whether or not the user wants to start a new game
  105. *********************************************************************************************************/
  106. bool play(){
  107.  
  108.     bool valid;
  109.     bool new_game;
  110.     char choice;
  111.     int x=0;
  112.     int r, c;
  113.     bool computer = false, player=false;
  114.    
  115.     // For the players own board
  116.     hit player_board_def[ROW][COL];
  117.     hit computer_board_def[ROW][COL];
  118.    
  119.     // Invisible reference board keeping track of boat locations... ((Should be const))
  120.     hit player_const_board_ref[ROW][COL];
  121.     hit computer_const_board_ref[ROW][COL];
  122.        
  123.     // For the board the players will be attacking
  124.     hit player_board_off[ROW][COL];
  125.     hit computer_board_off[ROW][COL];
  126.    
  127.     for(int i = 0; i < ROW; i++)
  128.            for(int j = 0; j < COL; j++)
  129.                player_board_def[i][j] = computer_board_def[i][j] = player_const_board_ref[i][j] = computer_const_board_ref[i][j] = player_board_off[i][j] = computer_board_off[i][j] = BLANK;
  130.  
  131.     player_populate(player_board_def);
  132.     printf("\nYour board is...\n");
  133.     board_display(player_board_def, player_const_board_ref);
  134.  
  135.     printf("\n\n The computer players 'random' board is... \n ");
  136.     placeBoat(computer_board_def);
  137.     board_display(computer_board_def);
  138.    
  139.     system("pause");
  140.     system("cls");
  141.    
  142.     // Assume all boards are set at this point so copy said boards
  143.     for(int i = 0; i < ROW; i++)
  144.         for(int j = 0; j < COL; j++){
  145.         player_const_board_ref[i][j] = player_board_def[i][j];
  146.         computer_const_board_ref[i][j] = computer_board_def[i][j];
  147.         }
  148.    
  149.     do{
  150.         ai_attack(computer_board_off, c, r); // Get coordinates to attack
  151.         process_attack_off(computer_board_off, player_const_board_ref, r, c); // Attack on offensive board
  152.         process_attack_def(player_board_def, player_const_board_ref, r, c); // Attack on defensive board
  153.         printf("\n AI has attacked %c%d\n", c+'A', r);
  154.         if(is_sunk(player_board_ref[r][c], player_board_def, player_const_board_ref))
  155.             printf("\n AI has sunk %s!", hit2string((int) player_const_board_ref[r][c]));
  156.                
  157.         printf("\n Human player's board...\n");
  158.         board_display(player_board_def, player_const_board_ref);
  159.         computer = is_game_over(player_board_def, player_const_board_ref); // Make sure computer hasn't already won
  160.                
  161.         printf("\n Computer player's board...\n");
  162.         board_display(player_board_off);
  163.                        
  164.         if(!computer){
  165.             player_attack(computer_const_board_ref, player_board_off, r, c); // Get coordinates to attack
  166.             process_attack_off(player_board_off, computer_const_board_ref, r, c); // Attack on offensive board
  167.             process_attack_def(computer_board_def, computer_const_board_ref, r, c); // Attack on defensive board
  168.                                    
  169.             // printf(" Human has attacked %c%d\n", c+'A', r);
  170.             player = is_game_over(computer_board_def, computer_const_board_ref); // Make sure player hasn't already won
  171.         }
  172.                
  173.         system("cls");
  174.     }while (!player && !computer); // Exit when someone wins
  175.    
  176.     printf("\n GAME OVER. %s player won!\n", computer ? "Computer" : "Human");
  177.  
  178.     board_display(player_board_off);
  179.     board_display(computer_board_def);
  180.  
  181.     // This is just to ask if you want to make a new game or not. Based on that it will start a new game or quit
  182.     // This can be put in a separate function if needed later...
  183.     do{
  184.         printf("\n\n Do you want to start a new game? (y/n): ");
  185.         scanf("%c", &choice);
  186.         fflush(stdin);
  187.         switch (toupper(choice)){
  188.             case 'Y':
  189.                 x=1;
  190.                 new_game=true;
  191.                 break;    
  192.             case 'N':
  193.                 x=2;
  194.                 new_game=false;
  195.                 break;
  196.             default:
  197.                 printf("\n\n Incorrect option entered, please choose again\n\n");
  198.                 x=3;
  199.         }
  200.     }while (x==3);
  201.     return (new_game);
  202. }
  203.  
  204. /*********************************************************************************************************
  205. Purpose: Process an attack on the offensive board.  Translate sinks into boat types so the player/computer
  206.         can figure out what type of boat he just sunk.
  207.  
  208. Input:  hit offense[ROW][COL]                   offense board to modify
  209.                 const hit reference[ROW][COL]   reference board to check for ships
  210.                 int r                                                   Row to aim at
  211.                 int c                                                   Column to aim at
  212.  
  213. Returns: Nothing
  214. *********************************************************************************************************/
  215. void process_attack_off(hit offense[ROW][COL], const hit reference[ROW][COL], int r, int c)
  216. {
  217.         if(reference[r][c] != BLANK)
  218.         {
  219.                 offense[r][c] = HIT;
  220.                 if(is_sunk(reference[r][c], offense, reference))
  221.                         for(int i = 0; i < ROW; i++)
  222.                                 for(int j = 0; j < COL; j++)
  223.                                         if(reference[i][j] == reference[r][c])
  224.                                                 offense[i][j] = reference[r][c];
  225.         }
  226.         else
  227.         {
  228.                 offense[r][c] = MISS;
  229.         }
  230. }
  231.  
  232. /*********************************************************************************************************
  233. Purpose: Process an attack on the defensive board, add hits when needed and misses where necessary.  DO
  234.         NOT translate sinks.
  235.  
  236. Input:  hit defense[ROW][COL]                   defensive board to modify
  237.                 const hit reference[ROW][COL]   reference board to check for ships
  238.                 int r                                                   Row to aim at
  239.                 int c                                                   Column to aim at
  240.  
  241. Returns: Nothing
  242. *********************************************************************************************************/
  243. void process_attack_def(hit defense[ROW][COL], const hit reference[ROW][COL], int r, int c)
  244. {
  245.         // This tests if the coordinate entered by the user is a ship piece on the computers board, if it is then
  246.         // we mark it as a hit. If it equals a blank spot on the computers board then it equals a miss.
  247.         if (reference[r][c] != BLANK)
  248.         defense[r][c] = HIT;
  249.     else
  250.         defense[r][c] = MISS;
  251. }
  252.  
  253. /*********************************************************************************************************
  254. Purpose: This function simply grabs input from the user for the coordinates they wish to attack
  255.  
  256. Input:  const hit computer_const_board_ref[ROW][COL], hit player_board_off[ROW][COL], int &r, int &c
  257.  
  258. Returns: Nothing
  259. *********************************************************************************************************/
  260. void player_attack(const hit computer_const_board_ref[ROW][COL], hit player_board_off[ROW][COL], int &r, int &c){
  261.    
  262.     char coord[3]={0};
  263.     char tchar;
  264.     bool valid;
  265.  
  266.  
  267.     do{  
  268.         do{
  269.             valid = true;
  270.             printf("\n Enter the coordinate you want to attack: ");
  271.                 fgets(coord, 3, stdin);
  272.                 fflush(stdin);
  273.                 strupr(coord);
  274.                 if(!isalpha(coord[0])){
  275.                         tchar = coord[0];
  276.                         coord[0] = coord[1];
  277.                         coord[1] = tchar;
  278.                 }
  279.                 if ((coord[0] < 'A' || coord[0] > 'J') || (coord[1] <'0' || coord[1] >'9')){
  280.                 printf("\n Incorrect coordinate entered. Please choose again.\n");
  281.                 valid = false;
  282.             }else
  283.                 valid = true;
  284.         }while (!valid);
  285.  
  286.         coord[0] -= 'A';
  287.         coord[1] -= '0';
  288.        
  289.         // This checks to make sure the spot the user choose is actually a blank spot so that way they
  290.         // cannot attack the same spot twice.
  291.         if (player_board_off[coord[1]][coord[0]] != BLANK){
  292.             printf("\n That coordinate has already been attacked. Please choose again.\n");
  293.             valid = false;
  294.         }
  295.  
  296.         }while (!valid);
  297.  
  298.     printf(" You are attacking: %c%d\n", coord[0] + 'A', coord[1]);
  299.     r = coord[1];
  300.     c = coord[0];
  301. }
  302.  
  303. /*********************************************************************************************************
  304. Purpose: This is to have the player choose which boat they want to place and then proceed to
  305. another function that based on the boat choosen will ask for coordinates and valid them. This continues
  306. until all boats have been placed.
  307.  
  308. Input: hit board[ROW][COL]
  309.  
  310. Returns: Nothing
  311. *********************************************************************************************************/
  312. void player_populate(hit player_board_def[ROW][COL]){
  313.    
  314.     int boattypes[5] = { CARRIER, BATTLESHIP, DESTROYER, SUBMARINE, PATROLBOAT };
  315.     bool boatplaced[5] = { false } ;
  316.     int boats = 0;
  317.     int choice;
  318.     bool valid;
  319.    
  320.     printf("\n");
  321.    
  322.     do{
  323.         do{
  324.             valid = true;
  325.             board_display(player_board_def);
  326.             printf("\n 1) Aircraft Carrier\n 2) Battleship\n 3) Destroyer\n 4) Submarine\n 5) Patrol Boat\n\n");
  327.             printf(" Choose which ship you want to place: ");
  328.             scanf("%d", &choice);
  329.             fflush(stdin);
  330.             if (choice > 0 && choice < 6){
  331.                 valid = true;
  332.             }else{
  333.                 printf("\n Incorrect option entered. Please choose again.\n\n");
  334.                 valid = false;
  335.             }
  336.         }while (!valid);
  337.        
  338.         choice--;
  339.         if(!boatplaced[choice]){ // Keeping track of which boats we have placed
  340.             boat_check(player_board_def, boattypes[choice]);
  341.             boats++; // Number of boats we have placed so far, when 5 stop placing boats.
  342.             boatplaced[choice] = true;
  343.         }else{
  344.             printf("\n You have already placed that ship. Please choose a different ship.\n\n ");
  345.             system("pause");
  346.         }
  347.         system("cls");
  348.     }while (boats < 5);
  349. }
  350.  
  351. /*********************************************************************************************************
  352. Purpose: This is to have the player choose which boat they want to place and then proceed to
  353. another function that based on the boat choosen will ask for coordinates and valid them. This continues
  354. until all boats have been placed.
  355.  
  356. Input: hit player_board_def[ROW][COL]
  357.  
  358. Returns: Nothing
  359. *********************************************************************************************************/
  360. void boat_check(hit player_board_def[ROW][COL], int boat_type)
  361. {
  362.         char coord1[3]={0};
  363.     char coord2[3]={0};
  364.     char tchar;
  365.     bool valid;
  366.        
  367.     do{
  368.                 valid = true;
  369.                
  370.                 // Input & validation for the start coordinates from the user
  371.                 do{
  372.                         printf("\n Enter first coordinate: ");
  373.                         fgets(coord1, 3, stdin);
  374.                         fflush(stdin);
  375.                         strupr(coord1);
  376.                         if(!isalpha(coord1[0])){
  377.                                 tchar = coord1[0];
  378.                                 coord1[0] = coord1[1];
  379.                                 coord1[1] = tchar;
  380.                         }
  381.         }while ((coord1[0] < 'A' || coord1[0] > 'J') && (coord1[0] <'0' || coord1[0] >'9'));
  382.        
  383.         // Input & validation for the end coordinates from the user      
  384.         do{
  385.                         printf(" Enter second coordinate: ");
  386.             fgets(coord2, 3, stdin);
  387.             fflush(stdin);
  388.             strupr(coord2);
  389.             if(!isalpha(coord2[0])){
  390.                                 tchar = coord2[0];
  391.                 coord2[0] = coord2[1];
  392.                 coord2[1] = tchar;
  393.                         }
  394.                 }while ((coord2[1] < 'A' || coord2[1] > 'J') && (coord2[1] <'0' || coord2[1] >'9'));
  395.                
  396.         // This changes the chars in the arrays to an actual number so that we can use them to interface
  397.         // with the location in the array it corrisponds to.
  398.         coord1[0] -= 'A';
  399.         coord1[1] -= '0';
  400.         coord2[0] -= 'A';
  401.         coord2[1] -= '0';
  402.                
  403.         // This checks the inputted numbers to see if they are valid by one of the element pairs being equal
  404.         // to each other. Such as if you have A2 & D2 as the coordinates the second element in both arrays
  405.         // are the same or if you have A2 & A5, the 'A's are the same (This verifies that the start & end points
  406.         // are truly in a horizontal or vertical line)
  407.                
  408.         if ((coord1[0]==coord2[0] && coord1[1]!=coord2[1]) || (coord1[0]!=coord2[0] && coord1[1]==coord2[1]))
  409.                 {
  410.                         for(int i = 0; i < 2; i++)
  411.             {
  412.                                 if(coord1[i] > coord2[i]) // Exchange coordinates to make 2nd larger than 1st
  413.                 {
  414.                                         for(int j = 0; j < 2; j++)
  415.                     {
  416.                                                 tchar = coord1[j];
  417.                         coord1[j] = coord2[j];
  418.                         coord2[j] = tchar;
  419.                                         }
  420.                                 }
  421.             }
  422.                        
  423.             // We have already guaranteed that at least 1 is the same, so we can MATHS to divine the boat size and determine its valid
  424.             if((coord2[0] - coord1[0]) + (coord2[1] - coord1[1]) + 1 != hit2space(boat_type))
  425.                                 valid = false;
  426.                        
  427.                         for(int i = coord1[0]; i <= coord2[0]; i++) // Checking horizontal
  428.                                 if(player_board_def[coord1[1]][i] != BLANK)
  429.                                         valid = false;
  430.                        
  431.                         for(int i = coord1[1]; i <= coord2[1]; i++) // Checking vertical
  432.                                 if(player_board_def[i][coord1[0]] != BLANK)
  433.                                         valid = false;
  434.                        
  435.                 }
  436.                 // If none of the previous checks have not been met then the coordinates cannot be
  437.         // correct therefore we must ask again
  438.         else
  439.         {
  440.                         valid = false;
  441.                 }
  442.         if (!valid)
  443.                 printf("\n Incorrect coordinates entered, please choose again\n");
  444.         } while (!valid);
  445.        
  446.     for(int i = coord1[0]; i <= coord2[0]; i++)
  447.                 player_board_def[coord1[1]][i] = (hit) boat_type; // Or respective boat type
  448.        
  449.         for(int i = coord1[1]; i <= coord2[1]; i++)
  450.                 player_board_def[i][coord1[0]] = (hit) boat_type; // Or respective boat type
  451. }
  452.  
  453.  
  454. /*********************************************************************************************************
  455. Purpose: This function simply prints out any array it is given in the board format that the battleship
  456. game is supposed to be displayed in
  457.  
  458. Input: hit board[ROW][COL]
  459.  
  460. Returns: Nothing
  461. *********************************************************************************************************/
  462. void board_display(hit board[ROW][COL]){
  463.  
  464.     char letters_array[11]={' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
  465.  
  466.     // This is for displaying the first line of dashes
  467.     for (int z=0; z < 4*COL+4; z++){
  468.         printf("-");
  469.     }
  470.     printf("\n");
  471.    
  472.     // This is for displaying A-J
  473.     for (int x=0; x < 11; x++){
  474.         printf(" %c |", letters_array[x]);
  475.     }
  476.     printf("\n");    
  477.    
  478.     // These for loops are for making the board dynamically based on the #define values and displays
  479.     // what is in the array in the board format accordingly
  480.     for (int x=0, y=0; x < ROW; x++, y++){
  481.         for (int z=0; z < 4*COL+4; z++){
  482.            printf("-");
  483.         }
  484.         printf("\n");
  485.        
  486.         // This is for displaying 0-9
  487.         printf(" %d |", y);
  488.        
  489.         // This is for displaying the contents of the element of the array we are currently at
  490.         for (int y=0; y < COL; y++){
  491.             printf(" %c |", board[x][y]);
  492.         }
  493.         printf("\n");
  494.     }
  495.  
  496.     // This is for displaying the last line of dashes
  497.     for (int z=0; z < 4*COL+4; z++){
  498.         printf("-");
  499.     }
  500.     printf("\n");
  501. }    
  502.  
  503. /*********************************************************************************************************
  504. Purpose: This is the overloaded version of the function that prints out any array it is given in the board
  505. format that the battleship game is supposed to be displayed in. This functions takes two boards
  506.  
  507. Input: hit board[ROW][COL] & hit ref[ROW][COL]
  508.  
  509. Returns: Nothing
  510. *********************************************************************************************************/
  511. void board_display(hit board[ROW][COL], const hit ref[ROW][COL]){
  512.  
  513.     char letters_array[11]={' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
  514.  
  515.     // This is for displaying the first line of dashes
  516.     for (int z=0; z < 4*COL+4; z++){
  517.         printf("-");
  518.     }
  519.     printf("\n");
  520.    
  521.     // This is for displaying A-J
  522.     for (int x=0; x < 11; x++){
  523.         printf(" %c |", letters_array[x]);
  524.     }
  525.     printf("\n");    
  526.    
  527.     // These for loops are for making the board dynamically based on the #define values and displays
  528.     // what is in the array in the board format accordingly
  529.     for (int x=0, y=0; x < ROW; x++, y++){
  530.         for (int z=0; z < 4*COL+4; z++){
  531.            printf("-");
  532.         }
  533.         printf("\n");
  534.        
  535.         // This is for displaying 0-9
  536.         printf(" %d |", y);
  537.        
  538.         // This is for displaying the contents of the element of the array we are currently at
  539.         for (int y=0; y < COL; y++){
  540.             printf(" %c |", is_sunk(ref[x][y], board, ref) ? tolower(ref[x][y]) : board[x][y]);
  541.         }
  542.         printf("\n");
  543.     }
  544.  
  545.     // This is for displaying the last line of dashes
  546.     for (int z=0; z < 4*COL+4; z++){
  547.         printf("-");
  548.     }
  549.     printf("\n");
  550. }
  551.  
  552. /*********************************************************************************************************
  553. Purpose: Determine whether or not all the boats on a board have been sunk
  554.  
  555. Input:  hit board[ROW][COL]             Board to look for sunken boats
  556.                 const hit ref[ROW][COL] Reference board for ship placement
  557.  
  558. Returns: bool                                   True if all boats are sunk, false otherwise.
  559. *********************************************************************************************************/
  560. bool is_game_over(hit board[ROW][COL], const hit ref[ROW][COL])
  561. {
  562.         hit boats[BOATCOUNT] = { CARRIER, BATTLESHIP, DESTROYER, SUBMARINE, PATROLBOAT };
  563.         int sinks = BOATCOUNT;
  564.        
  565.         for(int i = 0; i < BOATCOUNT; i++)
  566.                 if(is_sunk(boats[i], board, ref))
  567.                         sinks--;
  568.         return !sinks;
  569. }
  570.  
  571. /*********************************************************************************************************
  572. Purpose: Function to determine if a single boat has sunk already
  573.  
  574. Input:  hit boat                                Boat to check if has sunk
  575.                 hit board[ROW][COL]             Gameboard to check
  576.                 const hit ref[ROW][COL] Reference board to refer to for boat placement
  577.  
  578. Returns: bool                                   True if boat has sunk, false otherwise
  579. *********************************************************************************************************/
  580. bool is_sunk(hit boat, hit board[ROW][COL], const hit ref[ROW][COL])
  581. {
  582.         int size = hit2space(boat);
  583.         if(!size)
  584.                 return false;
  585.        
  586.         for(int i = 0; i < ROW; i++)
  587.                 for(int j = 0; j < COL; j++)
  588.                         if(ref[i][j] == boat && board[i][j] == HIT)
  589.                                 size--;
  590.         return (!size);
  591. }
  592.  
  593. /*********************************************************************************************************
  594. Purpose: Returns the number of spaces that the passed boat will take up.  A glorified switch statement, but
  595.         used everywhere.
  596.  
  597. Input:  int space               type of boat to check
  598.  
  599. Returns: int            Number of spaces that the ship will take up, counting from 1.  EG. Carrier would return 5
  600. *********************************************************************************************************/
  601. int hit2string(int space)
  602. {
  603.         switch(space)
  604.         {
  605.                 case CARRIER:           return S_CARRIER;
  606.                 case BATTLESHIP:        return S_BATTLESHIP;
  607.                 case DESTROYER:         return S_DESTROYER;
  608.                 case SUBMARINE:         return S_SUBMARINE;
  609.                 case PATROLBOAT:        return S_PATROLBOAT;
  610.                 default:                        return 0;
  611.     }
  612. }
  613.  
  614. /*********************************************************************************************************
  615. Purpose: Returns the number of spaces that the passed boat will take up.  A glorified switch statement, but
  616.         used everywhere.
  617.  
  618. Input:  int space               type of boat to check
  619.  
  620. Returns: int            Number of spaces that the ship will take up, counting from 1.  EG. Carrier would return 5
  621. *********************************************************************************************************/
  622. char *hit2string(int space)
  623. {
  624.         switch(space)
  625.         {
  626.                 case CARRIER:                   return "Carrier";
  627.                 case BATTLESHIP:                return "Battleship";
  628.                 case DESTROYER:                 return "Destroyer";
  629.                 case SUBMARINE:                 return "Submarine";
  630.                 case PATROLBOAT:                return "Patrol Boat";
  631.                 case MISS:                              return "Miss";
  632.                 case HIT:                               return "Hit";
  633.                 case BLANK:                             return "BLANK";
  634.         }
  635. }
  636.  
  637. /*********************************************************************************************************
  638. Purpose: This just prints out the first screen to display with a cool ascii graphic for the player to see
  639.  
  640. Input: Nothing
  641.  
  642. Returns: Nothing
  643. *********************************************************************************************************/
  644. void welcome_display(){
  645.    
  646.     // This just gives time for the user so they can fullscreen the command prompt to be able to see
  647.     // the game without scrolling up & down
  648.     printf("\n Loading; Please wait");
  649.     for (int x=0; x<3; x++){
  650.         printf(". ");
  651.         Sleep(1150);
  652.     }
  653.     system("cls");
  654.    
  655.     // This is fairly obvious that this is the title and graphic that is displayed when you start the program
  656.     printf("\n");
  657.     printf("\t\t\t\tWelcome to\n");
  658.     printf("\t\t\t     ================\n");
  659.     printf("   ____              __    __    ___                   __                    \n");
  660.     printf("  /\\  _`\\           /\\ \\__/\\ \\__/\\_ \\                 /\\ \\      __           \n");
  661.     printf("  \\ \\ \\_\\ \\     __  \\ \\ ,_\\ \\ ,_\\//\\ \\      __    ____\\ \\ \\___ /\\_\\  _____   \n");
  662.     printf("   \\ \\  _ <'  /'__`\\ \\ \\ \\/\\ \\ \\/ \\ \\ \\   /'__`\\ /',__\\\\ \\  _ `\\/\\ \\/\\ '__`\\ \n");
  663.     printf("    \\ \\ \\_\\ \\/\\ \\_\\.\\_\\ \\ \\_\\ \\ \\_ \\_\\ \\_/\\  __//\\__, `\\\\ \\ \\ \\ \\ \\ \\ \\ \\_\\ \\\n");
  664.     printf("     \\ \\____/\\ \\__/.\\_\\\\ \\__\\\\ \\__\\/\\____\\ \\____\\/\\____/ \\ \\_\\ \\_\\ \\_\\ \\ ,__/\n");
  665.     printf("      \\/___/  \\/__/\\/_/ \\/__/ \\/__/\\/____/\\/____/\\/___/   \\/_/\\/_/\\/_/\\ \\ \\/ \n");
  666.     printf("                                                                       \\ \\_\\ \n");    
  667.     printf("   Developers:                                                          \\/_/ \n");
  668.     printf("                                      #    _                                    ");
  669.     printf("   Larry Ing                       _ # #  (.)\n");
  670.     printf("   Luke Kontes               =====|_|#_#___|__                                  ");
  671.     printf("   Erich Healy                _  |____________|  _                              ");
  672.     printf("   Mark de Guzman       =====|.| | .  .  .  . | |.|====                         ");
  673.     printf("                       _ .---------------------------. _                        ");
  674.     printf("                 =====|.||  .  .  .  .  .  .  .  .   ||.|====\n");
  675.     printf("   \\---------------------'                           `--------------/\n");
  676.     printf("    \\ .  .  .  .           .  .  .  .        .  .  .  .     USS-42 /\n");
  677.     printf("     \\          .  .  .  .           .  .  .           .  .  .  . /\n");
  678.     printf("      \\__________________________________________________________/\n");
  679.     printf("  wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww\n");
  680.     printf(" wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww\n");
  681.     printf("   wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww \n");
  682.     printf("\n");
  683.     printf("\n ");    
  684.    
  685.     // Possibly use a sleep instead here...
  686.     system("pause");
  687.     system("cls");    
  688. }
  689.  
  690. /*********************************************************************************************************
  691. Purpose: This is the main attacking function for the AI.  It gathers information about the board and passes it
  692.         off to the other AI functions.  Coordinates to attack are passed by reference.
  693.  
  694. Input:  hit board[ROW][COL]             Gameboard that AI will be attacking
  695.                 int col                                 Column passed by reference that the AI will decide to attack
  696.                 int row                                 Row passed by reference that the AI will decide to attack
  697.  
  698. Returns: Nothing
  699. *********************************************************************************************************/
  700. void ai_attack(hit board[ROW][COL], int &col, int &row)
  701. {
  702.         int boatlist[BOATCOUNT] = { CARRIER, BATTLESHIP, DESTROYER, SUBMARINE, PATROLBOAT };
  703.         int boatsize = BOATCOUNT;
  704.         int i;
  705.        
  706.         // REMEMBER: col and row are passed by reference
  707.         for(int r = 0; r < ROW; r++)
  708.         {
  709.                 for(int c = 0; c < COL; c++)
  710.                 {
  711.                         if(board[r][c] != MISS && board[r][c] != BLANK) // Boat is an actual boat and needs to be removed from the boatlist
  712.                         {
  713.                                 for(i = 0; i < BOATCOUNT && board[r][c] != boatlist[i]; i++);
  714.                                 if(i != BOATCOUNT) // Otherwise this boat has already been removed
  715.                                 {
  716.                                         for(; i < BOATCOUNT - 1; i++)
  717.                                                 boatlist[i] = boatlist[i+1]; // Remove the boat from the list
  718.                                         boatsize--;
  719.                                 }
  720.                         }
  721.                 }
  722.         }
  723.         for(i = 0; i < boatsize; i++) // Convert boatlist to sizes
  724.                 boatlist[i] = hit2space(boatlist[i]);
  725.         ai_attack_random(board, col, row, boatlist, boatsize);
  726. }
  727.  
  728. /*********************************************************************************************************
  729. Purpose: This tries to pick the best space to attack on the board using a weighted system
  730.  
  731. Input:  hit board[ROW][COL]             Gameboard that AI will be attacking
  732.                 int col                                 Column passed by reference that the AI will decide to attack
  733.                 int row                                 Row passed by reference that the AI will decide to attack
  734.                 int boats[BOATCOUNT]    Array of boat sizes that still have not been sunk yet
  735.                 int boatsize                    Size of the boats array.
  736.  
  737. Returns: Nothing
  738. *********************************************************************************************************/
  739. void ai_attack_random(hit board[ROW][COL], int &col, int &row, int boats[BOATCOUNT], int boatsize)
  740. {
  741.         // The theory behind the AI here is thus:
  742.         // create a 2D deck for each space in the array holding coordinates and the score for that space
  743.         // The score represents how many variations of each type of remaining battleship can intercept that space
  744.         // Such that spaces without many hits nearby will have a higher weight than those adjacent to the edge of the board
  745.         // or next to miss markers.
  746.         // The deck is then sorted according to score and a random space from the list of top scorers is chosen and the AI targets that
  747.        
  748.         // TODO:
  749.         // As it stands, the AI here is too smart and thus too predictable.  need to figure out a way to make it slightly more random.
  750.         // Unless thats unneccesary...
  751.         int deck[ROW*COL][D_SIZE];
  752.         int decksize = 0;
  753.         int target, x;
  754.        
  755.         for(int i = 0; i < ROW; i++) // populate the deck and generate scores
  756.         {
  757.                 for(int j = 0; j < COL; j++)
  758.                 {
  759.                         if(board[i][j] == BLANK)
  760.                         {
  761.                                 deck[decksize][D_ROW] = i;
  762.                                 deck[decksize][D_COL] = j;
  763.                                 deck[decksize][D_SCORE] = ai_calculate_score(board, i, j, boats, boatsize);
  764.                                 decksize++;
  765.                         }
  766.                 }
  767.         }
  768.        
  769.         ai_sort_deck(deck, decksize - 1); // Sort the deck based on scores
  770.         for(target = 0, x = deck[0][D_SCORE]; x == deck[target][D_SCORE] && target < decksize; target++); // find the range of possible targets
  771.         target = rand() % target; // Pick the target to use
  772.         col = deck[target][D_COL];
  773.         row = deck[target][D_ROW];
  774. }
  775.  
  776. /*********************************************************************************************************
  777. Purpose: This calculates the weight score of a particular board space and returns that score.  Score is
  778.         based on how many possible ship combinations can legally overlap that space.  It then adds or subtracts
  779.         a modifier to the score based on adjacent and diagonal hits.
  780.  
  781. Input:  hit board[ROW][COL]             Main gameboard that it must calculate
  782.                 int r                                   Row number to check
  783.                 int c                                   Column number to check
  784.                 int boats[BOATCOUNT]    List of boats to check against space
  785.                 int boatsize                    Size of boats array
  786.  
  787. Returns: int    Weight score for that particular space
  788. *********************************************************************************************************/
  789. int ai_calculate_score(hit board[ROW][COL], int r, int c, const int boats[BOATCOUNT], const int boatsize)
  790. {
  791.         // Scoring algorithm works like such:  add 1 to the weight of the space for each section of a ship it can contain
  792.         // both horizontaly and verticaly
  793.         // Thus, x_?__x (x = miss, _ = blank, ? = coordinates) would have a score of:
  794.         //              +2 for patrol boat
  795.         //              +2 for sub and destroyer apiece
  796.         //              +1 for battleship since there is only one legal configuration in this section that would store the ? within the battleship
  797.         //              +0 for carrier since it cannot fit between those misses
  798.         // Additionally, score is only added for ships that have not yet been sunk, as defined by int boats.
  799.         // By this method, each space has a theoretical score limit of 34
  800.        
  801.         // Modifiers:
  802.         // Spaces will be modified based on their proximity to a hit.  such that spaces directly adjacent to hits will recieve extra points and
  803.         // spaces diagonally adjacent to hits will be demoted points
  804.         int score = 0;
  805.         int startpos, endpos;
  806.        
  807.         // Calculate the horizontal.
  808.         for(int boat = 0; boat < BOATCOUNT; boat++)
  809.         {
  810.                 for(startpos = c; startpos < COL - 1 && (board[r][startpos] == BLANK || board[r][startpos] == HIT) && startpos - c + 1 < boats[boat]; startpos++); // Move the start counter all the way to the right
  811.                 for(endpos = c; endpos >= 0 && (board[r][endpos] == BLANK || board[r][endpos] == HIT) && startpos - endpos + 1 < boats[boat]; endpos--); // Move end counter to the left to encompase size of boat
  812.                 if(startpos - endpos + 1 == boats[boat]) // make sure it can actually hold the boat before continuing
  813.                         for(; endpos >= 0 && startpos >= c && (board[r][endpos] == BLANK || board[r][endpos] == HIT) && (board[r][startpos] == BLANK || board[r][startpos] == HIT); startpos--, endpos--)
  814.                                 score++; // Move counters to the left and add one to the score for each successful move
  815.         }
  816.        
  817.         // Now the vertical, mainly the same thing
  818.         for(int boat = 0; boat < BOATCOUNT; boat++)
  819.         {
  820.                 for(startpos = r; startpos < ROW - 1 && (board[startpos][c] == BLANK || board[startpos][c] == HIT) && startpos - r + 1 < boats[boat]; startpos++); // Move the start counter all the way to the right
  821.                 for(endpos = r; endpos >= 0 && (board[endpos][c] == BLANK || board[endpos][c] == HIT) && startpos - endpos + 1 < boats[boat]; endpos--); // Move end counter to the left to encompase size of boat
  822.                 if(startpos - endpos + 1 == boats[boat]) // make sure it can actually hold the boat before continuing
  823.                         for(; endpos >= 0 && startpos >= r && (board[endpos][c] == BLANK || board[endpos][c] == HIT) && (board[startpos][c] == BLANK || board[startpos][c] == HIT); startpos--, endpos--)
  824.                                 score++; // Move counters to the left and add one to the score for each successful move
  825.         }
  826.        
  827.         // Process directly adjacent modifiers
  828.         if(r - 1 >= 0  && board[r-1][c] == HIT) score += AI_ACCURACY_ADJACENT;
  829.         if(r + 1 < ROW && board[r+1][c] == HIT) score += AI_ACCURACY_ADJACENT;
  830.         if(c - 1 >= 0  && board[r][c-1] == HIT) score += AI_ACCURACY_ADJACENT;
  831.         if(c + 1 < COL && board[r][c+1] == HIT) score += AI_ACCURACY_ADJACENT;
  832.        
  833.         // Process diagonally adjacent modifiers
  834.         if(r - 1 >= 0 && c - 1 >= 0   && board[r-1][c-1] == HIT) score -= AI_ACCURACY_DIAGONAL;
  835.         if(r + 1 < ROW && c - 1 >= 0  && board[r+1][c-1] == HIT) score -= AI_ACCURACY_DIAGONAL;
  836.         if(r - 1 >= 0 && c + 1 < COL  && board[r-1][c+1] == HIT) score -= AI_ACCURACY_DIAGONAL;
  837.         if(r + 1 < ROW && c + 1 < COL && board[r+1][c+1] == HIT) score -= AI_ACCURACY_DIAGONAL;
  838.        
  839.         return score;
  840. }
  841.  
  842. /*********************************************************************************************************
  843. Purpose: Sorting function for use in ai_attack_random.  Sorts a 2d array based on the third item in the
  844.         second array.  Bubblesort style
  845.  
  846. Input:  hit scores[][D_SIZE]    2d array that it needs to sort
  847.                 int rows                                Size of scores array counting from zero
  848.  
  849. Returns: Nothing
  850. *********************************************************************************************************/
  851. void ai_sort_deck(int scores[][D_SIZE], int rows) // munged bubblesort
  852. {
  853.         int temp, index;
  854.        
  855.         for(; rows > 0; rows--)
  856.         {
  857.                 for(index = 0; index < rows; index++)
  858.                 {
  859.                         if(scores[index][D_SCORE] < scores[index+1][D_SCORE])
  860.                         {
  861.                                 for(int i = 0; i < D_SIZE; i++)
  862.                                 {
  863.                                         temp = scores[index+1][i];
  864.                                         scores[index+1][i] = scores[index][i];
  865.                                         scores[index][i] = temp;
  866.                                 }
  867.                         }
  868.                 }
  869.         }
  870. }
  871.  
  872. /************************************************************
  873. Name: placementBoat
  874. Purpose: This function uses a switch-case statment to place the carrier, battleship, destroyer, submarine, and patrol boat, in that order.  It places them by calling the direction function.
  875. Input: hit board[][COL] - This is the board that will contain all the AI's boats.
  876.           int x - This is the randomly generated X cordinate.
  877.           int y - This is the randomly generated Y cordinate.  Together with the random X cordinate, these will serve as teh starting point for all points.
  878. Output: NA.
  879. ************************************************************/
  880. void placeBoat(hit board[][COL]){
  881.         int x, y;
  882.         int randDirection;
  883.         hit boats[BOATCOUNT] = { CARRIER, BATTLESHIP, DESTROYER, SUBMARINE, PATROLBOAT};
  884.         for(int i = 0; i < BOATCOUNT; i++)
  885.         {
  886.                 do{
  887.                 randDirection = (rand()%4)+1;
  888.                         x = rand()%ROW;
  889.                         y = rand()%COL;
  890.                 }while( !checkBlank(board,x,y,hit2space((int) boats[i]),randDirection) );
  891.                 direction(board,randDirection,x,y,hit2space((int) boats[i]),boats[i]);
  892.         }
  893. }
  894.  
  895. /************************************************************
  896. Name: direction
  897. Purpose: Based upon a randomly generated number, this function will decide which direction to place the remaining points for a said boat.
  898. Input: hit board[][COL] - This is the board that will contain all the AI's boats.
  899.           int x and int y - These are the basis upon which all other points will be place as explain in the previous function.
  900. Output: NA.
  901. ************************************************************/
  902. void direction(hit board[][COL],int randDirection,int x, int y,int limit, hit boatType){
  903.         for(int i=0;i<limit;i++){
  904.                 if(randDirection==UP){
  905.                         board[x][y-i] = boatType;
  906.                 }else if(randDirection == DOWN){  //If the direction is down this will be done.
  907.                         board[x][y+i] = boatType;
  908.                 }else if(randDirection==RIGHT){
  909.                         board[x-i][y] = boatType;
  910.                 }else{  //If the direction is left this will be done.
  911.                         board[x+i][y] = boatType;
  912.                 }
  913.     }  
  914. }
  915.  
  916. /************************************************************
  917. Name: checkBlank
  918. Purpose: This will check the spots that the Ai wishes to place the boat on an confirm it is able
  919. Input: hit board[][COL] - This is the board that will contain all the AI's boats.
  920.           int x and int y - These are the basis upon which all other points will be place as explain in the previous function.
  921.           int direction - A randomly generated direction
  922. Output: Returns true or false
  923. ************************************************************/
  924. bool checkBlank(hit board[][COL], const int x, const int y, const int limit, int direction){
  925.         int i;
  926.         bool valid = true;
  927.  
  928.     switch (direction){
  929.         case UP:
  930.             for(i=0;i<limit;i++){
  931.                 if(y-limit < 0 || board[x][y-i] != BLANK) valid = false;
  932.             }
  933.         case DOWN:
  934.             for(i=0;i<limit;i++){
  935.                 if(y+limit >= ROW || board[x][y+i] != BLANK) valid = false;
  936.             }
  937.         case RIGHT:
  938.             for(i=0;i<limit;i++){
  939.                 if(x-limit < 0 || board[x-i][y] != BLANK) valid = false;
  940.             }
  941.         case LEFT:
  942.             for(i=0;i<limit;i++){
  943.                 if(x+limit >= COL || board[x+i][y] != BLANK) valid = false;
  944.             }
  945.     }
  946.         return valid;
  947. }
  948.  
  949. /*    
  950. void say_qoute(){
  951.    
  952.         char *qoutes[] = {
  953.                 "Always in motion is the future...",
  954.                 "The force is strong with this one...",
  955.                 "The rumors of my death have been greatly exagerated",
  956.                 "All your base are belong to us",
  957.                 "May the force be with you.",
  958.                 "...Admiral, I want that ship - not excuses!",
  959.                 "There is a great disturbance in the Force",
  960.                 "We have a new enemy, the young Rebel who destroyed the Death Star.",
  961.                 "Impressive, most impressive. Obi-Wan has taught you well.",
  962.                 "There is no escape. Don't make me destroy you.",
  963.                 "You are beaten. It is useless to resist.",
  964.                 "I have you now!",
  965.                 "It's a trap!",
  966.                 "Don't underestimate the Force.",
  967.                 "I find your lack of faith disturbing.",
  968.         "Man your ships... and may the Force be with you."
  969.         }
  970.         puts(qoutes[rand() % 5]);
  971. }
  972. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement