GPWiki.org
GPWiki.org
It is currently Sun May 19, 2013 12:00 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: Sat Nov 26, 2011 3:31 am 
Bit Baby

Joined: Sat Nov 26, 2011 3:21 am
Posts: 9
Hi there

I have a pretty basic understanding of java. What im trying to do is make a rudimentary battleship game (remember the board game :P). I'm trying to find the most efficient way of populating a multidimensional array (the grid of the board, 7x7 or int grid[7][7]) with different lengths of 'ships' (2, 3 and 4). Currently i have a separate class to handle this task. What basically needs to be done, is check if the array (or grid) position is occupied with something, then check the adjacent grid positions in a random direction with all three sizes of ships so the whole ship can fit into the randomly generated position when the class add it to grid.

Im having a bit of trouble figuring out how to go about this. Any one have some tips or pointers?


Top
 Profile  
 
PostPosted: Sat Nov 26, 2011 9:53 am 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 275
Location: Here (where else?)
Your description seems fine to me, at first sight.
I am having a bit of trouble to understand what exactly you are having a problem with.

GinTox wrote:
trying to find the most efficient way of populating ....
For 7x7? Don't bother. You will need more time figuring out the optimal way, than your machine will have simply trying every possibility.
In other words, just program something that works, and you will be fine.

You seem to have the three steps already:
Quote:
check if the array (or grid) position is occupied with something,

Quote:
check the adjacent grid positions ...

Quote:
add it to grid.


Quote:
Im having a bit of trouble figuring out how to go about this. Any one have some tips or pointers?
As said, I am having a bit of trouble understanding what you are missing.
In my view, implement the above routines, glue them together, and you're done, or am I missing something?


Top
 Profile  
 
PostPosted: Sat Nov 26, 2011 4:51 pm 
Bit Baby

Joined: Sat Nov 26, 2011 3:21 am
Posts: 9
Hey thanks for replying

I figured it out :)...my first game yay ^^


Top
 Profile  
 
PostPosted: Sat Nov 26, 2011 5:14 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 275
Location: Here (where else?)
Congrats on your achievement :)

Now if only my first game was that easy ;)

I am writing FreeRCT, a game where you are supposed to get rich by building roller coasters in a park. So far, I just have mostly flat land :p


Top
 Profile  
 
PostPosted: Sat Nov 26, 2011 7:34 pm 
Corpse Bride
User avatar

Joined: Tue Jul 01, 2008 11:44 pm
Posts: 2216
Location: England
Alberth wrote:
I am writing FreeRCT


"FreeRCT" makes it sound like a derivative work. It may be best to choose a different name for your game.

As you may know, the RCT franchise is currently owned by Atari Inc, and they are known to fiercely defend their IP.

_________________
I ain't pushing no moon buttons.


Top
 Profile  
 
PostPosted: Sat Nov 26, 2011 8:15 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 275
Location: Here (where else?)
I am making the isometric version, not the 3D one. I quite doubt the former is sellable any more to the current audience :)
Also, 'RCT' is not what Atari uses, they use 'RollerCoaster Tycoon' (ie 2 words).
We will only use 'RCT'

However, it may not be enough.
Thank you for your advice; we will consider what to do.


Top
 Profile  
 
PostPosted: Sun Nov 27, 2011 7:39 am 
Bit Baby

Joined: Sat Nov 26, 2011 3:21 am
Posts: 9
Yep. Its pretty cool, next mission is to adapt it to a GUI :)

the solution i came up with is below. I had 2 other classes, a grid class handel everything to do with the grid such as checkin hit and miss, and changing value and then just the main method loop :).

The class below handel the grid populating. If there is a way that stands out to improve please let me know. was a good learning experience

Code:
import java.util.Random;

public class Populate {

   private int[][] grid;
   Random rand = new Random();
   
   public Populate(int[][] grid) {
      this.grid = grid;
      boolean gridIsEmpty = false;
      int x, y, direction;
      
      //loop for the three different sizes of ships
      for(int i=2; i<=4; i++) {
         do { //a loop that check if there is enough empty grid space before inserting into the grid itself
            direction = random(4) + 1;
            x = random(7);
            y = random(7);
            
            gridIsEmpty = checkAll(x, y, direction, i);
            
            if(gridIsEmpty) {
               insertIntoGrid(x, y, direction, i);
               break;
            }
         } while (!gridIsEmpty);
      }
   }
   
