以前做的小游戏,很多地方不足也不做修改了,比较有趣,用到了一点算法,所以摘过来放在这儿
- GitHub地址:https://github.com/rayonCheng/PushTheBox_-.git
- 和炸弹人游戏原理差不多,这个是在它之前写的,图上有游戏规则
- 重点分析:根据深度优先搜索算法,得出人能否移动到指定的目标点(可以找出最优的路线,但无法有序的显示出来故删掉了)
下面展示全部代码和部分注解
ViewController.m文件中
#define rowCount 10
// 每一行个数@interface ViewController ()
@property(nonatomic,strong)UICollectionView *collectView;
@property(nonatomic,strong)NSMutableArray *dataArray;
@property(nonatomic)CGPoint point;// 箱子所在的坐标位置
@property(nonatomic)CGPoint personPoint;// 人所在的坐标位置
@property(nonatomic)CGPoint endPoint; // 出口
@property(nonatomic)CGPoint startPoint; // 入口
@property(nonatomic,strong)NSMutableArray *allArray;// 记录人经过的路线所有信息@property(nonatomic)NSInteger success; // 判断人是否走到了正确的路线上@end
ViewController.m文件中
@implementation ViewController
static NSString *const cellId = @"cellId";// collectView注册时的标识符
- (void)viewDidLoad {
[super viewDidLoad]
// Do any additional setup after loading the view, typically from a nib.
[self layoutCollectionView]; // 游戏规则注释
UILabel *explainLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, [UIScreen mainScreen].bounds.size.height - 150, [UIScreen mainScreen].bounds.size.width - 40, 100)];
explainLabel.text = @"箱子推动的规则:\n点击非墙非箱子的地方,如果人可以移动过去则移动;点击箱子,如果人在箱子四周的一位距离则把箱子向人的相反方向推去(那个方向非墙),人跟着移动一步,人和箱子距离在1位以上则没法进行";
explainLabel.numberOfLines = 0; [explainLabel setFont:[UIFont systemFontOfSize:12]];
[self.view addSubview:explainLabel];
[self.view bringSubviewToFront:explainLabel]; // 箱子起始坐标 {1,2},人的起始坐标{0,2},出口是{9,7} // 墙占位符为2,空地为0,箱子为3,人为1
self.point = CGPointMake(1, 2);
self.personPoint = CGPointMake(0, 2);
self.startPoint = CGPointMake(0, 2);
self.endPoint = CGPointMake(9, 7);} // 重新开始
- (IBAction)refreshBtn:(id)sender {// 拉控件
// if (_personPoint.x != _startPoint.x || _personPoint.y != _startPoint.y ) {
// // 避免连续点击两次刷新按钮
// [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x withObject:@0];// 人曾经的位置变为空地// }
// if (_point.x != _startPoint.x + 1 || _point.y != _startPoint.y){
// // 箱子有移动
// [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x withObject:@0];// 箱子曾经的位置// }//
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x withObject:@1];// 人现在的位置
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1 withObject:@3];// 箱子现在的位置
//PS:开始想的太复杂导致思路错了走歪了,但逻辑还是经得起推敲的
self.dataArray = nil;// so easy
_point = CGPointMake(_startPoint.x + 1, _startPoint.y);
_personPoint = _startPoint;// 任何箱子的点重新赋值
[self.collectView reloadData];
}
- (void)layoutCollectionView{
if (!_collectView) {
CustomViewFlowLayout *layout = [[CustomViewFlowLayout alloc]init];
UICollectionView *collevtView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];
collevtView.backgroundColor = [UIColor whiteColor];
collevtView.delegate = self;
collevtView.dataSource = self;
[self.view addSubview:collevtView];
_collectView = collevtView;
[_collectView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellId];// collectView注册 }
}
// delegate和datasource方法
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
if (self.dataArray.count % rowCount == 0) {
return self.dataArray.count / rowCount;
}else
return self.dataArray.count / rowCount + 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return rowCount;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *collectCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];// 重用机制,上面别忘了注册
NSInteger inter = (indexPath.section) * rowCount + indexPath.row;
if ([self.dataArray[inter] isEqualToNumber:@2]) {
collectCell.backgroundColor = [UIColor blackColor];
}
if ([self.dataArray[inter] isEqualToNumber:@0]) {
collectCell.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
if (indexPath.row == self.point.x && indexPath.section == self.point.y) {
collectCell.backgroundColor = [UIColor redColor];
}// 代表箱子
if ([self.dataArray[inter] isEqualToNumber:@1]) {
collectCell.backgroundColor = [UIColor greenColor];
}// 代表人
return collectCell;
}
/* 箱子推动的规则: 点击非墙非箱子的地方,如果人可以移动过去则移动; 点击箱子,如果人在箱子四周的一位距离则把箱子向人的相反方向推去(那个方向非墙),人跟着移动一步,人和箱子距离在1位以上则没法进行 */
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSIndexPath *path = [NSIndexPath indexPathForRow:_personPoint.x inSection:_personPoint.y];
if (indexPath.row == self.point.x && indexPath.section == self.point.y) { // 点击了箱子
if (indexPath.row - 1 == self.personPoint.x && indexPath.section == self.personPoint.y && [_dataArray[indexPath.section * rowCount + indexPath.row + 1] isEqualToNumber:@0]) {
// 人在箱子左边一位,人和箱子向右移动一位
_personPoint = CGPointMake(indexPath.row, indexPath.section);
_point = CGPointMake(indexPath.row + 1, indexPath.section);
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1 withObject:@0];// 人曾经的位置变为空地
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1 withObject:@3];// 箱子现在的位置
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]];
}
if (indexPath.row + 1 == self.personPoint.x && indexPath.section == self.personPoint.y && [_dataArray[indexPath.section * rowCount + indexPath.row - 1] isEqualToNumber:@0]) { // 人在箱子右边一位,人和箱子向左移动一位
_personPoint = CGPointMake(indexPath.row, indexPath.section);
_point = CGPointMake(indexPath.row - 1, indexPath.section);
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1 withObject:@0];// 人曾经的位置变为空地
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1 withObject:@3];// 箱子现在的位置
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]];
}
if (indexPath.row == self.personPoint.x && indexPath.section - 1 == self.personPoint.y && [_dataArray[(indexPath.section + 1) * rowCount + indexPath.row] isEqualToNumber:@0]) { // 人在箱子上边一位,人和箱子向下移动一位
_personPoint = CGPointMake(indexPath.row, indexPath.section);
_point = CGPointMake(indexPath.row , indexPath.section + 1);
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10 withObject:@0];// 人曾经的位置变为空地
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10 withObject:@3];// 箱子现在的位置
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]]; }
if (indexPath.row == self.personPoint.x && indexPath.section + 1 == self.personPoint.y && [_dataArray[(indexPath.section - 1) * rowCount + indexPath.row] isEqualToNumber:@0]) { // 人在箱子下边一位,人和箱子向上移动一位
_personPoint = CGPointMake(indexPath.row, indexPath.section);
_point = CGPointMake(indexPath.row, indexPath.section - 1);
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10 withObject:@0];// 人曾经的位置变为空地
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10 withObject:@3];// 箱子现在的位置
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]];
}
}else if (_personPoint.x == indexPath.row && _personPoint.y == indexPath.section){ // 点了人自身,不做任何变化
}else if (
![_dataArray[(indexPath.section) * rowCount + indexPath.row] isEqualToNumber:@2]) { // 点击的地方不是墙且能够有路线达到那儿(不一定是最优方案--暂时先这样)
[self.allArray removeAllObjects];
self.success = 0;
NSInteger success = [self judgeTwoPointRouteWithStartPiontX:(NSInteger)_personPoint.x y:(NSInteger)_personPoint.y endPointX:(indexPath.row) y:(indexPath.section)];
if (success == 1) {
[self.dataArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isEqualToNumber:@1]) {
// [self.allArray addObject:obj];
// NSIndexPath *path1 = [NSIndexPath indexPathForRow:( idx / rowCount) inSection:(idx % rowCount) ];
// NSLog(@"= %@",obj);
// [self.collectView reloadItemsAtIndexPaths:@[path1]];
[_dataArray replaceObjectAtIndex: (NSUInteger)idx withObject:@0];// 人曾经的位置变为空地
}
}];
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
self.personPoint = CGPointMake(indexPath.row, indexPath.section);
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path]];
}
}
if (_point.x == _endPoint.x && _point.y == _endPoint.y) { NSLog(@"过关啦");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜" message:@"过关了" preferredStyle:(UIAlertControllerStyleAlert)];// 比alertView好用且齐全
UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x withObject:@1];// 人现在的位置
// [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x withObject:@0];// 人曾经的位置变为空地
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1 withObject:@3];// 箱子现在的位置
// [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x withObject:@0];// 箱子曾经的位置// 和重新按钮 那一块同理
self.dataArray = nil;
_point = CGPointMake(1, 2);
_personPoint = CGPointMake(0, 2);
[self.collectView reloadData];
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
}
}// 输入起始点和结束点,判断这两点在地图内有没有连通的路线?有几条?
// 详解可看上一篇文章(炸弹人游戏),只是将BOOL值替换成了nsinteger- (NSInteger )judgeTwoPointRouteWithStartPiontX:(NSInteger)startX y:(NSInteger)startY endPointX:(NSInteger)endX y:(NSInteger)endY{ NSInteger inter = startY * rowCount + startX;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人走过的路线
if (startX == endX && startY == endY) {
self.success = 1;
// for (int i = 0; i < _dataArray.count; i ++) {
// if ([_dataArray[i] isEqualToNumber:@1]) {
// // 记录走过的每一个点
// [self.allArray addObject:
[NSNumber numberWithInt:i]];// //
}//
}
} // 上下左右四个方向是否能移动
if (_success != 1 && [_dataArray[startX + (startY - 1) * rowCount] isEqualToNumber:@0]) {
[self judgeTwoPointRouteWithStartPiontX:startX y:(startY - 1) endPointX:endX y:endY];
}
if (_success != 1 && [_dataArray[startX + (startY + 1) * rowCount] isEqualToNumber:@0]) {
[self judgeTwoPointRouteWithStartPiontX:startX y:(startY + 1) endPointX:endX y:endY];
}
if (_success != 1 && [_dataArray[startX - 1 + (startY ) * rowCount] isEqualToNumber:@0]) {
[self judgeTwoPointRouteWithStartPiontX:(startX - 1) y:(startY) endPointX:endX y:endY];
}
if (_success != 1 && [_dataArray[startX + 1 + (startY ) * rowCount] isEqualToNumber:@0]) {
[self judgeTwoPointRouteWithStartPiontX:(startX + 1) y:(startY) endPointX:endX y:endY];
}
if (_success != 1) {
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@0];
}
return _success;}
#pragram mark ----getter
- (NSMutableArray *)dataArray{
if (!_dataArray) {
_dataArray = [NSMutableArray arrayWithArray:@[@2,@2,@2,@2,@2,@2,@2,@2,@2,@2, @2,@0,@0,@0,@0,@0,@0,@0,@0,@2, @1,@3,@0,@2,@2,@0,@2,@2,@0,@2, @2,@0,@0,@2,@0,@0,@2,@0,@0,@2,@2,@0,@0,@2,@0,@2,@0,@2,@0,@2,@2,@0,@0,@0,@0,@0,@0,@2,@0,@2,@2,@0,@0,@2,@2,@2,@0,@2,@2,@2,@2,@0,@0,@0,@0,@0,@0,@0,@0,@0,@2,@2,@2,@2,@2,@2,@2,@2,@2,@2] ];
}
return _dataArray;
}
- (NSMutableArray *)allArray{
if (!_allArray) {
_allArray = [NSMutableArray arrayWithCapacity:20];
}
return _allArray;
}
此工程先于炸弹人编写,逻辑不如其严谨,可两者结合比较,更好的理解
- PS:文章排版有问题,以前是富文本格式,现在转换为markdown格式,改的头疼