上一篇博客咱们介绍了在开发一款蓝牙对战五子棋游戏中核心的蓝牙通信框架的设计与编写,本篇博客未来完成独立的棋盘逻辑与胜负断定算法。上篇博客地址以下:git
五子棋游戏中和核心通信类设计:http://my.oschina.net/u/2340880/blog/644432。github
咱们知道,五子棋游戏的棋盘是由横纵交叉的两组平行线组成,每个横纵线的交点便是棋盘上能够落子的点。所以,在设计棋盘前,咱们能够先来设计建立棋盘上每个独立的落子点,这里称之为棋格,在iOS中,可使用UIButton类来进行棋格的设计。算法
建立一个类,命名为TipButton做为棋格类,实现其头文件以下:框架
TipButton.hide
#import <UIKit/UIKit.h> @interface TipButton : UIButton //标记此瓦片是否已经落子 0 空 1 己方落子 2 敌方落子 @property(nonatomic,assign)int hasChess; //落子 BOOL类型的参数 决定是己方仍是敌方 -(void)dropChess:(BOOL)isMine; //设置白子或者黑子 @property(nonatomic,assign)BOOL isWhite; //瓦片编号 @property(nonatomic,assign)int index; @end
实现.m文件以下:布局
#import "TipButton.h" @implementation TipButton - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self creatView]; } return self; } -(void)creatView{ //建立横竖两条线 UIView * line1 = [[UIView alloc]initWithFrame:CGRectMake(self.frame.size.width/2-0.25, 0, 0.5, self.frame.size.height)]; line1.backgroundColor = [UIColor grayColor]; [self addSubview:line1]; UIView * line2 = [[UIView alloc]initWithFrame:CGRectMake(0, self.frame.size.height/2-0.25, self.frame.size.width, 0.5)]; line2.backgroundColor = [UIColor grayColor]; [self addSubview:line2]; } -(void)dropChess:(BOOL)isMine{ UIView * view = [[UIView alloc]initWithFrame:CGRectMake(self.frame.size.width/2-5, self.frame.size.height/2-5, 10, 10)]; view.layer.masksToBounds = YES; view.layer.cornerRadius = 5; UIColor * myColor; UIColor * otherColor; if (_isWhite) { myColor = [UIColor whiteColor]; otherColor = [UIColor blackColor]; }else{ myColor = [UIColor blackColor]; otherColor = [UIColor whiteColor]; } if (isMine) { view.backgroundColor = myColor; self.hasChess = 1; }else{ view.backgroundColor = otherColor; self.hasChess = 2; } [self addSubview:view]; } @end
建立一个继承于UIView的类,做为五子棋游戏的棋盘,命名为GameView实现以下:atom
GameView.hspa
#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.net
#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
游戏运行的主要界面以下图所示:
附录:游戏的源码已经放在git上,时间比较仓促,只用了一下午来写,其中还有许多细节与bug没有进行调整,有须要的能够做为参考:
git地址:https://github.com/ZYHshao/BlueGame。
专一技术,热爱生活,交流技术,也作朋友。
——珲少 QQ群:203317592