   //method that begins checking all adjacent squares
   public boolean checkAll(int x, int y, int direction, int shipLength) {
      boolean z = false;
      if(check(x, y)) {
         for(int count = 1; count <= shipLength; count++) {
            if(!checkDirection(x, y, direction, count)) {
               z = false;
               break;
            }
            z = true;
         }
      }
      return z;
   }
   
   //checks to see if the next adjacent square is empty, up down left and right
   public boolean checkDirection(int x, int y, int direction, int count) {
      boolean z = false;
      
      switch(direction) {
         case 1: z = (check(x+count, y));
               break;
         case 2: z = (check(x-count, y));
               break;
         case 3: z = (check(x, y+count));
               break;
         case 4: z = (check(x, y-count));
               break;
      }
      
      return z;
   }
   
   //check to see if a the grid element at that position is in bounds and empty
   public boolean check(int x, int y) {
      boolean z = false;
      if((x >= 0 && x <= 6) && (y >= 0 && y <= 6))   
         if(grid[x][y] == 0)
            z = true;
      
      return z;
   }
   
   //inserts ship into the grid (different lengths)
   public void insertIntoGrid(int x, int y, int direction, int shipLength) {
      for(int z = 1; z <= shipLength; z++) {
         switch(direction) {
            case 1: grid[x+z][y] = 1; break;
            case 2: grid[x-z][y] = 1; break;
            case 3: grid[x][y+z] = 1; break;
            case 4: grid[x][y-z] = 1; break;
         }   
      }
   }
   
   //method to return grid once finished with populating
   public int[][] getGrid() {
      return grid;
   }   
   
   //method to randomly generate numbers...just easier to type =)
   public int random(int x) {
      return  rand.nextInt(x);
   }
}


Top
 Profile  
 
PostPosted: Sun Nov 27, 2011 11:32 am 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 275
Location: Here (where else?)
You want comments on your code?
Ok :)

Below, I'll give a detailed explanation of things I noticed, and alternatives you may want to consider.
For people not used to code review, it may look like I hate your code.
This is not the case however, I think it is a useful piece of code, and most importantly, it works :)
So please consider my comments as positive remarks for possible improvement on good code.

I added '>' in front of your code lines (and nothing to my code lines) for ease of distinguishing.

