上一篇博客咱們介紹了在開發一款藍牙對戰五子棋遊戲中核心的藍牙通信框架的設計與編寫,本篇博客未來完成獨立的棋盤邏輯與勝負斷定算法。上篇博客地址以下: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