实现 iOS 上的井字游戏

分享到:

实现 iOS 上的井字游戏

实现 iOS 上的井字游戏

简介

本文介绍如何用 MVC 模式在 iOS 上实现双人对战的井字游戏. 读者最好有一些 iOS 编程基础, 以便更好的理解本文的代码. 希望这篇文章对提高读者的 iOS 和 MVC 编程水平有所帮助.

背景

井字游戏

关于游戏的规则我就不多说了, 相信大家都知道怎么玩. (如果不清楚游戏规则, 请点 这里). 下面要介绍的是人和人对战的井字游戏, 至于人机对战不属于本文讨论的范围.

MVC 模式

MVC 是 iOS 开发中常用的一种设计模式. MVC 把应用程序中的对象分成三类:

  • Model: 只负责程序中的数据部分, 与用户界面无关.

  • View: 负责程序界面的显示和用户交互部分.

  • Controller: 是连接 Model 和 View 的一条纽带. 比如, 它把用户输入的数据传给 Model, 或者把 Model 的数据传给 View. 

我们的游戏将使用 MVC 模式来实现. 下面的图片是 MVC 各部分之间的关系:

 

实现 iOS 上的井字游戏

MVC 的更多内容请点 这里.

实现

Model

我们已经讲过, Model 对象与用户界面无关.  游戏项目中, 有个类 (TTTicTacToe.m), 跟用户界面没有半毛钱关系, 纯粹是用来实现游戏逻辑, 保存游戏状态的. 比如:  棋盘 - 一个简单的 char 二维数组, 保存玩家每一步走法的函数, 判断有没有玩家胜出的函数等等. 而 View 则通过 UIButton 把游戏的状态显示出来.

数组跟按钮之间的映射

我们已经讲过, 游戏的状态保存在 Model 类的一个二维数组中. 而棋盘则用 UIButton 对象实现. 当 View 要在用户界面显示游戏状态的时候, 需要找个方法, 把二维数组跟 UIButton 对象关联起来. 由于 UIButton 对象通过 tag (也就是 ID) 访问, 我们从 1 到 16, 给它编个号. 然后再想办法跟数组关联起来就可以了.  Model 的二维数组看起来像酱紫:

实现 iOS 上的井字游戏

通过这个公式: buttonID = i*4 + j + 1, 就能把数组元素[i,j] 跟 UIButton 对象的 ID 关联起来. 比如: 数组元素[2,3]对应的是 ID(也叫tag) 为 12 的 UIButton 对象.

View Controller

下面, 我们讲下这个实现游戏逻辑的函数(包括用户界面). 当用户按下某个按钮(UIButton 对象)时, 该函数就会被调用(我们把按钮的坐标当作参数传给它). 代码已经写了详细的注释, 我再简单说下. View 调用 Model 对象(self.game 是 TTTicTacToe.m 类的对象)保存玩家下棋的数据的.   然后调用 redrawTable 函数, 把 Model 中的游戏状态显示出来(这个函数后面再讲). 最后调用 self.game checkForWin 函数判断有没有玩家获胜.

-(void) userMoveX:(int)x andY:(int)y
{
    BoardCoord pos;
    pos.x = x;
    pos.y = y;
    
    //由 x 和 y 坐标推算出按钮的 ID.
    int buttonID = 4 * y + x + 1;
    
    // 玩家最多走 16 步棋.
    if(self.counter > 15)
        return;
    
    // 保存玩家下棋的状态.
    [self.game updateBoardAtPos:pos withPlayer:((self.counter) % 2)];
    
    // 更新用户界面
    [self redrawTable];
    
    // 判断有没有玩家胜出?
    if([self.game checkForWin:pos])
    {
        if((self.counter % 2) == 0)
        {
            NSLog(@"Win X");
            self.status.text = @"Player X wins!";
        }
        else
        {
            self.status.text = @"Player O wins!";
            NSLog(@"Win O");
        }
        
        // 如果其中一个玩家获胜, 游戏结束
        // 禁用所有按钮(Disabled)
        for(int i=1; i<=16; i++)
        {
            //通过 tag 获取按钮对象
            UIButton *b = (UIButton*)[self.view viewWithTag:i];
            // 禁用按钮
            b.enabled = NO;
        }        
    }
    
    // 玩家当前点到的按钮也要禁用
    UIButton *b = (UIButton*)[self.view viewWithTag:buttonID];
    b.enabled = NO;
    // counter 增 1
    self.counter++;
}

注意: (self.counter) % 2 这行代码中, self.counter 表示玩家总共已经下了几步棋. 对 2 求余, 结果是 0 表示玩家 X, 1 表示玩家 O . 

最后就剩下这个用按钮显示棋盘的函数了:

-(void) redrawTable
{
    for(int i=0; i < SIZE; i++)
        for(int j=0; j < SIZE; j++)
        {
            // 获取按钮的 handle
            UIButton*b = (UIButton*) [self.view viewWithTag:(i*4+j+1)];
            
            UIImage *btnImage;
            if([self.game objectAtX:j andY:i] == 'X')
            {
                 // 设为 X 图标
                 btnImage = [UIImage imageNamed:@"xIcon.png"];
            }else
            {
                if([self.game objectAtX:j andY:i] == 'O')
                {
                    // 设为 O 图标
                    btnImage = [UIImage imageNamed:@"oIcon.png"];
                }
            }
        
            // 在按钮上面显示图标
            // 如果 btnImage 为 nil, 则不用显示
            [b setImage:btnImage forState:UIControlStateNormal];
        } 
}

历史

  •  Version 1.00 - Initial release

本文地址:http://www.oschina.net/translate/implementing-tic-tac-toe-on-ios

原文地址:http://www.codeproject.com/Tips/839837/Implementing-Tic-Tac-Toe-on-iOS

昵    称:
验证码:

相关文档: