3
\$\begingroup\$

Given the scheme of the fleet of the human player, let the user choose which coordinates attack each turn.
The "computer player" will then attack on its turn following the classic rules of battleship. (The computer player must be able to win, you can't make the computer attack every turn the same cell)

The schemes must contain all the needed ships, this is the list:

[ ][ ]               x 4

[ ][ ][ ]            x 3

[ ][ ][ ][ ]         x 2

[ ][ ][ ][ ][ ][ ]   x 1

The scheme must follow the example below, and must be one for each player.

[ ][ ]   [ ]      [ ][ ][ ][ ]
         [ ]                  
[ ]      [ ]   [ ][ ][ ]   [ ]
[ ]                        [ ]
[ ]                         
[ ]            [ ]         [ ]
               [ ]         [ ]
[ ][ ]                     [ ]

            [ ][ ][ ][ ][ ][ ]

To input the player scheme you can just hard-code it in your script or let the user insert it in some way (use a specific char to separate rows or let user inser one row per time etc, up to you), the important thing is that your player must be able to easily insert a new scheme (no minified/compressed input so).

The fleet owned by the computer must be randomly generated by the script.

The coordinates are a number(1-10) and a letter(A-L), this is an example battlefield with coordinates:

      A  B  C  D  E  F  G  H  I  L
   |‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
 1 | [ ][ ]   [ ]      [ ][ ][ ][ ]
 2 |          [ ]                  
 3 | [ ]      [ ]   [ ][ ][ ]   [ ]
 4 | [ ]                        [ ]
 5 | [ ]                         
 6 | [ ]            [ ]         [ ]
 7 |                [ ]         [ ]
 8 | [ ][ ]                     [ ]
 9 |
10 |             [ ][ ][ ][ ][ ][ ]

Each turn the script must ask which coordinates hit, and return an indication:

  • not hit = the selected coordinates doesn't match a part of a ship
  • hit = the selected coordinates does match part of a ship but the ship is not yet sunk
  • hit and sunk = the selected coordinates does match part of a ship and the ship is sunk

Then it will have to make the computer hit a cell (bonus points if you can write a smart script that will be challenging) and indicate to user which cell was hit and if one of his ships was hit (same indications of above).

Example "gameplay" log:

Your coordinates: A1
hit
Enemy coordinates: C1
not hit
Your coordinates: B1
hit and sunk

if the user chooses two times the same coordinates consider it as not hit or just ignore it

The expected final outputs (when one of the two players has not ships available) are the two schemes with the coordinates hit by the computer player marked with an x, example of the first scheme:

[x][x]   [x]      [x][x][x][ ]
 x       [x]                  
[ ] x    [x]   [ ][ ][x]   [x]
[ ]                        [x]
[ ]       x                 
[x]            [x]         [ ]
               [x]    x    [ ]
[ ][ ] x                   [ ]

    x       [ ][ ][x][ ][ ][ ]

It's probably not the easiest code-golf challenge here but as usual, the shortest code will win.

\$\endgroup\$
  • 2
    \$\begingroup\$ Two Face: B12! The Riddler: Hit! And my favorite vitamin might I add. ~ Batman Forever \$\endgroup\$ – WallyWest Feb 5 '14 at 23:00
  • \$\begingroup\$ You sunk my battleship. \$\endgroup\$ – unclemeat Feb 5 '14 at 23:27
  • \$\begingroup\$ Hmm, you did not specify that the algorithm must be intelligent, and since this is code-golf, people will exploit this to make code shorter, making the computer play [A1][A2][A3][A4][A5]... Further, they will hardcode computer ships in stupid positions to make code even shorter. And more, the rules does not stop people to make a cheating computer intelligence that directly looks the user's ship positions. \$\endgroup\$ – Victor Stafusa Feb 6 '14 at 0:25
  • 1
    \$\begingroup\$ @Victor The ship positions for the computer must be randomly generated (look at the question again) \$\endgroup\$ – Justin Feb 6 '14 at 0:50
  • \$\begingroup\$ @victor actually generate random coordinates for where the computer should attack takes less code then use your method in most of the languages, also I've specified that would be nice have a challenging enemy, but it's up to you this, I think it's already an enough long golf script \$\endgroup\$ – Fez Vrasta Feb 6 '14 at 6:56
2
\$\begingroup\$

Well, better late than never. I remembered doing something like this in a school class long time ago... Ungolfed and waaaaaay too long.

#include <iostream>
#include <ctime>
#include <sstream>
#include <cstdlib>
using namespace std;

class board{
private:
    char grid[10][10];
public:
    void initializeGrid(){
        for (int row=0; row<10; row++){
            for (int column=0; column<10; column++){
                grid[row][column]='~';
            }
        }
    }
    void displayGrid(bool hideShips=false){
        int y=10;
        for (int i=0; i<10; i++){
            if (y!=10){cout<< " ";}
            cout<<y;
            for (int c=0; c<10; c++){
                cout<<" ";
                if (grid[i][c]=='X'){
                    if (hideShips==true){
                        cout<<"~";
                    }else{
                        cout<<grid[i][c];
                    }
                }else{cout<<grid[i][c];}
            }
            y--;
            cout<<endl;
        }
        cout<<"   A B C D E F G H I J"<<endl;
    }
    char getSpace(int x, int y){
        return grid[y][x];
    }
    void addSpace(char space, int x, int y){
        grid[y][x]=space;
    }
};

class ship{
private:
    int length;
    board* boardOP;
public:
    ship(int L, board* BOP){
        length=L;
        boardOP=BOP;
    }
    bool buildShip(int *X, int *Y, int dX, int dY, board *boardOP){
        int shipStore[10]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
        for(int i=0; i<length; i++){
            shipStore[i*2]=*X;
            shipStore[i*2+1]=*Y;
            if (*Y+dY<10&&*Y+dY>-1
              &&*X+dX<10&&*X+dX>-1
              &&boardOP->getSpace(*X+dX,*Y+dY)=='~'){
                *Y=*Y+dY;
                *X=*X+dX;
            }else{return false;}
        }
        for(int c=0; c/2<length; c+=2){
            boardOP->addSpace('X',shipStore[c],shipStore[c+1]);
        }
        return true;
    }
    int getLength(){return length;}
};

class player{
protected:
    board* thisBoardOP;
    board* otherBoardOP;
    int X;
    int Y;
    int hits;
public:
    virtual void go(){}
    player(){
        hits=0;
    }
    bool won(){
        if(hits==17){return true;
        }else{return false;}
    }
    bool hit(){
        if (otherBoardOP->getSpace(X-1,10-Y)=='X'){
            cout<<"hit!"<<endl;
            hits++;
            otherBoardOP->addSpace('#',X-1,10-Y);
            return true;
        }else{
            cout<<"miss!"<<endl;
            otherBoardOP->addSpace('O',X-1,10-Y);
            return false;
        }
    }
    void arrangeShips(){
        ship aircraftCarrier(5,thisBoardOP);
        positionShip(&aircraftCarrier);

        ship battleship(4,thisBoardOP);
        positionShip(&battleship);

        ship cruiser(3,thisBoardOP);
        positionShip(&cruiser);

        ship destroyer(3,thisBoardOP);
        positionShip(&destroyer);

        ship patrolBoat(2,thisBoardOP);
        positionShip(&patrolBoat);
    }
    void positionShip(ship* type){
        while(1){
            int dY=0;
            int dX=0;
            dX=(rand()%2)-(rand()%2);
            if(dX==0){
                dY=(rand()%2);
                if(dY==0){(dY)--;}
            }else{dY=0;}
            int Y=(rand()%10);
            int X=(rand()%10);
            if (thisBoardOP->getSpace(X,Y)=='~'){
                if (type->buildShip(&X,&Y,dX, dY,thisBoardOP)==false){
                    dX*=-1;
                    dY*=-1;
                    if (type->buildShip(&X,&Y,dX,dY,thisBoardOP)==true){return;}
                }else{return;}
            }
        }
    }
};

class human: public player{
public:
    human(board* tBOP, board* oBOP){
        thisBoardOP=tBOP;
        otherBoardOP=oBOP;
    }
    void go(){
        setXY();
        hit();
        cout<<X<<endl;
        cout<<Y<<endl;
    }
    void setXY(){
        string input;
        while(1){
            do{
                cout<<endl<<"Enter x coordinate:"<<endl;
                char letterX='\0';
                cin>>input;
                if (input.length()==1){letterX=input[0];}
                X=convertLetter(letterX);
                if(X==0){cout<<endl<<"Please enter a valid letter between A-J"<<endl;}
            }while(X==0);
            do{
                cout<< endl<<"Enter y coordinate:"<<endl;
                cin>>input;
                stringstream(input)>>Y;
                if(Y>10||Y<1){cout<<"Please enter a valid number between 1-10"<<endl;}
            }while(Y>10||Y<1);
            if(otherBoardOP->getSpace(X-1,10-Y)=='#'
             ||otherBoardOP->getSpace(X-1,10-Y)=='O'){
                cout<<endl<<"You cannot shoot a space that has already been hit!"<<endl;
            }else{break;}
        }
    }
    int convertLetter(char letter){
        if (int(letter)>64&&int(letter)<75){
            return int(letter)-64;
        }else if(int(letter)>96&&int(letter)<107){
            return int(letter)-96;
        }
        return 0;
    }
};

class computer: public player{
private:
    int originX;
    int originY;
    int vX;
    int vY;
    bool foundEnd1;
    bool foundEnd2;
    bool foundDirection;
    bool oppositeCheck;
    int distance;
    int count;
public:
    computer(board* tBOP, board* oBOP){
        thisBoardOP=tBOP;
        otherBoardOP=oBOP;
        originX=0;
        originY=0;
        vX=0;
        vY=0;
        foundEnd1=false;
        foundEnd2=false;
        foundDirection=false;
        oppositeCheck=false;
        distance=2;
        count=0;
    }
    void go(){
        setXY();
        if(hit()==true){
            if(originX==0){
                originX=X;
                originY=Y;
            }else if(foundDirection==false){
                foundDirection=true;
                if(oppositeCheck==true){
                    if(vX<0||vY<0){foundEnd1=true;
                    }else{foundEnd2=true;}
                }
            }
        }else if(foundDirection==true){
            if (X-originX>0||Y-originY>0){foundEnd1=true;
            }else{foundEnd2=true;}
        }
    }
    void setXY(){
        if(originX!=0){
            if(foundEnd1==false
             ||foundEnd2==false){
                if(foundDirection==false){
                    findDirection();
                }else{
                    findRest();
                }
            }
            if(foundEnd1==true
             &&foundEnd2==true){
                originX=0;
                originY=0;
                vX=0;
                vY=0;
                foundEnd1=false;
                foundEnd2=false;
                foundDirection=false;
                oppositeCheck=false;
                distance=2;
                count=0;
            }
        }
        if (originX==0){
            do{
                X=(rand()%10)+1;
                Y=(rand()%10)+1;
            }while(otherBoardOP->getSpace(X-1,10-Y)=='O'
                 ||otherBoardOP->getSpace(X-1,10-Y)=='#');
        }
    }
    void findDirection(){
        if(count==0){
            vX=(rand()%2)-(rand()%2);
            if(vX==0){
                vY=(rand()%2);
                if(vY==0){(vY)--;}
            }else{vY=0;}
        }
        while(count<4){
            if(count==2){oppositeCheck=false; int i=vX; vX=vY; vY=i;
            }else if(count!=0){oppositeCheck=true; vX*=-1; vY*=-1;}
            count++;
            if(originX+vX<11&&originX+vX>0
             &&originY+vY<11&&originY+vY>0
             &&otherBoardOP->getSpace((originX+vX)-1,10-(originY+vY))!='#'
             &&otherBoardOP->getSpace((originX+vX)-1,10-(originY+vY))!='O'){
                X=originX+vX;
                Y=originY+vY;
                return;
            }
        }
        foundEnd1=true;
        foundEnd2=true;
    }
    void findRest(){
        int adjustment=0;
        if(foundEnd1==true){
            if(vX<0||vY<0){adjustment=1;
            }else{adjustment=-distance;}
        }else if(foundEnd2==true){
            if(vX<0||vY<0){adjustment=-distance;
            }else{adjustment=1;}
        }else{
            adjustment=(rand()%2);
            if(adjustment==0){adjustment=-distance;}
        }
        if (vX<0||vY<0){adjustment*=-1;}
        int i=0;
        while(i<2&&(foundEnd1==false||foundEnd2==false)){
            if (vX==0){
                if(originY+vY+adjustment>0
                 &&originY+vY+adjustment<11
                 &&otherBoardOP->getSpace(originX-1,10-(originY+vY+adjustment))!='#'
                 &&otherBoardOP->getSpace(originX-1,10-(originY+vY+adjustment))!='O'){
                        Y=originY+vY+adjustment;
                    if(adjustment==1||adjustment==-1){vY+=adjustment;}
                    distance++;
                        return;
                }
            }else{
                if(originX+vX+adjustment>0
                 &&originX+vX+adjustment<11
                 &&otherBoardOP->getSpace((originX+vX+adjustment)-1,10-originY)!='#'
                 &&otherBoardOP->getSpace((originX+vX+adjustment)-1,10-originY)!='O'){
                        X=originX+vX+adjustment;
                    if(adjustment==1||adjustment==-1){vX+=adjustment;}
                    distance++;
                        return;
                }
            }
            if(adjustment==1){adjustment=-distance; foundEnd1=true;
            }else if(adjustment==-1){adjustment=distance; foundEnd2=true;
            }else if(adjustment==distance){adjustment=-1; foundEnd1=true;
            }else{adjustment=1; foundEnd2=true;}
            i++;
        }

    }
};

int main(){
    srand((unsigned int)(time(0)));

    board boardO1;
    boardO1.initializeGrid();

    board boardO2;
    boardO2.initializeGrid();

    human humanO(&boardO2,&boardO1);
    humanO.arrangeShips();

    computer computerO(&boardO1,&boardO2);
    computerO.arrangeShips();

    player* playerOP=&humanO;

    while(1){
        boardO1.displayGrid(true);
        cout<<endl;
        boardO2.displayGrid();
        playerOP->go();
        if(playerOP->won()==true){
            cout<<endl;
            if(playerOP==&humanO){
                cout<<"You win!"<<endl;
            }else{
                cout<<"Computer wins!"<<endl;
            }
            cout<<endl;
            boardO1.displayGrid(true);
            cout<<endl;
            boardO2.displayGrid();
            break;
        }
        if (playerOP==&humanO){playerOP=&computerO;
        }else{playerOP=&humanO;}
    }

    return 0;
}

Result:

./a.out
10 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 8 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 7 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 5 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   A B C D E F G H I J

10 ~ ~ ~ ~ ~ ~ ~ ~ X ~
 9 ~ ~ ~ X ~ ~ ~ ~ X ~
 8 X ~ ~ X ~ ~ ~ ~ X ~
 7 X ~ ~ X ~ ~ ~ ~ X ~
 6 X ~ ~ ~ ~ X X X X ~
 5 X ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ X X
   A B C D E F G H I J

Enter x coordinate:
d

Enter y coordinate:
4
hit!
4
4
10 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 8 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 7 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 5 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ # ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   A B C D E F G H I J

10 ~ ~ ~ ~ ~ ~ ~ ~ X ~
 9 ~ ~ ~ X ~ ~ ~ ~ X ~
 8 X ~ ~ X ~ ~ ~ ~ X ~
 7 X ~ ~ X ~ ~ ~ ~ X ~
 6 X ~ ~ ~ ~ X X X X ~
 5 X ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ X X
   A B C D E F G H I J
miss!
10 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 8 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 7 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 5 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ # ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   A B C D E F G H I J

10 ~ ~ ~ ~ ~ ~ ~ ~ X ~
 9 ~ ~ ~ X ~ ~ ~ ~ X ~
 8 X ~ ~ X ~ ~ ~ ~ X ~
 7 X ~ ~ X ~ ~ ~ ~ X ~
 6 X ~ ~ ~ ~ X X X X ~
 5 X ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ O ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ X X
   A B C D E F G H I J

Enter x coordinate:
d

Enter y coordinate:
7
miss!
4
7
10 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 8 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 7 ~ ~ ~ O ~ ~ ~ ~ ~ ~
 6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 5 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ # ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   A B C D E F G H I J

10 ~ ~ ~ ~ ~ ~ ~ ~ X ~
 9 ~ ~ ~ X ~ ~ ~ ~ X ~
 8 X ~ ~ X ~ ~ ~ ~ X ~
 7 X ~ ~ X ~ ~ ~ ~ X ~
 6 X ~ ~ ~ ~ X X X X ~
 5 X ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ O ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ X X
   A B C D E F G H I J
miss!
10 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 9 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 8 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 7 ~ ~ ~ O ~ ~ ~ ~ ~ ~
 6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 5 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 ~ ~ ~ # ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   A B C D E F G H I J

10 ~ ~ ~ ~ ~ ~ ~ ~ X ~
 9 ~ ~ ~ X ~ ~ ~ ~ X ~
 8 X ~ ~ X ~ ~ ~ ~ X ~
 7 X ~ ~ X ~ ~ ~ ~ X ~
 6 X ~ ~ ~ ~ X X X X ~
 5 X ~ ~ ~ ~ ~ ~ ~ ~ ~
 4 O ~ ~ O ~ ~ ~ ~ ~ ~
 3 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 2 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 1 ~ ~ ~ ~ ~ ~ ~ ~ X X
   A B C D E F G H I J

Enter x coordinate:
d

Enter y coordinate:
4

You cannot shoot a space that has already been hit!
\$\endgroup\$
0
\$\begingroup\$

Since this is a rather involved problem, I'll be going at it step by step and posting here.

First part, computer board generation:

I used a very simple (yet rules-abiding) algorithm to determine where to put the boats.

from random import randint as t
r=range
a=10
d=(0,9)
s=[0]*a
c = [['' for _ in r(a)] for _ in r(a)]
for _ in "1234":
 k=t(0,6)
 c[k][s[k]],c[k][s[k]+1]=['d'+_]*2
 s[k]+=2
for _ in "123":
 k=t(0,6)
 while(s[k]>7):
  k=t(*d)
 c[k][s[k]],c[k][s[k]+1],c[k][s[k]+2]=['s'+_]*3
 s[k]+=3
for _ in "12":
 k=t(0,8)
 while(s[k]>6):
  k=t(*d)
 for q in r(4):
  c[k][s[k]+q]='r'+str(_)
 s[k]+=4
 for _ in r(0,6):
  c[9][s[9]+_]='b1'
s[9]+=6

#Testing                                                                                                                                                                          
for line in c:
 print(line)

A pretty standard output for the algorithm is:

['', '', '', '', '', '', '', '', '', '']
['d1', 'd1', 's1', 's1', 's1', 'r1', 'r1', 'r1', 'r1', '']
['d2', 'd2', 'd3', 'd3', '', '', '', '', '', '']
['s3', 's3', 's3', 'r2', 'r2', 'r2', 'r2', '', '', '']
['s2', 's2', 's2', '', '', '', '', '', '', '']
['d4', 'd4', '', '', '', '', '', '', '', '']
['', '', '', '', '', '', '', '', '', '']
['', '', '', '', '', '', '', '', '', '']
['', '', '', '', '', '', '', '', '', '']
['b1', 'b1', 'b1', 'b1', 'b1', 'b1', '', '', '', '']
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.