iOS简易蓝牙对战五子棋游戏设计思路之二——核心棋盘逻辑与胜负判定算法(二)

简介: iOS简易蓝牙对战五子棋游戏设计思路之二——核心棋盘逻辑与胜负判定算法

三、游戏棋盘的设计


   创建一个继承于UIView的类,作为五子棋游戏的棋盘,命名为GameView实现如下:


GameView.h


#import <UIKit/UIKit.h>

#import "TipButton.h"

#import "BlueToothTool.h"

//用于处理用户下子后的逻辑

@protocol GameViewDelegate<NSObject>

-(void)gameViewClick:(NSString *)index;

@end

@interface GameView : UIView<UIAlertViewDelegate>

//存放所有棋格

@property(nonatomic,strong)NSMutableArray<TipButton *> * tipArray;

@property(nonatomic,weak)id<GameViewDelegate>delegate;

//进行下子

-(void)setTipIndex:(int)index;

@end

GameView.m


#import "GameView.h"

@implementation GameView

- (instancetype)initWithFrame:(CGRect)frame

{

   self = [super initWithFrame:frame];

   if (self) {

       _tipArray = [[NSMutableArray alloc]init];

       [self creatView];

   }

   return self;

}

//创建表格视图 横16 竖20

-(void)creatView{

   self.layer.borderColor = [UIColor colorWithRed:222/255.0 green:222/255.0 blue:222/255.0 alpha:1].CGColor;

   self.layer.borderWidth = 0.5;

   CGFloat width = self.frame.size.width/12;

   CGFloat height = self.frame.size.height/20;

   //排列布局

   for (int i=0; i<240; i++) {

       TipButton * btn = [[TipButton alloc]initWithFrame:CGRectMake(width*(i%12), height*(i/12), width, height)];

       [btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];

       btn.isWhite = NO;

       btn.index=i;

       [self addSubview:btn];

       [_tipArray addObject:btn];

   }

}

-(void)click:(TipButton *)btn{

   if (btn.hasChess==0) {

       //下子

       [btn dropChess:YES];

       //进行胜负判定

       [self cheak];

       [self.delegate gameViewClick:[NSString stringWithFormat:@"%d",btn.index]];

   }

}

//进行胜负判定

-(void)cheak{

   //判定己方是否胜利

   if ([self cheakMine]) {

       UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"您胜利啦" message:@"" delegate:self cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];

       [alert show];

   }

   //判断对方是否胜利

   if ([self cheakOther]) {

       UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"您失败了" message:@"" delegate:self cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];

       [alert show];

   }

}

-(void)setTipIndex:(int)index{

   //下子

   for (TipButton * btn in _tipArray) {

       if (btn.index==index) {

           [btn dropChess:NO];

           [self cheak];

       }

   }

}

-(BOOL)cheakOther{

   //遍历所有棋子

   for (int i=0; i<_tipArray.count; i++) {

       TipButton * tip = _tipArray[i];

       //获取是否是己方棋子

       if (tip.hasChess==2) {

           //进行五子判定逻辑

           //横向

           if ( [self cheak1HasMineOrOther:NO index:i]) {

               return YES;

           }

           //左上到右下的对角线

           if ( [self cheak2HasMineOrOther:NO index:i]) {

               return YES;

           }

           //纵向

           if ( [self cheak3HasMineOrOther:NO index:i]) {

               return YES;

           }

           //右上到左下的对角线

           if ( [self cheak4HasMineOrOther:NO index:i]) {

               return YES;

           }

       }

   }

   return NO;


}


-(BOOL)cheakMine{

   //遍历所有棋子

   for (int i=0; i<_tipArray.count; i++) {

       TipButton * tip = _tipArray[i];

       //获取是否是己方棋子

       if (tip.hasChess==1) {

           //进行五子判定逻辑

           //横向

           if ( [self cheak1HasMineOrOther:YES index:i]) {

               return YES;

           }

           //左上到右下的对角线

           if ( [self cheak2HasMineOrOther:YES index:i]) {

               return YES;

           }

           //纵向

           if ( [self cheak3HasMineOrOther:YES index:i]) {

               return YES;

           }

           //右上到左下的对角线

           if ( [self cheak4HasMineOrOther:YES index:i]) {

               return YES;

           }

       }

   }

   return NO;

}



-(BOOL)cheak1HasMineOrOther:(BOOL)mine index:(int)index{

   int mineOrOther = 0;

   if (mine) {

       mineOrOther = 1;

   }else{

       mineOrOther = 2;

   }

   int count=1;

   //左侧右侧同时进行可以增加效率

   //左侧

   count = count +[self algorithmic1:index param:mineOrOther num:4];

   //右侧

   count = count +[self algorithmic2:index param:mineOrOther num:4];

   if (count>=5) {

       return YES;

   }else{

       return NO;

   }

}


