PuyoPuyo DFS算法练习
题目和解析有空再整理。
package puyopuyo;
/**
* @Author jinjun99
* @Date Created in 2021/11/21 11:18
* @Description
* @Since version-1.0
*/
public class Block {
/**
* 状态
*/
int event = 0;
/**
* 方向
*/
int dir = 0;
/**
* 列号
*/
int col = 0;
/**
* 颜色
*/
int[] val;
public Block(int[] val) {
this.val = val;
}
}
package puyopuyo;
/**
* @Author jinjun99
* @Date Created in 2021/11/21 13:00
* @Description
* @Since version-1.0
*/
public class Point {
int x = 0;
int y = 0;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point() {
}
}
package puyopuyo;
import java.util.Arrays;
import java.util.Stack;
/**
* @Author jinjun99
* @Date Created in 2021/11/21 17:36
* @Description
* @Since version-1.0
*/
public class Demo02 {
/**
* 宽度
*/
private static int width = 4;
/**
* 高度
*/
private static int height = 6;
/**
* 地图
*/
private static int[][] map = new int[height][width];
/**
* 标记图
*/
private static int[][] mark = new int[height][width];
/**
* 列的高度,y坐标
*/
private static int[] tail = new int[width];
private static int[] dirX = {1,0,-1,0};
private static int[] dirY = {0,1,0,-1};
/**
* 当前块
*/
private static Block block;
/**
* 地图初始化
*/
private static void inti(int w){
width = w;
map = new int[height][width];
}
/**
* 旋转一个角度
* @param angle
*/
private static void rotate(int angle){
block.dir=(block.dir+angle)%4;
//右边界
if (block.dir==0&&block.col==width-1){
block.col=width-2;
}
if (block.dir==2&&block.col==0){
block.col=1;
}
}
/**
* 移动一段距离
* @param distance
*/
private static void move(int distance){
block.col+=distance;
//中间区域不用考虑
if (block.col>=1 && block.col<=width-2){
return;
}
//右方向看右边界
if (block.dir==0 && block.col>=width-1){
block.col=width-2;
return;
}
//左方向看左边界
if (block.dir==2 && block.col<=0){
block.col=1;
return;
}
//其他方向右越界(dis过大)
if (block.col > width-1){
block.col = width-1;
}
//其他方向左越界(dis过大)
if (block.col < 0){
block.col = 0;
}
}
private static void hinder(int count,int life){
// block.event = 2;
int h = height-1;
for (int i = 0; i < count; i++) {
map[h-tail[i]][i] = -1*life;
tail[i]++;
}
}
/**
* 更新当前块下落后的地图,记录列高度
* @return
*/
private static int land(){
//1.将一个圆叠在另一个圆上,不留空隙。
Point p1 = new Point();
Point p2 = new Point();
int h = height-1;
if (block.event==0){
switch (block.dir){
case 0:
{
p1.x = block.col;
p1.y = h-tail[block.col];
map[p1.y][p1.x] = block.val[0];
p2.x = block.col+1;
p2.y = h-tail[block.col];
map[p2.y][p2.x] = block.val[1];
tail[block.col]++;
tail[block.col+1]++;
break;
}
case 1:
{
p1.x = block.col;
p1.y = h-(tail[block.col]+1);
map[p1.y][p1.x] = block.val[0];
p2.x = block.col;
p2.y = h-tail[block.col];
map[p2.y][p2.x] = block.val[1];
tail[block.col]+=2;
break;
}
case 2:
{
p1.x = block.col;
p1.y = h-tail[block.col];
map[p1.y][p1.x] = block.val[0];
p2.x = block.col-1;
p2.y = h-tail[block.col-1];
map[p2.y][p2.x] = block.val[1];
tail[block.col]++;
tail[block.col-1]++;
break;
}
case 3:
{
p1.x = block.col;
p1.y = h-tail[block.col];
map[p1.y][p1.x] = block.val[0];
p2.x = block.col;
p2.y = h-(tail[block.col]+1);
map[p2.y][p2.x] = block.val[1];
tail[block.col]+=2;
break;
}
default:
break;
}
solution(p1,p2);
}
int j=0;
for (int i = 0; i < width; i++) {
j= Math.max(tail[i], j);
}
return j;
}
private static Point[] drop = new Point[width*height];
/**
* 块下落后的消除
* @param p1
* @param p2
*/
private static void solution(Point p1,Point p2){
int dropNum = 2;
drop[0] = p1;
drop[1] = p2;
while (dropNum!=0){
for (int i = 0; i < dropNum; i++) {
//一组两个颜色相同
if (mark[drop[i].y][drop[i].x] == 1){
continue;
}
dfs(drop[i].x,drop[i].y);
clear();
}
markHinder();
dropNum = updateMap();
}
}
private static Stack<Point> elimP = new Stack<>();
private static int[][] mark2 = new int[height][width];
/**
* 搜索4个同色相连块,放入搜索队列
* @param x
* @param y
*/
private static void dfs(int x,int y){
mark2[y][x] = 1;
elimP.push(new Point(x,y));
for (int i = 0; i < 4; i++) {
int a = x+dirX[i];
int b = y+dirY[i];
if (a>=0&&a<width&&b>=0&&b<height&&map[b][a]==map[y][x]&&mark2[b][a]==0){
dfs(a,b);
}
}
}
/**
* 根据搜索结果清理同色块
*/
private static void clear(){
int s = elimP.size();
if (s>=4){
for (int i = 0; i < s; i++) {
Point p = elimP.pop();
map[p.y][p.x]=0;
mark[p.y][p.x]=1;
tail[p.x]--;
}
}
elimP.removeAllElements();
}
/**
* 消除同色块后,更新阻碍块寿命和位置,顺便消除标记
*/
private static void markHinder(){
int h = height-1;
for (int i = 0; i < width; i++) {
for (int j = 0; j <= tail[i]; j++) {
if (map[h-j][i]<0){
if (check(h-j,i)==1){
map[h-j][i] += 1;
if (map[h-j][i]==0){
tail[i]--;
}
}
}
}
}
mark2 = new int[height][width];
mark = new int[height][width];
}
/**
* 同色块消除后,把空中的块放下来,顺便放入搜索队列
* @return 空中块的数量
*/
private static int updateMap(){
int c = 0;
int s = 0;
int sum = 0;
int h = height-1;
for (int i = 0; i < width; i++) {
for (int j = 0; j < tail[i]; j++) {
int l = h-j;
if (map[l][i]==0){
if (j>=tail[i]){
break;
}
//j=1,c=3
while (map[l-c][i]==0&&j+c<tail[i]){
c++;
}
if (j+c+1==tail[i]){
tail[i]=j;
break;
}
if (map[l-c][i]>0) {
map[l][i] = map[l - c][i];
map[l - c][i] = 0;
drop[s].x = i;
drop[s++].y = l;
sum++;
}
if (map[l-c][i]<0) {
map[l][i] = map[l - c][i];
map[l - c][i] = 0;
}
}
}
}
return sum;
}
/**
* 查看阻碍块四周是否有爆裂的同色块
* @param y
* @param x
* @return
*/
private static int check(int y,int x){
for (int i = 0; i < 4; i++) {
int a = y+dirY[i];
int b = x+dirX[i];
if (a>=0&&b>=0&&a<height&&b<width&&mark[a][b]==1){
return 1;
}
}
return 0;
}
public static void main(String[] args) {
int sum = 0;
block = new Block(new int[]{1,1});
rotate(0);
move(1);
sum = land();
hinder(2,2);
hinder(4,1);
block = new Block(new int[]{2,2});
rotate(0);
move(2);
sum = land();
block = new Block(new int[]{1,1});
rotate(1);
move(2);
sum = land();
block = new Block(new int[]{2,2});
rotate(1);
move(3);
sum = land();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (map[i][j]<0){
System.out.print(map[i][j]);
}else {
System.out.print(" "+map[i][j]);
}
if (j==width-1){
System.out.println();
}
}
}
System.out.println("最高列长度是:"+sum);
}
}
负数代表阻碍块生命值,正数代表颜色,0为空
打印一下过程:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 1 1 0
最高列长度是:1
0 0 0 0
0 0 0 0
0 0 0 0
0-1 2 0
-1-2-1 2
-2 1 1-1
最高列长度是:3
0 0 0 0
0 0 1 0
0 0 1 0
0-1 2 0
-1-2-1 2
-2 1 1-1
最高列长度是:5
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
-1 0 0 0
-1-1 0 0
最高列长度是:2