Gomoku五子棋OC实现

最近有朋友在学习UI,想制作一个简单的五子棋来练手,但不知道思路,我就写了一个五子棋来作为引导吧。

提到五子棋,首先就是得考虑到一个棋盘的问题,由于朋友是初学UI,所以在棋盘布局上就是用了view的方法创建了棋盘,tableView等方法应该会更好一些,感兴趣的朋友可以去学习学习相关知识。五子棋是15 x 15的布局,代码实现如下

for (int i = 0; i < 15; i++) {
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(45, 100 + i * 20, 280, 1)];
        view.backgroundColor = [UIColor blackColor];
        [self.view addSubview:view];
        [view release];
        for (int j = 0; j < 15; j++) {
            UIView *view = [[UIView alloc] initWithFrame:CGRectMake(45 + j * 20, 100, 1, 280)];
            view.backgroundColor = [UIColor blackColor];
            [self.view addSubview:view];
            [view release];
        }
    }

 实际效果如图

*棋盘笑过去*

有了棋盘之后就是落子的问题,实际上,本程序采用的并不是真正意义上得“落子”,而是在每个可以落子的点预设了没有初始化颜色的button,通过button点击事件来改变button的颜色,达到实际落子的效果,预设棋子代码如下

//    预设棋子
    for (int i = 0 ; i < 15; i++) {
        for (int j = 0; j < 15; j++) {
            UIButton *chess = [UIButton buttonWithType:UIButtonTypeSystem];
            chess.frame = CGRectMake(45 + 20 * j, 100 + 20 * i, 18, 18);
            chess.center = CGPointMake(45 + 20 * j, 100 + 20 * i);
            chess.layer.cornerRadius = 9;
            chess.layer.masksToBounds = YES;
            [chess addTarget:self action:@selector(playChess:) forControlEvents:UIControlEventTouchUpInside];
            [self.view addSubview:chess];
            [chess release];
            
            [_dataSource addObject:@"empty"];
        }
    }
该程序没有使用自定义视图,但是吧每个棋子需要有自己的属性,也就是“没被点击empty”, “黑子black”, 和“白子white”, 这些属性我通过创建一个可变数组_dataSource的属性来存储,方便管理。同时,五子棋还需判断当前回合是黑子还是白子的回合,我定义了一个flag属性来标记回合。基本逻辑是当点击某个落子点的时候,如果该落子点有白子,则该落子点为“white”, 如果为黑子,则为“black”,如果没有子,则为“empty”, 说明该处可以放置棋子 ,根据放置棋子的颜色,向用于存储棋盘棋子信息的可变数组_dataSource传值,代码实现如下
if (_flag) {
            sender.backgroundColor = [UIColor blackColor];
            [_dataSource replaceObjectAtIndex:(15 * y + x) withObject:@"black"];
            _labelTurn.text = @"white turn";
        } else {
            sender.backgroundColor = [UIColor whiteColor];
            [_dataSource replaceObjectAtIndex:(15 * y + x) withObject:@"white"];
            _labelTurn.text = @"black turn";
        }
        _flag = !_flag;
至此,基本的棋盘和落子功能已经实现了,现在需要判断的是赢得比赛的逻辑。一个比较通行的方法是每次落子完成后对这个数组横向,纵向,斜向四个方向分别遍历,找到至少五个值相同的即为获胜,返回数组内存储的值即可。在这里,每次落子都遍历数组效率太低,考虑每次落子对该子周围的棋子进行遍历,提高程序效率,代码如下
//        向右
        int xRight = x + 1;
        int yRight = y;
        int countRight = 0;
        while ([_dataSource[15 * yRight + xRight] isEqualToString:_dataSource[15 * y + x]]) {
            countRight++;
            xRight++;
            if (xRight >= 15) {
                break;
            }
        }
        
//        左上
        int xLeftUp = x - 1;
        int yLeftUp = y - 1;
        int countLeftUp = 0;
        while ([_dataSource[15 * yLeftUp + xLeftUp] isEqualToString:_dataSource[15 * y + x]]) {
            countLeftUp++;
            xLeftUp--;
            yLeftUp--;
            if (xLeftUp < 0 || yLeftUp < 0) {
                break;
            }
        }
        
//        右下
        int xRightDown = x + 1;
        int yRightDown = y + 1;
        int countRightDown = 0;
        while ([_dataSource[15 * yRightDown + xRightDown] isEqualToString:_dataSource[15 * y + x]]) {
            countRightDown++;
            xRightDown++;
            yRightDown++;
            if (xRightDown >= 15 || yRightDown >= 15) {
                break;
            }
        }
        
//        右上
        int xRightUp = x + 1;
        int yRightUp = y - 1;
        int countRightUp = 0;
        while ([_dataSource[15 * yRightUp + xRightUp] isEqualToString:_dataSource[15 * y + x]]) {
            countRightUp++;
            xRightUp++;
            yRightUp--;
            if (xRightUp >= 15 || yRightUp < 0) {
                break;
            }
        }
        
//        左下
        int xLeftDown = x - 1;
        int yLeftDown = y + 1;
        int countLeftDown = 0;
        while ([_dataSource[15 * yLeftDown + xLeftDown] isEqualToString:_dataSource[15 * y + x]]) {
            countLeftDown++;
            xLeftDown--;
            yLeftDown++;
            if (xLeftDown < 0 || yLeftDown >= 15) {
                break;
            }
        }

//        判断输赢
        if ((countUp + countDown >= 4) || (countLeft + countRight >= 4) || (countLeftDown + countRightUp >= 4) || (countRightDown + countLeftUp >= 4)) {
            NSLog(@"%@ win", _dataSource[15 * y + x]);
            _labelWin.text = [_dataSource[15 * y + x] stringByAppendingString:@" win"];
当然,可以考虑使用递归来获取count,有兴趣的朋友可以自己尝试。

至此,游戏的判断功能也有了,但是在一方获胜之后程序依旧能够继续执行,需要对游戏结束做一个控制,这里用的是将所有棋子信息都改成了获胜子的信息,代码如下

//            游戏结束后不再能够落子
            for (int i = 0; i < 225; i++) {
                [_dataSource replaceObjectAtIndex:i withObject:_labelWin.text];
            }


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值