以前做的小游戲阔涉,很多地方不足也不做修改了,比較有趣捷绒,用到了一點(diǎn)算法瑰排,所以摘過來放在這兒
- GitHub地址:https://github.com/rayonCheng/PushTheBox_-.git
推箱子.png
- 和炸彈人游戲原理差不多,這個(gè)是在它之前寫的暖侨,圖上有游戲規(guī)則
- 重點(diǎn)分析:根據(jù)深度優(yōu)先搜索算法椭住,得出人能否移動到指定的目標(biāo)點(diǎn)(可以找出最優(yōu)的路線,但無法有序的顯示出來故刪掉了)
下面展示全部代碼和部分注解
ViewController.m文件中
#define rowCount 10
// 每一行個(gè)數(shù)@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@property(nonatomic,strong)UICollectionView *collectView;
@property(nonatomic,strong)NSMutableArray *dataArray;
@property(nonatomic)CGPoint point;// 箱子所在的坐標(biāo)位置
@property(nonatomic)CGPoint personPoint;// 人所在的坐標(biāo)位置
@property(nonatomic)CGPoint endPoint; // 出口
@property(nonatomic)CGPoint startPoint; // 入口
@property(nonatomic,strong)NSMutableArray *allArray;// 記錄人經(jīng)過的路線所有信息@property(nonatomic)NSInteger success; // 判斷人是否走到了正確的路線上@end
ViewController.m文件中
@implementation ViewController
static NSString *const cellId = @"cellId";// collectView注冊時(shí)的標(biāo)識符
- (void)viewDidLoad {
[super viewDidLoad]
// Do any additional setup after loading the view, typically from a nib.
[self layoutCollectionView]; // 游戲規(guī)則注釋
UILabel *explainLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, [UIScreen mainScreen].bounds.size.height - 150, [UIScreen mainScreen].bounds.size.width - 40, 100)];
explainLabel.text = @"箱子推動的規(guī)則:\n點(diǎn)擊非墻非箱子的地方字逗,如果人可以移動過去則移動京郑;點(diǎn)擊箱子宅广,如果人在箱子四周的一位距離則把箱子向人的相反方向推去(那個(gè)方向非墻),人跟著移動一步些举,人和箱子距離在1位以上則沒法進(jìn)行";
explainLabel.numberOfLines = 0; [explainLabel setFont:[UIFont systemFontOfSize:12]];
[self.view addSubview:explainLabel];
[self.view bringSubviewToFront:explainLabel]; // 箱子起始坐標(biāo) {1跟狱,2},人的起始坐標(biāo){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 ) {
// // 避免連續(xù)點(diǎn)擊兩次刷新按鈕
// [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏?/ }
// if (_point.x != _startPoint.x + 1 || _point.y != _startPoint.y){
// // 箱子有移動
// [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x withObject:@0];// 箱子曾經(jīng)的位置// }//
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x withObject:@1];// 人現(xiàn)在的位置
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1 withObject:@3];// 箱子現(xiàn)在的位置
//PS:開始想的太復(fù)雜導(dǎo)致思路錯(cuò)了走歪了,但邏輯還是經(jīng)得起推敲的
self.dataArray = nil;// so easy
_point = CGPointMake(_startPoint.x + 1, _startPoint.y);
_personPoint = _startPoint;// 任何箱子的點(diǎn)重新賦值
[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];// 重用機(jī)制幢码,上面別忘了注冊
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;
}
/* 箱子推動的規(guī)則: 點(diǎn)擊非墻非箱子的地方笤休,如果人可以移動過去則移動; 點(diǎn)擊箱子症副,如果人在箱子四周的一位距離則把箱子向人的相反方向推去(那個(gè)方向非墻)店雅,人跟著移動一步,人和箱子距離在1位以上則沒法進(jìn)行 */
- (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) { // 點(diǎn)擊了箱子
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];// 人現(xiàn)在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1 withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏? [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1 withObject:@3];// 箱子現(xiàn)在的位置
[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];// 人現(xiàn)在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1 withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏? [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1 withObject:@3];// 箱子現(xiàn)在的位置
[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];// 人現(xiàn)在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10 withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏? [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10 withObject:@3];// 箱子現(xiàn)在的位置
[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];// 人現(xiàn)在的位置
[_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10 withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏? [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10 withObject:@3];// 箱子現(xiàn)在的位置
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]];
}
}else if (_personPoint.x == indexPath.row && _personPoint.y == indexPath.section){ // 點(diǎn)了人自身窍奋,不做任何變化
}else if (
![_dataArray[(indexPath.section) * rowCount + indexPath.row] isEqualToNumber:@2]) { // 點(diǎn)擊的地方不是墻且能夠有路線達(dá)到那兒(不一定是最優(yōu)方案--暫時(shí)先這樣)
[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];// 人曾經(jīng)的位置變?yōu)榭盏?
}
}];
NSInteger inter = indexPath.section * 10 + indexPath.row;
[_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人現(xiàn)在的位置
self.personPoint = CGPointMake(indexPath.row, indexPath.section);
[self.collectView reloadItemsAtIndexPaths:@[indexPath,path]];
}
}
if (_point.x == _endPoint.x && _point.y == _endPoint.y) { NSLog(@"過關(guān)啦");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜" message:@"過關(guān)了" preferredStyle:(UIAlertControllerStyleAlert)];// 比alertView好用且齊全
UIAlertAction *action = [UIAlertAction actionWithTitle:@"確定" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x withObject:@1];// 人現(xiàn)在的位置
// [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x withObject:@0];// 人曾經(jīng)的位置變?yōu)榭盏?// [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1 withObject:@3];// 箱子現(xiàn)在的位置
// [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x withObject:@0];// 箱子曾經(jīng)的位置// 和重新按鈕 那一塊同理
self.dataArray = nil;
_point = CGPointMake(1, 2);
_personPoint = CGPointMake(0, 2);
[self.collectView reloadData];
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
}
}// 輸入起始點(diǎn)和結(jié)束點(diǎn),判斷這兩點(diǎn)在地圖內(nèi)有沒有連通的路線酱畅?有幾條琳袄?
// 詳解可看上一篇文章(炸彈人游戲),只是將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]) {
// // 記錄走過的每一個(gè)點(diǎn)
// [self.allArray addObject:
[NSNumber numberWithInt:i]];// //
}//
}
} // 上下左右四個(gè)方向是否能移動
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;
}
此工程先于炸彈人編寫纺酸,邏輯不如其嚴(yán)謹(jǐn)窖逗,可兩者結(jié)合比較,更好的理解
- PS:文章排版有問題餐蔬,以前是富文本格式碎紊,現(xiàn)在轉(zhuǎn)換為markdown格式,改的頭疼