Я исследовал алгоритм случайного блуждания с этим кодом и наткнулся на проблему, которую пока не могу понять. Кажется, левая часть генерируемого изображения заполняется быстрее, чем правая. Я несколько раз просматривал код и не могу понять, сработал ли его шаблон распределения или просто ошибка программирования.
Этот код случайным образом выбирает 4 направления, куда ставить следующую точку, и, если точка уже занята (1 в байтовом массиве), он пытается найти свободную, используя предварительно рассчитанный расширяющийся круговой паттерн. Переменная «scale» - это размер отдельного «точечного» прямоугольника. «circleFillR» определяет размер предварительно рассчитанного массива окружностей с шагом 1 до «circleFillR». Для увеличения количества попыток размещения точки используются переменные «nSteps» и «nSeries».
Исходный код должен быть автономным Java 1.8:)
package random_walker;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class random_walker3 extends JPanel{
JFrame fr;
public final Logger LOG = Logger.getLogger(random_walker3.class.getName());
Graphics2D g = null;
private int scale = 5;
private final int panelX = 1600, panelY = 850;
private int dotsX = (panelX / scale) - scale / 2;
private int dotsY = (panelY / scale) - scale / 2;
private byte[][] fl;
public int mouseX = 0, mouseY = 0;
Random r = new Random(System.currentTimeMillis());
int nSeries = 1;
int nSteps = 40000;
public int circleFillR = 30;
class Point2d {
Point2d(int _x, int _y) { x = _x; y = _y;}
public int x;
public int y;
}
public ArrayList<Point2d>[] circ;
int lX, lY;
private void dot(int x, int y) {
g.fillRect(x * scale, y * scale, scale, scale);
}
public void paintComponent(Graphics gr) {
super.paintComponent(gr);
g = (Graphics2D) gr;
setBackground(Color.white);
for(int i = 0; i < dotsX * dotsY; i++) {
if(fl[i % dotsX][i / dotsX] == 1) dot(i % dotsX, i / dotsX);
}
}
private void zeroByte2DArray(byte[][] a) {
for(int x = 0; x < a.length; x++)
Arrays.fill( a[x], (byte) 0);
}
private void StartSim() {
zeroByte2DArray(fl);
for(int j = 0; j < nSeries; j++) {
lX = Math.abs(r.nextInt() % (dotsX - 1));
lY = Math.abs(r.nextInt() % (dotsY - 1));
int dir;
for(int i = 0; i < nSteps; i++) {
if(i % 10 == 0) repaint();
dir = Math.abs(r.nextInt() % 4);
switch(dir) {
case 0:
if(lY > 0) lY--;
else lY = dotsY - 1;
break;
case 1:
if(lX < dotsX - 2) lX++;
else lX = 0;
break;
case 2:
if(lY < dotsY - 2) lY++;
else lY = 0;
break;
case 3:
if(lX > 0) lX--;
else lX = dotsX - 1;
break;
default:
LOG.info("junk lx " + lX + " ly " + lY);
System.exit(1);
}
try {
if(fl[lX][lY] == 1) {
TryCircular();
}
else fl[lX][lY] = 1;
}
catch (Exception e) {
LOG.info("lx " + lX + " ly " + lY);
System.exit(1);
}
}
repaint();
}
}
private void TryCircular() {
ArrayList<Point2d> ar;
for(int i = 1; i < circleFillR; i++) {
ar = circ[i];
for (Point2d pd : ar) {
if(lX + pd.x < dotsX && lX + pd.x >= 0 && lY + pd.y < dotsY && lY + pd.y >= 0 ) {
if(fl[lX + pd.x][lY + pd.y] == 0) {
fl[lX + pd.x][lY + pd.y] = 1;
lX += pd.x;
lY += pd.y;
return;
}
}
}
}
}
public void ButtonStartMouseActionHandler(ActionEvent e) {
StartSim();
}
private void AddButtonListeners(JButton b) {
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ButtonStartMouseActionHandler(e);
}
});
b.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
int newPosX, newPosY;
newPosX = b.getX() + e.getX() - mouseX;
newPosY = b.getY() + e.getY() - mouseY;
if(newPosX < 0) newPosX = 0;
if(newPosX > panelX - 50) newPosX = panelX - 50;
if(newPosY < 0) newPosY = 0;
if(newPosY > panelY - 50) newPosY = panelY - 50;
b.move(newPosX, newPosY);
}
@Override
public void mousePressed(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseClicked(MouseEvent e) {}
});
}
public ArrayList<Point2d> bcircle_list(int r) {
ArrayList<Point2d> ls = new ArrayList<Point2d>();
int x = 0;
int y = r;
int d = (5 - r * 4) / 4;
do {
ls.add(new Point2d(-y, x));
ls.add(new Point2d(-y, -x));
ls.add(new Point2d(y, x));
ls.add(new Point2d(y, -x));
ls.add(new Point2d(-x, y));
ls.add(new Point2d(-x, -y));
ls.add(new Point2d(x, y));
ls.add(new Point2d(x, -y));
if(d < 0) {
d += 2 * x + 1;
}
else {
d += 2 * (x - y) + 1;
y--;
}
x++;
} while(x <= y);
return ls;
}
public static void main(String[] args) {
random_walker3 pan = new random_walker3();
pan.fl = new byte[pan.dotsX][pan.dotsY];
pan.fr = new JFrame("random walker3");
pan.circ = new ArrayList[pan.circleFillR];
JButton bStart = new JButton("Refresh");
pan.AddButtonListeners(bStart);
pan.add(bStart);
pan.fr.add(pan);
pan.fr.setBounds(100, 100, pan.panelX, pan.panelY);
pan.fr.setVisible(true);
pan.fr.setFocusable(true);
pan.fr.setResizable(false);
pan.fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pan.fr.setBackground(Color.white);
pan.PreComputeCircles();
pan.LOG.info("starting with " + pan.dotsX + "x" + pan.dotsY + "="+ pan.dotsX * pan.dotsY + " points");
pan.StartSim();
}
private void PreComputeCircles() {
for(int i = 1; i < circleFillR; i++) {
circ[i] = bcircle_list(i);
}
}
}