Java-maze迷宫生成算法

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentSkipListSet;

public class MazeView extends View {

    public static int[][] dirArray = new int[][]{
            {0, 2}, {0, -2}, {2, 0}, {-2, 0},
    };
    private static List<int[]> dir = Arrays.asList(dirArray);

    int xCount, yCount;
    int xCells, yCells;
    int xWalls, yWalls;

    Paint wallPaint;
    Paint cellPaint;

    int wallSize;
    int cellSize;

    List<Integer> visitedCell = new ArrayList<>(); // cell
    HashSet<Integer> completedCell = new HashSet<>(); // cell 已完成的格子
    ConcurrentSkipListSet<Integer> removedWall = new ConcurrentSkipListSet<>(); // wall

    Random random = new Random();

    public MazeView(Context context) {
        this(context, null);
    }

    public MazeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MazeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        wallPaint = new Paint();
        wallPaint.setColor(Color.BLACK);
        wallPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        cellPaint = new Paint();
        cellPaint.setColor(Color.WHITE);
        cellPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        wallSize = 10;
        cellSize = 30;
    }

    private void generateMaze() {
        xWalls = getWidth() / (wallSize + cellSize);
        yWalls = getHeight() / (wallSize + cellSize);

        xCells = xWalls - 1;
        yCells = yWalls - 1;

        xCount = xCells + xWalls;
        yCount = yCells + yWalls;

        int cellx = random.nextInt(xCount);
        int celly = random.nextInt(yCount);
        cellx |= 1;
        celly |= 1;

        visitedCell.add((cellx << 16) + celly);

        while (visitedCell.size() > 0) {
            int index = random.nextInt(visitedCell.size());
            int cell = visitedCell.get(index);

            int cx = cell >> 16;
            int cy = cell & 65535;
            Collections.shuffle(dir);
            boolean find = false;
            for (int[] d : dir) {
                int x = cx + d[0];
                int y = cy + d[1];
                if (x >= 0 && x < xCount && y >= 0 && y < yCount) {
                    int p = (x << 16) + y;
                    if (!completedCell.contains(p) && !visitedCell.contains(p)) {
                        find = true;
                        visitedCell.add(p);
                        int wallx = (cx + x) / 2;
                        int wally = (cy + y) / 2;
                        int wallp = (wallx << 16) + wally;
                        removedWall.add(wallp);
                        break;
                    }
                }
            }
            if (!find) {
                completedCell.add(cell);
                visitedCell.remove(index);
            }
            SystemClock.sleep(1);
            postInvalidate();
        }
        Log.d("chao", "exit");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Async.run(() -> {
            if (xCount == 0) {
                generateMaze();
            }
        });
        drawCells(canvas);
        removeWalls(canvas);
    }

    private void removeWalls(Canvas canvas) {
        for (int pack : removedWall) {
            int x = pack >> 16;
            int y = pack & 65535;
            int wallsY = (y + 1) / 2;
            int cellsY = y / 2;
            int wallsX = (x + 1) / 2;
            int cellsX = x / 2;

            boolean vertical = x % 2 == 0;
            int width = vertical ? wallSize : cellSize;
            int height = !vertical ? wallSize : cellSize;

            int top = wallsY * wallSize + cellsY * cellSize;
            int left = wallsX * wallSize + cellsX * cellSize;
            canvas.drawRect(left, top, left + width, top + height, cellPaint);
        }
    }

    private void drawCells(Canvas canvas) {
        int realw = xWalls * wallSize + xCells * cellSize;
        int realh = yWalls * wallSize + yCells * cellSize;
        int tx = (getWidth() - realw) / 2;
        int ty = (getHeight() - realh) / 2;

        setTranslationX(tx);
        setTranslationY(ty);

        canvas.drawRect(0, 0, realw, realh, wallPaint);

        for (int i = 0; i < yCount; i++) {
            for (int j = 0; j < xCount; j++) {
                if (i % 2 == 1 && j % 2 == 1) {
                    int wallsY = (i + 1) / 2;
                    int cellsY = i - wallsY;
                    int wallsX = (j + 1) / 2;
                    int cellsX = j - wallsX;
                    int top = wallsY * wallSize + cellsY * cellSize;
                    int left = wallsX * wallSize + cellsX * cellSize;
                    canvas.drawRect(left, top, left + cellSize, top + cellSize, cellPaint);
                }
            }
        }
    }

}

posted @ 2022-07-19 20:13  rome753  阅读(230)  评论(0编辑  收藏  举报