I am creating a 2d tile map with a method called generateMap.There is an array called map which keeps what tile will be on x and y locations.There are only 4 types of tiles and they are represented in numbers,1-2-3-4.
Numbers also triggers different colors.That's why they are here.
For example : map[10][10]=1 = means there will be a tile number 1 on x10 and y10.(Green)
The thing is all four types of tiles has the same probability to show up,but somehow every time I run the method,"4"becomes much more frequent than the others.
For every tile that doesn't have a neighboring tile,which means every tile with either x0 location or y0 location,I assign them a random number.But with every tile with eight neighboring tiles at least one with same type,has a higher chance to have same type as them.
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.concurrent.ThreadLocalRandom;
public class Map {
public int tilesize=20;
public int tiletype;
public int mapx,mapy=0;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int userwidth = (int) screenSize.getWidth();
int userheight= (int) screenSize.getHeight();
int width = tilesize/userwidth;
int height = tilesize/userheight;
public int map[][] = new int [140][80];
public void generateMap() {
for(int x=0; x<130; x++) {
for(int y=0; y<70; y++) {
if(x==0 || y==0) {
int randomtile=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile;
}
else {
if(map[x][y-1]==1 || map[x][y+1]==1 || map[x-1][y]==1 || map[x+1][y]==1
|| map[x+1][y+1]==1 || map[x-1][y-1]==1 || map[x-1][y+1]==1 || map[x+1][y-1]==1)
{
int randomtile=ThreadLocalRandom.current().nextInt(0, 10);
if(randomtile>=1 && randomtile <=7) {
map[x][y]=1;
}
else {
int randomtile2=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile2;
}
}
if(map[x][y-1]==2 || map[x][y+1]==2 || map[x-1][y]==2 || map[x+1][y]==2
|| map[x+1][y+1]==2 || map[x-1][y-1]==2 || map[x-1][y+1]==2 || map[x+1][y-1]==2)
{
int randomtile=ThreadLocalRandom.current().nextInt(0, 10);
if(randomtile>=1 && randomtile <=7) {
map[x][y]=2;
}
else {
int randomtile2=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile2;
}
}
if(map[x][y-1]==3 || map[x][y+1]==3 || map[x-1][y]==3 || map[x+1][y]==3
|| map[x+1][y+1]==3 || map[x-1][y-1]==3 || map[x-1][y+1]==3 || map[x+1][y-1]==3)
{
int randomtile=ThreadLocalRandom.current().nextInt(0, 10);
if(randomtile>=1 && randomtile <=7) {
map[x][y]=3;
}
else {
int randomtile2=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile2;
}
}
if(map[x][y-1]==4 || map[x][y+1]==4 || map[x-1][y]==4 || map[x+1][y]==4
|| map[x+1][y+1]==4 || map[x-1][y-1]==4 || map[x-1][y+1]==4 || map[x+1][y-1]==4)
{
int randomtile=ThreadLocalRandom.current().nextInt(0, 10);
if(randomtile>=1 && randomtile <=7) {
map[x][y]=4;
}
else {
int randomtile2=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile2;
}
}
}
}
}
}
}
My problem is understanding why 4 is more frequent.
Your code is hard to read:
if
block that checks neighbours is a copy/paste job, which means reading it, you have to hunt around to check for differences, and fixing bugs / changing behaviour means you better remember to do it in all 4 places.That's not because you're simply unaware of certain code practices; this code is borderline broken. Clean it up and your question becomes obvious. Hence, the underlying problem is that you've obfuscated the truth by overcomplicating things.
Let's focus on a single if
block:
if(map[x][y-1]==2 || map[x][y+1]==2 || map[x-1][y]==2 || map[x+1][y]==2
|| map[x+1][y+1]==2 || map[x-1][y-1]==2 || map[x-1][y+1]==2 || map[x+1][y-1]==2)
{
int randomtile=ThreadLocalRandom.current().nextInt(0, 10);
if(randomtile>=1 && randomtile <=7) {
map[x][y]=2;
}
else {
int randomtile2=ThreadLocalRandom.current().nextInt(0, 5);
map[x][y]=randomtile2;
}
}
To disentangle this:
The odds that the 'if' triggers is very high and you roll through 4 'if' statements! If the final if
triggers, all the ifs before it is meaningless as all ways through each if block will end up setting the tile value.
This is why you get '4' so much: Because it's the last if block, and almost always the if block triggers (and thus, sets the tile to '4' 76% of the time, which means all further tiles will also be '4' with nearly 76% odds).
Your underlying problem is that you've overcomplicated things, and probably that you aren't actually clear about what algorithm you really want. Surely it's not 'if any neighbour is a 4, then 76% odds this tile should also be a 4'. Especially considering your neighbour check isn't correct either (you loop through all cells left to right then top to bottom, so checking the cell to the right-bottom of you is pointless, as that will always be a 0 as you haven't gotten there yet).
I'd go back to the drawing board, figure out (and not in terms of code, in terms of basic language and some diagrams) what the algorithm should actually be.
At the very least your code picks from 5 tiles (.nextInt(0, 5)
picks randomly from 0,1,2,3 or 4 which is five different numbers!) - but your question indicates you wanted 4.
For example, if it's a very simple: I want each and every tile to just randomly be chosen from 0/1/2/3, then all you need is:
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) {
tile[y][x] = rnd.nextInt(4);
}
That's it. If you want a perfect distribution (as in, there are guaranteed equal amounts of 1/2/3/4 in the grid, i.e. for a 20x20 grid, that's 400 squares, there are always exactly one-hundred 1s, one-hundred 2s, and so on):
List<Integer> tiles = new ArrayList<Integer>();
for (int i = 0; i < width * height / 4; i++) {
tiles.add(1);
tiles.add(2);
tiles.add(3);
tiles.add(4);
}
Collections.shuffle(tiles);
var it = tiles.iterator();
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) {
tiles[y][x] = it.next();
}
This adds 100 of each tile to a bag, shuffles it, and then pulls tiles out of the bag, thus ensuring that each tile is equally likely.
If you really want some 'they tend to clump together' theme going, you'll need to spend quite a bit of time sketching out precisely what the algorithm should be, and as a tip, you tend to want algorithms to get to an endpoint ASAP. In your current code, after one 'if' triggers, you just try the next one which may or may not trigger. That's a bad way to do it - instead every 'if' should end in some sort of break;
. Then it is 'simply' a matter of ensuring every 'if' matches precisely with the odds your algorithm wants it to have.