-(BOOL)cheak2HasMineOrOther:(BOOL)mine index:(int)index{

   int mineOrOther = 0;

   if (mine) {

       mineOrOther = 1;

   }else{

       mineOrOther = 2;

   }

   int count=1;

   //左上右下同时进行可以增加效率

   //左上

   count = count +[self algorithmic3:index param:mineOrOther num:4];

   //右下

   count = count +[self algorithmic4:index param:mineOrOther num:4];

   if (count>=5) {

       return YES;

   }else{

       return NO;

   }

}


-(BOOL)cheak3HasMineOrOther:(BOOL)mine index:(int)index{

   int mineOrOther = 0;

   if (mine) {

       mineOrOther = 1;

   }else{

       mineOrOther = 2;

   }

   int count=1;

   //纵向

   //向上

   count = count +[self algorithmic5:index param:mineOrOther num:4];

   //向下

   count = count +[self algorithmic6:index param:mineOrOther num:4];

   if (count>=5) {

       return YES;

   }else{

       return NO;

   }

}

-(BOOL)cheak4HasMineOrOther:(BOOL)mine index:(int)index{

   int mineOrOther = 0;

   if (mine) {

       mineOrOther = 1;

   }else{

       mineOrOther = 2;

   }

   int count=1;

   //纵向

   //向上

   count = count +[self algorithmic7:index param:mineOrOther num:4];

   //向下

   count = count +[self algorithmic8:index param:mineOrOther num:4];

 

   NSLog(@"%d",count);

   if (count>=5) {

       return YES;

   }else{

       return NO;

   }

}


/*

左侧递归进行查找 index 棋子编号 param 对比值 num 递归次数

*/

