Function to randomly place ships on an array

Hey guys I need some help with this function to randomly place ships of varying lengths (Battleships) on a 2D array. A carrier = 5 places Battleship = 4 places Destroyer and submarine = 3 places and a patrol boat = 2 places.

My array is as follows:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const int rows = 11;
const int columns = 11;
char yourBoard[rows][columns] = {
		{ ' ','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', },
		{ '0','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '1','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '2','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '3','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '4','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '5','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '6','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '7','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '8','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
		{ '9','-', '-', '-', '-', '-', '-', '-', '-', '-', '-', },
};



so basically i need the ships to be placed only on places on the array where there is '-'.

Here is my function so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void generateAircraftCarrier() // 5 = Aircraft Carrier
{
   srand(time(NULL));
   int initialRandomColumn = (rand() % 10) + 1;
   int initialRandomRow = (rand() % 10) + 1;

   if (columns - initialRandomColumn > 5)
   {
       for (int i = 0; i < 5; i++)
       {
           yourBoard[initialRandomRow][initialRandomColumn] = '5';
	   initialRandomColumn++;
       }
   }
   else
   {
       for (int i = 0; i < 5; i++)
       {
	   yourBoard[initialRandomRow][initialRandomColumn] = '5';
	   initialRandomColumn--;
       }
    }
}


this only places horizontally and I need it be randomly between horizontally and vertically. When i add another function for a different boat it keeps placing the ships right on top of each other every time i run the program. So correct me if i'm wrong but i think need something like

while yourBoard [rows][columns] = '-'
then randomly place ships
and while yourBoard [rows][columns] != '-'
then look for a new random spot

Any help is appreciated thanks
Last edited on
@makkz first, plz put your code in code tags, shown as "<>", that makes code much 'watchable'. it repulses potential helpers. so edit your post and it might still attract some more helpers.

I need it be randomly between horizontally and vertically

why don't you make two separte function "put_horizontally()" and "put_vertically()" with much of above code and use generateAircraftCarrier() to randomly trigger one of those. eg:

1
2
3
4
5
6
7
8
9
void generateAircraftCarrier()
{
    srand(time(NULL));
    int choice=rand()%2;
    if(choice==0)
    put_horizontally();
    else
    put_vertically();
}


keeps placing the ships right on top of each other

you need to do what you yourself suggested. a possible logic to do that could be:

1
2
3
4
5
6
7
8
9
10
11
for (int i = 0; i < 5; i++)
{
if(yourBoard[initialRandomRow][initialRandomColumn] != '-')
i-=1;///repeats the same process again

else
{
yourBoard[initialRandomRow][initialRandomColumn] = '5';
initialRandomColumn++;
}
}


hope this helps.
Last edited on
@koopey thanks for the reply. Alright i edited my post cheers, just my first time posting on here :)

Your code helps thanks man! So with the "put_horizontally()" and "put_vertically()" do i have to make one of these for each ship since they are all of varying lengths? And with
if(yourBoard[initialRandomRow][initialRandomColumn] = '-')
did you not mean " != '-' " ?
@makkz well, if you want different number of spaces occupied based on varying length, you definitely have to implement them differently, but that doesn't mean you have to make numerous "put_horizontally()" and "put_vertically()". You could pass length as argument. Since you want to randomly select a length, you would have to produce it too.eg:

1
2
3
4
5
6
7
8
9
10
11
void generateAircraftCarrier()
{
    srand(time(NULL));
    int choice=rand()%2;
    int length=rand()% number///replace number by integer here for range 
                                    ///of suitable value to randomly produce a length
    if(choice==0)
    put_horizontally(length);///length passed here
    else
    put_vertically(length);///length passed here too
}


then implement "put_horizontally()" and "put_vertically()" with series of if/else, each if statement with condition of a certain length.

did you not mean " != '-' "
no actually, i did mean "==". if ...=="-", then don't overwrite in that space and reapeat the same loop once again as if that process never happened(i-=1;), else fill that with corresponding number('5' in this case). my bad ;) do just opposite
Last edited on
@koopey ok wait just to clarify (sorry i am new to c++ this is only my second program ever so i appreciate your patience :) ) i have my "put_horizontally()" and "put_vertically()" functions as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void put_Horizontally ()
{
	srand(time(NULL));
	int initialRandomColumn = (rand() % 10) + 1;
	int initialRandomRow = (rand() % 10) + 1;

	if (columns - initialRandomColumn > 5)
	{
		for (int i = 0; i < 5; i++)
		{
			if (yourBoard[initialRandomRow][initialRandomColumn] == '-')
				i -= 1;
			else
			{
				yourBoard[initialRandomRow][initialRandomColumn] = '5';
				initialRandomColumn++;
			}
		}
	}
	else
	{
		for (int i = 0; i < 5; i++)
		{
			if (yourBoard[initialRandomRow][initialRandomColumn] == '-')
				i -= 1;
			else
			{
				yourBoard[initialRandomRow][initialRandomColumn] = '5';
				initialRandomColumn--;
			}
		}
	}
}

void put_Vertically ()
{
	srand(time(NULL));
	int initialRandomColumn = (rand() % 10) + 1;
	int initialRandomRow = (rand() % 10) + 1;

	if (rows - initialRandomRow > 5)
	{
		for (int i = 0; i < 5; i++)
		{
			if (yourBoard[initialRandomRow][initialRandomColumn] == '-')
				i -= 1;
			else
			{
				yourBoard[initialRandomRow][initialRandomColumn] = '5';
				initialRandomRow++;
			}
		}
	}
	else
	{
		for (int i = 0; i < 5; i++)
		{
			if (yourBoard[initialRandomRow][initialRandomColumn] == '-')
				i -= 1;
			else
			{
				yourBoard[initialRandomRow][initialRandomColumn] = '5';
				initialRandomRow--;
			}
		}
	}
}

void generateAircraftCarrier() // 5 = Aircraft Carrier
{
	srand(time(NULL));
	int choice = rand() % 2;
	if (choice == 0)
		put_Horizontally ();
	else
		put_Vertically ();
}


this is my function to show my array:

1
2
3
4
5
6
7
8
9
10
11
void Show ()
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < columns; j++)
		{
		cout << yourBoard [i][j] << "  ";
		}
	cout << endl;
	}
}


The 5 represents the Aircraft Carrier, a 4 will represent a Battleship(length of 4), a 3 will represent a Destroyer(length = 3), a 2 will represent a submarine(length = 3) and a 1 will represent a patrol boat(length = 2) so I dont need to randomly produce a lenght for the ships.
in main when i call generateAircraftCarrier (); and then Show (); nothing happens, why might this be?
@makkz
did you not mean " != '-' " ?
mybad ;) . slip of tongue mind. it indeed is "!=". initially the array is filled with "-", so what seemed "nothing happens", program continuously kept looping the i-=1; under the hood. hope you have running program now.

Edit: this is your second program. about my first 100 programs kept just outputting "hello world!", "hello me", "hello mom", "hello dad"and sum of "1+1" and similar stuffs. so good job.
Last edited on
@koopey I thought it would've been != '-' instead cause == '-' was just not making sense to me but then again I thought I was just doing something wrong :P

then implement "put_horizontally()" and "put_vertically()" with series of if/else, each if statement with condition of a certain length.


with that do you mean i write the "put_horizontally()" and "put_vertically()" functions with something like
1
2
3
4
5
6
7
8
9
put_horizontally ()
{
   if length = 5
      then generate random ship
   else if length = 4
      "      "
   else if length = 3
      "      "
}

and so on? I am still struggling to get my head around doing this part
@makkz i initially thought you wanted to do sth specific based on length but if your programs worked in way that you wanted, never mind what i said before but if you wanted it to do sth else, plz explain what you really want to do.
Last edited on
lines 3, 37, 71: You only ever want to call srand() once in your program. Calling it multiple times in the same second will cause the random number generator to reset to the same sequence of pseudo-random numbers. Place the call to srand() at the beginning of main().

Before you attempt to place a ship on the board, you need to check if any of the cells are out of bounds or occupied. If any cells are occupied, you don't want to try placing a ship of that particular length at that location.

First off, lets define the directions:
1
2
3
4
enum DIR 
{ ACROSS,
   DOWN
};

Now lets add some helpers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
bool inbounds (int r, int c)
{  return r >= 0 && r< MAX_ROWS && c >= 0 & c < MAX_COLS);
}