Code:
> public class Populate {
This being Java, I can see you may want to encapsulate the population algorithm
in a class. However, why do you make it a full object?

Populate sounds like an action to me, not an object. Perhaps you could make all
methods static instead?

Alternatively, you could also add the Populate code to the Grid class.

Code:
>       //loop for the three different sizes of ships
>       for(int i=2; i<=4; i++) {
>          do { //a loop that check if there is enough empty grid space before inserting into the grid itself
>             direction = random(4) + 1;
>             x = random(7);
>             y = random(7);
Ah, magic numbers 4, 7, and 7 (and elsewhere, grid[x][y] == 0 or 1)

As a rule of the thumb, it pays to make constants or enums for each number, and use those.
That way, you document what numbers mean, and it is much easier to change sizes etc.

Code:
>             gridIsEmpty = checkAll(x, y, direction, i);
>             
>             if(gridIsEmpty) {
>                insertIntoGrid(x, y, direction, i);
>                break;
>             }
>          } while (!gridIsEmpty);
What's the point of this while condition? You break out of the loop if it worked.
A better way to express looping is by for(;;) { ... } or by while(true) { ... }

Code:
>    public boolean checkAll(int x, int y, int direction, int shipLength) {
>       boolean z = false;
>       if(check(x, y)) {
>          for(int count = 1; count <= shipLength; count++) {
>             if(!checkDirection(x, y, direction, count)) {
>                z = false;
>                break;
>             }
>             z = true;
>          }
>       }
>       return z;
>    }
The 'z = true' is done once for every iteration. Since one time is enough, I'd
suggest you initialize 'z' to true instead, and drop the assignment.

You are aware that your ship does not start at (x,y) but just next to it?
This makes the check(x, y) a bit weird. Why check at one end but not at the other end?
Also, by making 'count = 0', checkDirection() does the same as check() so you
may want to merge the check into the loop.

Code:
    public boolean checkAll(int x, int y, int direction, int shipLength) {
       for(int count = 0; count < shipLength; count++) {
          if(!checkDirection(x, y, direction, count)) return false;
       }
       return true;
    }


Finally, methods do not require a single exit, it is perfectly fine to write it
as above. However, this depends on your code style.

Code:
>    public boolean checkDirection(int x, int y, int direction, int count) {
>       boolean z = false;
>       
>       switch(direction) {
>          case 1: z = (check(x+count, y));
>                break;
>          case 2: z = (check(x-count, y));
>                break;
>          case 3: z = (check(x, y+count));
>                break;
>          case 4: z = (check(x, y-count));
>                break;
>       }
You need the x-step and y-step mapping (from 'direction' to a difference in x and
y) twice, once here and once in check().

To ensure both routines use the same x/y positions, you can make a getXStep(direction)
and a getYStep(direction) method, and use those in your code.

One step further is to make a Direction object containing direction, which you
pass around, and query getXStep and getYStep from it.

Another step further is to make a Position object containing x & y, and use that
instead of two x and y integers.

All three are valid solutions, which one is best depends on how often you need
Direction and Position objects elsewhere in your code.

Code:
>    //check to see if a the grid element at that position is in bounds and empty
"a the grid" :)
Good that you document your methods. I'd use standard javadoc for documenting methods and classes so you can leverage all tools that exist for it, but I am very document-minded.

Code:
>    public boolean check(int x, int y) {
>       boolean z = false;
>       if((x >= 0 && x <= 6) && (y >= 0 && y <= 6))   
>          if(grid[x][y] == 0)
>             z = true;
The parentheses around '(x >= 0 && x <= 6)' are not needed (also around the y tests). For me, they were
confusing as I expected a || somewhere (which is the only case where I use parentheses in conditions).
The grid-test could also be merged into it, but I can see you may want to keep it separate.

Compared to the other parts of the code, these lines miss a few curly braces.
I always use curly braces for multi-line statements, but perhaps you have a different code style?


In all, a nice piece of code.
Good luck with the GUI mission :)


Top
 Profile  
 
PostPosted: Sun Nov 27, 2011 2:14 pm 
Bit Baby

Joined: Sat Nov 26, 2011 3:21 am
Posts: 9
holy crap dude thanks. I appreciate you taking the time to make such a long post and go through it all. Hehe there's alot of redundant code in here :P. Also i want to put all the code that randomly populates the "grid" into someplace separate. If making an object of this class is not the most correct way to do it, do you think i could extend this class into the grid class and just call a method to start it all up?

Just one thing though, i was a bit confused about this

Code:
>direction = random(4) + 1;
>             x = random(7);
>             y = random(7);


you said i should put as constants but the reason these get reassigned every time is because if the ship can be placed in those rand positions it will generate a new random position and direction. DId i understand you right?, because as i understand it constants are "FINAL" variables that cannot be chaged.


Top
 Profile  
 
PostPosted: Sun Nov 27, 2011 2:45 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 275
Location: Here (where else?)
GinTox wrote:
Also i want to put all the code that randomly populates the "grid" into someplace separate. If making an object of this class is not the most correct way to do it, do you think i could extend this class into the grid class and just call a method to start it all up?
I'd make it a class with static methods in that case.

GinTox wrote:
Just one thing though, i was a bit confused about this

Code:
>direction = random(4) + 1;
>             x = random(7);
>             y = random(7);

you said i should put as constants but the reason these get reassigned every time is because if the ship can be placed in those rand positions it will generate a new random position and direction. DId i understand you right?, because as i understand it constants are "FINAL" variables that cannot be chaged.
I was talking about the numbers 4, 7, and 7, not about the variables.

Compare with
Code:
 direction = random(DIRECTION_COUNT) + 1;
             x = random(HORIZONTAL_GRID_SIZE);
             y = random(VERTICAL_GRID_SIZE);
Note that these numbers are used elsewhere too, eg 'x <= 6' -> 'x < HORIZONTAL_GRID_SIZE'

For the direction you may want to use an enum, and move the random direction generation into the enum too.

Edit: Removed "static class" as such things don't exist in Java :)


Top
 Profile  
 
PostPosted: Sun Nov 27, 2011 4:03 pm 
Bit Baby

Joined: Sat Nov 26, 2011 3:21 am
Posts: 9
oh i see what you mean. Ah cool. Thanks alot for taking the time man :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group