201604-2 俄罗斯方块

29 篇文章 0 订阅
22 篇文章 1 订阅

解题思路

对下降的方块确定上下左右界限,在地图中找到下降的起始列和结束列(和下降块匹配),遍历地图map,直到当前的位置的值和下降块该处的值相与,如果=1,说明找到了第一个可能是界限的行,然后从当前行进行遍历,遍历的方法是:

假如下降块为:
0 1 1 0
0 0 1 0
0 0 1 0
0 0 0 0
分离之后的下降块为:
1 1
0 1
0 1
即只保留包含整个下降块的矩阵,然后用该矩阵去遍历分离出的map
先从地图map中确认起始的列:n-1+left_boundary,结束列:n-1+right_boundary
测试数据:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0
1 1 1 1 0 0 1 1 1 1
0 0 0 0 1 0 0 0 0 0
0 1 1 0
0 0 1 0
0 0 1 0
0 0 0 0
3

裁剪后的map为:
测试样例1
遍历分离的map发现第一个可能在此停止下降的点:
测试样例2
用改行与下降块的最后一行进行匹配,如果不满足对应元素相与为1的情况,就将其增加为两行,与下降块的倒数两行进行判断
【注意】数组map增设一行,即最后一行全设为1,防止下降过程中无障碍物数组下标访问越界的情况,同时便于判断。
【说明】下降停留行位置的判断实例:

下降块:(此处新设的数据,与上例的数据不同)
1 1
0 1
0 1
遍历得到的第一个对应位置相与不为0的map的行:
1 0
用改行与最后一行:0 1匹配,0 && 1 = 0, 1 && 0 = 0,不满足条件,则方格可以继续下降一个单位,于是就变为:
0 1
0 1
与map的 1 0及其下一行匹配,假设为
1 0
1 0
按照以上方法,仍然不匹配,继续下降一个单位:
1 1
0 1
0 1
与
1 0
1 0
1 0
匹配,由于1 && 1 = 1,满足条件,得到降落点所在行,然后根据得到的行标记,用切割后的下降块矩阵更新map。

经检查,该代码不完整,仍然存在bug…在中间的障碍物,无法正确检测。

#include <iostream>
#include <cstdio>
using namespace std;

const int ROW = 15;
const int COL = 10;
const int N = 4;

int map[ROW + 1][COL];
int block[N][N];
int lower_boundary = 0, upper_boundary = 3;
int left_boundary = 3, right_boundary = 0;

int main(int argc, char const *argv[])
{
	std::ios::sync_with_stdio(false);

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			cin >> map[i][j];
		}
	}
	for (int j = 0; j < COL; j++)
	{
		map[ROW][j] = 1;
	}

	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			cin >> block[i][j];
			if (block[i][j])
			{
				if (i < upper_boundary)
					upper_boundary = i;
				if (i > lower_boundary)
					lower_boundary = i;
				if (j < left_boundary)
					left_boundary = j;
				if (j > right_boundary)
					right_boundary = j;
			}
		}
	}
	// printf("upper_boundary:%d\n", upper_boundary);
	// printf("lower_boundary:%d\n", lower_boundary);
	// printf("left_boundary:%d\n", left_boundary);
	// printf("right_boundary:%d\n", right_boundary);
	int n;
	cin >> n; // 从左边的第n-1列开始下落

	// 找到第一个不为0的障碍物节点
	int flag_x = ROW;
	bool flag = false;
	// cout << n - 1 + left_boundary << endl;
	// cout << n + right_boundary + 1 << endl;
	for (int i = 0; i < ROW + 1 && !flag; i++)
	{
		for (int j = n - 1 + left_boundary; j < n + right_boundary; j++)
		{
			// 如果该位置不为0
			if (map[i][j])
			{
				flag_x = i;
				flag = true;
				break;
			}
		}
	}
	// printf("flag_x=%d\n", flag_x);
	flag = false;
	int stop_x = flag_x;
	for (int i = lower_boundary, index = 0; i >= upper_boundary - index && !flag; i--)
	{
		for (int j = left_boundary; j <= right_boundary; j++)
		{
			if (block[i][j] && map[flag_x + index][n - 1 + j])
			{
				stop_x = flag_x + index;
				flag = true;
				break;
			}
		}
		if (!flag)
		{
			index++;
		}
	}
	// printf("stop_x=%d\n", stop_x);

	// 更新格子状态
	int start_x = stop_x - 1;
	for (int i = lower_boundary; i >= upper_boundary; i--, start_x--)
	{
		int start_y = n - 1 + left_boundary;
		for (int j = left_boundary; j <= right_boundary; j++, start_y++)
		{
			map[start_x][start_y] = map[start_x][start_y] || block[i][j];
		}
	}

	// output
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			cout << map[i][j] << " ";
		}
		cout << endl;
	}

	return 0;
}

修改版

参考:https://blog.csdn.net/tigerisland45/article/details/54790942

主要思想在于构建下降的坐标系,下降块(4*4的矩阵)block左上角为坐标原点,每次遍历将坐标原点下移一个单位,直到满足可以停落的条件,然后用之前标记的block中为1的障碍物的坐标去填充背景图backmap即可。

#include <iostream>
using namespace std;

const int ROW = 15;
const int COL = 10;
const int N = 4;
int backmap[ROW + 1][COL];
int block[N][N];

struct coord
{
    int row;
    int col;

    void operator()(const int row, const int col)
    {
        this->row = row;
        this->col = col;
    }
} coords[N];

int main(int argc, char const *argv[])
{
    std::ios::sync_with_stdio(false);
    int row, col;

    // 初始化
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            cin >> backmap[i][j];
        }
    }
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            cin >> block[i][j];
        }
    }
    cin >> col;
    for (int j = 0; j < COL; j++)
    {
        backmap[ROW][j] = 1; // 将最后一行设置为1
    }
    // 记录block的不为0的障碍块的相对坐标
    int k = 0;
    for (int i = N - 1; i >= 0; i--)
    {
        for (int j = 0; j < N; j++)
        {
            if (block[i][j])
            {
                coords[k++](i, j);
            }
        }
    }
    for (int i = 0; i < N; i++)
    {
        cout << coords[i].row << "," << coords[i].col << endl;
    }

    // 处理下降
    row = 1, col--;
    bool flag = false;
    while (!flag)
    {
        for (int i = 0; i < N; i++)
        {
            if (backmap[row + coords[i].row][col + coords[i].col] == 1)
            {
                flag = true;
                break;
            }
        }
        if (!flag)
            row++;
        else
            break;
    }
    row--; // 得到满足降落的坐标
    for (int i = 0; i < N; i++)
    {
        backmap[row + coords[i].row][col + coords[i].col] = 1;
    }
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            cout << backmap[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

【PS】使用两个break的原因:break只能够一层一层地跳出循环,不能跳出多重循环,如果要直接跳出多重循环,需要使用goto语句,但并不推荐使用,goto破坏了代码的结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值