bool all_inbounds (DIR dir, int r, int c, int len)
{  if (dir == ACROSS)
    { for (int i=0; i<len; i++)
         if (! inbounds(r,c+i))
           return false;
    }
    else
    {  for int i=0; i<len; i++)
         if (! inbounds(r+i,c))
           return false;
    }
    return true;
}

bool all_unoccupied (char board[][MAX_COLS],DIR dir, int r, int c, int len)
{  if (! all_inbounds(dir, r, c, len))
      return false;
    if (dir == ACROSS)
    { for (int i=0; i<len; i++)
          if (board[r][c+i] != ' ')    
            return false;
    }
    else
    { for (int i=0; i<len; i++)
        if (board[r+i][c] != ' ')
          return false
    }
    return true;
}

Now we can write our place ship function. Note that this is a bool function so that it can indicate whether or not a ship was placed.
1
2
3
4
5
6
7
8
9
10
11
12
13
bool place_ship (DIR dir, int r, int c, int len)
{  if (! all_unoccupied (board, dir, r, c, len))
       return false;  // can't place ship here
    // legal to place ship here.  Go ahead and do so
    if (dir == ACROSS)
    { for (int i=0; i<len; i++)
          board[r][c+i] = len;    // len indicates the type of ship
    }
    else
    { for (int i=0; i<len; i++)
        board[r+i][c] = len; 
    }
    return true;  // ship placed 

Last edited on
@AbstractionAnon Can you explain your code alittle bit more? That would be of great help
@koopey Alright i want to randomly place the 5 ships of the lengths specified on the array where there is a '-', they cant overlap or be placed on anything that is not '-' :)
@makkz AbstractionAnon's code is good and most probably, that is what you wanted after all. the only drawback is you wanted both 'destroyer' and 'submarine' to have 3 places and the code above doesn't differentiate between two.

In above code, you have to manually provide the length(i.e. choose the ship yourself) and even the direction(row or column to place the ship) and code above then places it randomly. Initially I thought, you wanted to randomly choose the length(randomly choose ship) and direction(randomly choose row or column).
Last edited on
Can you explain your code alittle bit more? That would be of great help

It's pretty straight forward. Nothing fancy. You should be able to figure it out.

inbounds() simply determines if a given row and column are inbounds or not.

all_inbounds() tests if the specified number of cells are all inbound, given a starting position and direction. If the direction is across, each column is checked (line 8). If the direction is down, then each row is checked (line 13).

all_unoccupied() makes sure that every cell where we want to place a ship is in fact unoccupied. If any of the cells that would be used are out of bounds, false is returned immediately. If that check passes, then we know this is a legal position for a ship of the specified length. But we don't know yet if the cells are in fact unoccupied. So if the direction is across, we iterate through the horizontal positions looking for any cells that might be occupied (non-blank). If we find any, we return false. If the direction is down, we do the same thing, incrementing the row instead of the column.

place_ship() takes a direction, a row, a column and a length. If all_unoccupied() is not true, then we exit immediatly since we know we can't place a ship here. If all_unoccupied returns true, then we know we can place a ship here and we go ahead and do so, iterating through the columns or rows, depending on the direction.
@koopey It doesn't necessarily need to choose a random ship(length), it just needs to place all 5 ships in valid random locations(horizontally or vertically)
@makkz got it. aye captain!(ship reference or just lame attempt at humour or isn't humor at all...awkward laugh) the above code would work fine then. need to make "place_ship()" independent of 'dir' argument and someway to distinguish destroyer and submarine though.
Last edited on
@koopey LOL that was pretty punny ;)
need to make "place_ship()" independent of 'dir' argument
How to do that?

what if we just have something like C = Carrier B = Battleship and so on?
How to do that?

rather than making in independent, you could choose between directions same old way as we did before. randomly choose between 0 and 1 and correspond each to different direction, just as you randomly choose row and column to provide to "place_ship()".

what if we just have something like C = Carrier B = Battleship and so on?

didn't quite get that. did you mean for proper distinction. if so, yes you could do that.

@koopey Alright, how should i go about calling the place_ship() function in main() then that @AbstractionAnon posted?
What's so hard? Generate a random direction, generate a random row, generate a random direction, specify the length of the ship you want to place, then call place_ship() with those arguments. You may have to repeat that procedure a number of times to place a single ship since place_ship() may return false indicating it could not place a ship using the specified arguments.
Topic archived. No new replies allowed.