import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class Generator {
private int W = 25;
private int H = 25;
private int N = 1;
private int M = 1;
private int filledGridNum = 0;
private int coverage = 25;
private int baseStationStrength = 99;
private double effectiveGridRatio = 0.80D;
private int validValue = 0;
private int[][] grids;
private int[][] labels; // default 0 represents weak coverage area
private Map<Integer, List<Integer>> gridValueMap = new HashMap<>();
private Random random;
private int randomIntBetween(int lower, int upper) {
return lower + random.nextInt(upper - lower + 1);
}
private double randomDoubleBetween(double lower, double upper) {
return lower + (upper - lower) * random.nextDouble();
}
private void generate(long seed) {
if (seed == 1) { // sample case
H = 3;
W = 4;
N = 1;
M = 3;
validValue = 5;
grids = new int[][] {
{9, 6, 4},
{2, 1, 7},
{7, 0, 4},
{7, 9, 6}
};
return;
}
random = new Random(seed);
W = randomIntBetween(20, 250);
H = randomIntBetween(20, 250);
N = randomIntBetween(1, 10);
M = randomIntBetween(1, 10);
effectiveGridRatio = randomDoubleBetween(0.7, 0.9);
baseStationStrength = randomIntBetween(70, 100);
coverage = randomIntBetween(Math.min(W, H) / 8, Math.min(W, H) / 4);
grids = new int[W][H];
labels = new int[W][H];
filledGridNum = 0;
while (filledGridNum <= W * H * effectiveGridRatio) {
int baseX = randomIntBetween(0, W - 1);
int baseY = randomIntBetween(0, H - 1);
if (grids[baseX][baseY] == 0 && labels[baseX][baseY] == 0) {
int[] dir = new int[8];
for (int i = 0; i < dir.length; ++i) {
dir[i] = randomIntBetween(0, 1);
}
grids[baseX][baseY] = randomIntBetween(35, baseStationStrength);
fill(dir, coverage, baseX, baseY, grids[baseX][baseY]);
filledGridNum++;
}
}
fillFinalValue();
calValidValue();
}
private void fillFinalValue() {
for (int key : gridValueMap.keySet()) {
int y = key & 0x0000FFFF;
int x = key >> 16;
IntSummaryStatistics stats = gridValueMap.get(key).stream().mapToInt((z) -> z).summaryStatistics();
if (labels[x][y] == 1) {
grids[x][y] = stats.getMax();
} else {
grids[x][y] = (int) stats.getAverage();
}
}
}
private void calValidValue() {
ArrayList<Integer> numList = new ArrayList<>();
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
if (grids[i][j] > 0) {
numList.add(grids[i][j]);
}
}
}
Collections.sort(numList);
validValue = numList.get(randomIntBetween(numList.size() / 3, 2 * numList.size() / 3));
}
private void fill(int[] dir, int radius, int baseX, int baseY, int baseValue) {
labels[baseX][baseY] = 2; // 2 represents the base station area
for (int x = Math.max(0, baseX - radius); x <= Math.min(W - 1, baseX + radius); x++) {
for (int y = Math.max(0, baseY - radius); y <= Math.min(H - 1, baseY + radius); y++) {
if (labels[x][y] == 2) { // Base station area is not affected by other base stations
continue;
}
int dx = x - baseX;
int dy = y - baseY;
int dis2 = dx * dx + dy * dy;
if (dis2 == 0 || dis2 > radius * radius) {
continue;
}
double dis = Math.sqrt(dis2 + 0.0);
double d = ((dis * dis * dis) / (double) radius) * Math.log(dis) + randomDoubleBetween(0.0, 0.2);
int attenuation = (int) (10 * d + 12.67);
double sector = 4 * Math.atan2(dy + 0.0, dx + 0.0) / Math.PI;
if (sector < 0) {
sector += 8;
}
if (dir[(int) Math.floor(sector)] == 1) {
boolean isStrongCoverageArea = (baseValue < 65 && Math.floor(dis) == 1) ||
(baseValue >= 65 && Math.floor(dis) <= 2);
fillSingleGrid(x, y, baseValue, attenuation, isStrongCoverageArea);
}
}
}
}
private void fillSingleGrid(int x, int y, int baseValue, int strength, boolean isStrongCoverageArea) {
int value = Math.max(baseValue - strength, 0);
if (value > 0) {
int key = (x << 16) + y;
if (gridValueMap.containsKey(key)) {
gridValueMap.get(key).add(value);
} else {
List<Integer> list = new ArrayList<>();
list.add(value);
gridValueMap.put(key, list);
grids[x][y] = -1;
filledGridNum++;
if (isStrongCoverageArea) {
labels[x][y] = 1;
}
}
}
}
private void print() {
System.out.println("" + H + " " + W);
System.out.println("" + N + " " + M);
System.out.println(validValue);
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
if (j != 0) System.out.print(" ");
System.out.print(grids[j][i]);
}
System.out.println("");
}
}
private void printLabel() {
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
System.out.print("|");
System.out.print(labels[j][i]);
}
System.out.println("|");
}
}
private void printPic(String name) {
int squareSize = 100;
while (squareSize > 1 && (W*squareSize > 1250 || H*squareSize > 750)) {
--squareSize;
}
BufferedImage bi = new BufferedImage(W * squareSize, H * squareSize, BufferedImage.TYPE_INT_BGR);
int maxValue = 1;
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
maxValue = Math.max(maxValue, grids[i][j]);
}
}
for (int i = 0; i < W; i++) {
for (int j = 0; j < H; j++) {
int[] rgb = getRGB((grids[i][j]*100)/maxValue);
int _x = i * squareSize;
int _y = j * squareSize;
for (int x = _x; x < _x + squareSize; x++) {
for (int y = _y; y < _y + squareSize; y++) {
bi.setRGB(x, y, (((rgb[0] & 0x000000FF) << 16) | ((rgb[1] & 0x000000FF) << 8)) | (rgb[2] & 0x000000FF));
}
}
}
}
try {
ImageIO.write(bi, "png", new File(name + ".png"));
} catch (IOException e) {
System.out.println("Write png error | " + e.getMessage());
}
}
private int[] getRGB(int value) {
int r = 0;
int g = 0;
int b = 0;
if (value >= 80) {
r = 255;
} else if (value >= 70) {
r = 255;
g = 97;
} else if (value >= 60) {
r = 255;
g = 255;
} else if (value >= 50) {
r = 34;
g = 139;
b = 34;
} else if (value >= 40) {
g = 255;
} else if (value >= 30) {
g = 255;
b = 127;
} else {
r = 255;
g = 255;
b = 255;
}
int[] rgb = new int[3];
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
return rgb;
}
public static void main(String args[]) {
long seed = 1L;
if (args.length != 0) seed = Long.parseLong(args[0]);
Generator generator = new Generator();
generator.generate(seed);
generator.print();
generator.printPic("grid-" + seed);
}
}