-(int)algorithmic1:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

           //左侧有子

       if (index-tem>=0) {

           //左侧无换行

           if(((index-tem)%12)!=11){

               if (_tipArray[index-tem].hasChess==param) {

                  return  [self algorithmic1:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}

/*

右侧递归进行查找 index 棋子编号 param 对比值 num 递归次数

*/

-(int)algorithmic2:(int)index param:(int)param num:(int)num{

 

   if (num>0) {

       int tem = 4-(num-1);

       //右侧有子

       if (index+tem<240) {

           //右侧无换行

           if(((index+tem)%12)!=11){

               if (_tipArray[index+tem].hasChess==param) {

                   return  [self algorithmic2:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}


/*

左上递归进行查找 index 棋子编号 param 对比值 num 递归次数

*/

-(int)algorithmic3:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //左上有子

       if ((index-(tem*12)-tem)>=0) {

           //右侧无换行

           if(((index-(tem*12)-tem)%12)!=11){

               if (_tipArray[(index-(tem*12)-tem)].hasChess==param) {

                   return  [self algorithmic3:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}


-(int)algorithmic4:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //左上有子

       if ((index+(tem*12)+tem)<240) {

           //右侧无换行

           if(((index+(tem*12)+tem)%12)!=0){

               if (_tipArray[(index+(tem*12)+tem)].hasChess==param) {

                   return  [self algorithmic4:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}


-(int)algorithmic5:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //上有子

       if ((index-(tem*12))>=0) {

           if (_tipArray[(index-(tem*12))].hasChess==param) {

               return  [self algorithmic5:index param:param num:num-1];

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}


-(int)algorithmic6:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //上有子

       if ((index+(tem*12))<240) {

           if (_tipArray[(index+(tem*12))].hasChess==param) {

               return  [self algorithmic6:index param:param num:num-1];

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}

-(int)algorithmic7:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //左上有子

       if ((index-(tem*12)+tem)>=0) {

           //右侧无换行

           if(((index-(tem*12)+tem)%12)!=0){

               if (_tipArray[(index-(tem*12)+tem)].hasChess==param) {

                   return  [self algorithmic7:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}


-(int)algorithmic8:(int)index param:(int)param num:(int)num{

   if (num>0) {

       int tem = 4-(num-1);

       //左上有子

       if ((index+(tem*12)-tem)<240) {

           //右侧无换行

           if(((index+(tem*12)-tem)%12)!=11){

               if (_tipArray[(index+(tem*12)-tem)].hasChess==param) {

                   return  [self algorithmic8:index param:param num:num-1];

               }else{

                   return 4-num;

               }

           }else{

               return 4-num;

           }

       }else{

           return 4-num;

       }

   }else{

       //递归了四次

       return 4-num;

   }

}

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{

   [[BlueToothTool sharedManager]disConnect];

   [(UIViewController *)[self.superview nextResponder] dismissViewControllerAnimated:YES completion:nil];

}

@end

关于胜负判定的算法逻辑,这里采用了向各个方向进行递归查找的方式,这里有一点需要主要,在4个方向进行递归查找时,理论上每个方向只需要单面递归即可,但是代码中采用了双面递归在进行累加的方式,这样的设计可以遍历更少的棋子判定出胜负情况。


四、整合通讯与游戏逻辑


  创建一个继承于UIViewController的类作为游戏视图控制器,实现如下:


GameViewController.m


#import "GameViewController.h"

#import "GameView.h"

#import "BlueToothTool.h"

@interface GameViewController ()<BlueToothToolDelegate,GameViewDelegate>

{

   UIView * _bgView;

   UILabel * _tipLabel;

   GameView * _view;

}

@end


@implementation GameViewController


- (void)viewDidLoad {

   [super viewDidLoad];

   self.view.backgroundColor = [UIColor brownColor];

   //创建游戏视图

   _view = [[GameView alloc]initWithFrame:CGRectMake(20, 40, (self.view.frame.size.width-40), (self.view.frame.size.width-40)/12*20)];

   _view.delegate=self;

   [self.view addSubview:_view];

   //创建背景视图

   _bgView = [[UIView alloc]initWithFrame:self.view.frame];

   _bgView.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.1];

   UIButton * btn = [UIButton buttonWithType:UIButtonTypeSystem];

   btn.frame = CGRectMake(self.view.frame.size.width/2-50, 150, 100, 30);

   UIButton * btn2 = [UIButton buttonWithType:UIButtonTypeSystem];

   btn2.frame = CGRectMake(self.view.frame.size.width/2-50, 250, 100, 30);

   [btn setTitle:@"创建游戏" forState:UIControlStateNormal];

   [btn2 setTitle:@"扫描附近游戏" forState:UIControlStateNormal];

   btn.backgroundColor = [UIColor orangeColor];

   btn2.backgroundColor = [UIColor orangeColor];

   [btn addTarget:self action:@selector(creatGame) forControlEvents:UIControlEventTouchUpInside];

   [btn2 addTarget:self action:@selector(searchGame) forControlEvents:UIControlEventTouchUpInside];

   [_bgView addSubview:btn];

   [_bgView addSubview:btn2];

 

   [self.view addSubview:_bgView];

   //设置蓝牙通讯类代理

   [BlueToothTool sharedManager].delegate=self;

   //创建提示标签

   _tipLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,40)];

   [self.view addSubview:_tipLabel];

   _tipLabel.textAlignment = NSTextAlignmentCenter;

}

-(void)creatGame{

   [[BlueToothTool sharedManager]setUpGame:@"" block:^(BOOL first) {

       [_bgView removeFromSuperview];

       if (first) {

           _tipLabel.text = @"请您下子";

           //进行发送下子信息

       }else{

           _tipLabel.text = @"请等待对方下子";

           self.view.userInteractionEnabled = NO;

           [self gameViewClick:@"-1"];

       }

   }];

}

-(void)searchGame{

   [[BlueToothTool sharedManager]searchGame];

}

- (void)didReceiveMemoryWarning {

   [super didReceiveMemoryWarning];

   // Dispose of any resources that can be recreated.

}

-(void)getData:(NSString *)data{

   if (_bgView.superview) {

       [_bgView removeFromSuperview];

   }

   if ([data integerValue]==-1) {

       _tipLabel.text = @"请您下子";

        self.view.userInteractionEnabled = YES;

       return;

   }

   _tipLabel.text = @"请您下子";

   [_view setTipIndex:[data intValue]];

   self.view.userInteractionEnabled = YES;

}


-(void)gameViewClick:(NSString *)index{

   _tipLabel.text = @"请等待对方下子";

   [[BlueToothTool sharedManager]writeData:index];

   self.view.userInteractionEnabled = NO;

}

@end

游戏运行的主要界面如下图所示:


image.png







附录:游戏的源码已经放在git上,时间比较仓促,只用了一下午来写,其中还有许多细节与bug没有进行调整,有需要的可以作为参考:


git地址:https://github.com/ZYHshao/BlueGame

目录
相关文章
|
27天前
3秒的你对战“它”有没有胜算——quicksort
3秒的你对战“它”有没有胜算——quicksort
26 0
|
2天前
|
算法
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
|
3天前
|
算法 机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人
|
6天前
|
算法 数据挖掘 开发者
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】
|
6天前
|
SQL 算法 数据可视化
python 贪心算法 动态规划实现 跳跃游戏ll【力扣题45】
python 贪心算法 动态规划实现 跳跃游戏ll【力扣题45】
|
10天前
|
算法 JavaScript 前端开发
【经典算法】LCR187:破冰游戏(约瑟夫问题,Java/C/Python3/JavaScript实现含注释说明,Easy)
【经典算法】LCR187:破冰游戏(约瑟夫问题,Java/C/Python3/JavaScript实现含注释说明,Easy)
13 1
|
1月前
|
算法 定位技术 C语言
推箱子游戏(算法设计)
推箱子游戏(算法设计)
|
1月前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
41 0
|
1月前
|
算法 JavaScript 前端开发
游戏物理系统 - 如何在JavaScript中实现基本的碰撞检测算法?
在JavaScript中实现2D矩形碰撞检测,常用AABB方法,适合简单游戏。创建Rectangle类,包含位置和尺寸属性,并定义`collidesWith`方法检查两矩形是否相交。通过比较边界位置判断碰撞,当四条边界条件均满足时,认定发生碰撞。基础算法适用于初级需求,复杂场景可采用更高级的碰撞检测库。
22 1
|
1月前
|
人工智能 算法
【算法】深入理解 Prolog:逻辑编程的奇妙世界
【算法】深入理解 Prolog:逻辑编程的奇妙世界
45 0