数据结构- 炸弹人游戏

1. 基本任务介绍

算法目的:炸弹放在哪里可以最大杀伤?
编程难点

  1. 数组作为形参是深(是)?如果深,有必要应用?
    答:形参是实参的一份拷贝,是局部变量。但是数组是个例外,因为数组的数据太多了,将其一一赋值既麻烦又浪费空间,所以数组作为参数传递给函数的只是数组首元素的地址,数据还是在内存里的,函数在需要用到后面元素时再按照这个地址和数组下标去内存查找。也就是说后面的元素根本没到函数里来。因为数组的复制将导致连续的内存读与内存写,其时间开销取决于数组长度,有可能会变得非常大。为了避免复制数组的开销,才用指针代替数组。因此C语言使得当数组作为实参传递给函数的时候,将退化为同类型的指针,再传递指针的值。
    因此,在函数中修改数组值时,修改的是真的值。
  • 由于是通过指针传递,因此无法得到数组的长度。(在通过指针传递时,需要另外传入参数来传递数组的大小)
  • 传递引用时,同时将数组长度也传递进去了,所以传入时必须为相应长度的数组。并且,在传递引用时,需要注意用()将&aa括起来,否则编译器报错。
  1. 二维数组形参和一维不太一样
  • (Type (&str_)[size], char map_[][13]) 后面的13好像不能少
  1. 不能纯统计每行列的敌人,有墙的

代码


// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
# include <string>
#include<iostream>
using namespace std;
char map_[13][13] = {0
  };
std::string map2[] = {
    "#############",
"#GG.GGG#GGG.#",
"###.#G#G#G#G#",
"#.......#..G#",
"#G#.###.#G#G#",
"#GG.GGG.#.GG#",
"#G#.#G#.#.#.#",
"##G...G.....#",
"#G#.#G###.#G#",
"#...G#GGG.GG#",
"#G#.#G#G#.#G#",
"#GG.GGG#G.GG#",
"#############",
};
 int lines = sizeof(map_) / sizeof(map_[0][0]); //总共多长
    int col = sizeof(map_[0])/ sizeof(map_[0][0]); 
    int row = lines / col;
template <typename  Type, int size>
void string2char(Type (&str_)[size], char map_[][13]) {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < str_[i].size(); j++) {
            map_[i][j] = str_[i][j];
        }
    }
}

int get_range1(int i, int j) {
    int num = 0;
    for (int i_ = 0; i_ < row; i_++) {
        if (map_[i_][j] == 'G') num += 1;
        //num += map_[i_][j];
    }
    for (int i_ = 0; i_ < col; i_++) {
        if (map_[i][i_] == 'G') num += 1;
        //num += map_[i][i_];
    }
    return num;
}
int get_direction(int  currenti, int  currentj, int direction[2]) {
    int num = 0;
    while ((currenti >= 0 && currenti <= row)&&((currentj >= 0 && currentj <= col) )) {
        currenti += direction[0];
        currentj += direction[1];

        if (map_[currenti][currentj] == 'G') 
            num += 1;
        if (map_[currenti][currentj] == '#')
            break;
        
    }
    return num;
}
int get_range(int i, int j) {
    int num = 0;
    int currenti=i, currentj=j;
    int direction[][2] = {
        {1,0},
        {0,1},
        {-1,0},
        {0,-1}
    };
    for (auto d : direction) {
        num += get_direction(i, j, d);
    }
    return num;
}




void main() {
    string2char(map2, map_);
    int i = 0;
    // 遍历所有 map_ 的点位
    int num_ = 0;
    int maxi = 0;
    int maxj = 0;
    int max_num = 0;
    for (int i = 0; i < row;i++) {
        for (int j = 0; j < col; j++) {
            if (map_[i][j] == '.') {
                num_ = get_range(i, j);
                if (num_ > max_num) {
                    maxi = i;
                    maxj = j;
                    max_num = num_;
                }
            }
                

        }
    }
    cout << maxi << "," << maxj << endl;
    return;
}


2. 基于广度搜索的炸弹人算法

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
# include <string>
#include<iostream>
using namespace std;
char map_[13][13] = {0
  };
