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);
}
}
}
}
}