Схема распределения алгоритма двумерного случайного блуждания - PullRequest
0 голосов
/ 16 января 2020

Я исследовал алгоритм случайного блуждания с этим кодом и наткнулся на проблему, которую пока не могу понять. Кажется, левая часть генерируемого изображения заполняется быстрее, чем правая. Я несколько раз просматривал код и не могу понять, сработал ли его шаблон распределения или просто ошибка программирования.

Этот код случайным образом выбирает 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);
        }
    }
}
...