std::string map2[] = {
    "#############",
"#GG.GGG#GGG.#",
"###.#G#G#G#G#",
"#.......#..G#",
"#G#.###.#G#G#",
"#GG.GGG.#.GG#",
"#G#.#G#.#.#.#",
"##G...G.....#",
"#G#.#G###.#G#",
"#...G#GGG.GG#",
"#G#.#G#G#.#G#",
"#GG.GGG#G.GG#",
"#############",
};
 int lines = sizeof(map_) / sizeof(map_[0][0]); //总共多长
    int col = sizeof(map_[0])/ sizeof(map_[0][0]); 
    int row = lines / col;
template <typename  Type, int size>
void string2char(Type (&str_)[size], char map_[][13]) {
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < str_[i].size(); j++) {
            map_[i][j] = str_[i][j];
        }
    }
}

int get_direction(int  currenti, int  currentj, int direction[2]) {
    int num = 0;
    while ((currenti >= 0 && currenti <= row)&&((currentj >= 0 && currentj <= col) )) {
        currenti += direction[0];
        currentj += direction[1];

        if (map_[currenti][currentj] == 'G') 
            num += 1;
        if (map_[currenti][currentj] == '#')
            break;
        
    }
    return num;
}
int get_range(int i, int j) {
    int num = 0;
    int currenti=i, currentj=j;
    int direction[][2] = {
        {1,0},
        {0,1},
        {-1,0},
        {0,-1}
    };
    for (auto d : direction) {
        num += get_direction(i, j, d);
    }
    return num;
}


// ---------------

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <queue>
#include<vector>
#include<string>
using namespace std;

struct Point {
	//行与列
	int row;
	int col;
	int step = 0;
	int range = -1;

	//默认构造函数
	Point() {
		row = col = -1;
	}

	Point(int x, int y, int step_ = 0) {
		this->row = x;
		this->col = y;
		step = step_;
	}

	bool operator==(const Point& rhs) const {
		if (this->row == rhs.row && this->col == rhs.col)
			return true;
		return false;
	}
};


class Pos_find {
public:
	int maze[13][13];
	int passed[13][13];
	int neighbour[4][2] = {
		{1,0},
		{0,1},
		{-1,0},
		{0,-1}
	};	
	int row = sizeof(maze) / sizeof(maze[0]);
	int col = sizeof(maze[0]) / sizeof(maze[0][0]);
	int range_map[13][13] = { 0 }; //[]TODO: int range_map[row][col] = { 0 }; 为什么报错
	int obstacles = -1, blank = 0, enemy=-2;
	queue<Point> vecPath;
	Point ** mark = 0;
	template <class  T1, class  T2>
	bool valid_point(Point point, T1 obstacles = -1, T2 blank = 0) {
		//判断点是否可以作为下一 1 障碍物 2 边界 3 未走过
		int row = sizeof(maze) / sizeof(maze[0]);
		int col = sizeof(maze[0]) / sizeof(maze[0][0]);

		// 判断障碍物
		if (maze[point.row][point.col] == obstacles) {
			return false;
		}
		if (enemy != -2 && (maze[point.row][point.col] == enemy)) {
			return false;
		}

		// 判断边界
		if ((point.row < 0 || point.row > row - 1) || (point.col < 0 || point.col > col - 1))
			return false;

		else
			// 未走过
			if (passed[point.row][point.col] == 0)
				return true;
			else {
				cout << "wrong in valid" << endl;
				return false;
			}
	}

 
	int get_range(int i, int j) {
		int num = 0;
		//int currenti = i, currentj = j;
		int direction[][2] = {
			{1,0},
			{0,1},
			{-1,0},
			{0,-1}
		};
		for (auto d : direction) {
			num += get_direction(i, j, d);
		}
		return num;
	}

	int get_direction(int  currenti, int  currentj, int direction[2]) {
		int num = 0;
		while ((currenti >= 0 && currenti <= row) && ((currentj >= 0 && currentj <= col))) {
			currenti += direction[0];
			currentj += direction[1];

			if (maze[currenti][currentj] == 'G')
				num += 1;
			if (maze[currenti][currentj] == '#')
				break;

		}
		return num;
	}

