推箱子小游戏

以前做的小游戏,很多地方不足也不做修改了,比较有趣,用到了一点算法,所以摘过来放在这儿

  • 和炸弹人游戏原理差不多,这个是在它之前写的,图上有游戏规则
  • 重点分析:根据深度优先搜索算法,得出人能否移动到指定的目标点(可以找出最优的路线,但无法有序的显示出来故删掉了)

下面展示全部代码和部分注解

ViewController.m文件中

#define rowCount 10 
// 每一行个数@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>

@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格式,改的头疼
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容