	// 修改地图
	template <typename  Type, int size>
	void string2char(Type(&str_)[size]) {
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < str_[i].size(); j++) {
				maze[i][j] = str_[i][j];
			}
		}
		obstacles = '#';
		blank = '.';
		enemy = 'G';

	}

	void mazePath( Point& start_pos, Point& target_pos) {
		vecPath = queue<Point>();// build a empty queue
		vecPath.push(start_pos);
		maze[start_pos.row][start_pos.col] = 1;
		int flag = 0;
		int row = sizeof(maze) / sizeof(maze[0]);
		int col = sizeof(maze[0]) / sizeof(maze[0][0]);
		Point temp_point, new_point;
		int i = 1;
		// 建立一个二维数组,每个数组里面是Point
		Point** mark = new Point * [row];//[TODO] 这里不需要释放吗?
		//for (auto ) // ?auto 吗?[TODO]
		for (int i = 0; i < row; i++) {
			mark[i] = new Point[col];
		}
		// 开始的格子指向自己
		mark[0][0] = start_pos;
		// 指向数组的指针
		while (vecPath.empty() == false) {
			// 取
			temp_point = vecPath.front();
			// 获取相邻值
			for (auto deta : neighbour) {
				new_point = Point(temp_point.row + deta[0], temp_point.col + deta[1], temp_point.step + 1);
				if (valid_point(new_point, obstacles, blank)) { // 如果点可以加入
					maze[new_point.row][new_point.col] = temp_point.step + 1;
					mark[new_point.row][new_point.col] = temp_point;// 放入父节点
					vecPath.push(new_point);
				}
				if (new_point == target_pos) {
					flag = 1;
					break;
				}
			}
			vecPath.pop();
			if (flag == 1) break;
			i++;
		}

		if (vecPath.empty() == false) {
			// 获取最后一个格子的数值
			temp_point = vecPath.back();
			// 依据最后一个获取前一个
			while ((temp_point.row == start_pos.row && temp_point.col == start_pos.col) == false) {
				cout << " <" << temp_point.row << "," << temp_point.col << "> ";
				temp_point = mark[temp_point.row][temp_point.col];
			}
		}
		return;
	}

	void mazePath(Point& start_pos) {
		int num_ = 0;
		int maxi = 0;
		int maxj = 0;
		int max_num = 0;
		vecPath = queue<Point>();// build a empty queue
		vecPath.push(start_pos);
		//maze[start_pos.row][start_pos.col] = 1; []TODO:记录步伐应该放在一起,这种容易漏掉。
		max_num = get_range(start_pos.row, start_pos.col);
		range_map[start_pos.row][start_pos.col] = max_num;
		passed[start_pos.row][start_pos.col] = 1;
		int flag = 0;

		Point temp_point, new_point;
		int i = 1;
		// 建立一个二维数组,每个数组里面是Point
		Point** mark = new Point * [row];//[TODO] 这里不需要释放吗?		
		//for (auto ) // ?auto 吗?[TODO]
		for (int i = 0; i < row; i++) {
			mark[i] = new Point[col];
		}
		// 开始的格子指向自己
		mark[0][0] = start_pos;



		// 指向数组的指针
		while (vecPath.empty() == false) {
			// 取
			temp_point = vecPath.front();
			// 获取相邻值
			for (auto deta : neighbour) {
				new_point = Point(temp_point.row + deta[0], temp_point.col + deta[1], temp_point.step + 1);
				if (valid_point(new_point, obstacles, blank)) { // 如果点可以加入
					//maze[new_point.row][new_point.col] = temp_point.step + 1; //[x]TODO: 随意修改成员变量不是好习惯 - > 新编量记录走过的地方
					num_ = get_range(new_point.row, new_point.col);
					range_map[new_point.row][new_point.col] = num_;
					mark[new_point.row][new_point.col] = temp_point;// 放入父节点
					passed[new_point.row][new_point.col] = temp_point.step + 1;
					vecPath.push(new_point);
					if (num_ > max_num) {
						maxi = new_point.row;
						maxj = new_point.col;
						max_num = num_;
					}
				}
			}
			vecPath.pop();
			//if (flag == 1) break;
			i++;
		}
		// 找到最大的点
		cout << max_num << endl;
		return;
	}
};  //[TODO] warning :警告	C26495	未初始化变量 Pos_find::mark。始终初始化成员变量(type.6)。	 	238  解决加 Point ** mark = 0;
 
int main()
{
	// 

	Pos_find map_;
	Point start_pt = Point(1, 3), end_pt = Point(4,4);

	//map_.mazePath(start_pt, end_pt);

	//  任务二
	// 修改地图
	map_.string2char(map2);
	map_.mazePath(start_pt);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值