首次参加齐鲁软件设计大赛经验(及总结出的划水要点)

17年,大一暑假首次参加齐鲁软件设计大赛(现名山东省大学生软件设计大赛),在大三师姐的怂恿下,号召了当时身边的“天赋少年”们踏上了一条价值300人民币的不归路。。。。


1. 人员物色(一个优秀的指挥者胜过三个优秀的程序员)

大赛小组人数区间3~5人,工作简单分配的话就是编码,美工和文档。小队五人也是按照这个规则进行的划分。但是问题很快就暴露出来了,作为小队队长的我,无论是项目设计经验还是工作安分配验都严重匮乏(我对项目的理解程度,只是在兴趣使然的情况下拜读了FrederickP.Brooks.Jr.《人月神话》),以至于在后续的工作中,我自己完全沦为了一名devops(开发,运维,测试于一体的职位),这直接导致了我整个暑假都在战战兢兢码代码的过程中度过。

介于我汗与泪的教训,在这里引入第一个公理:
一个优秀的指挥者胜过三个优秀的程序员(可以推广为程序员应该学会用架构的思维看待每一个项目(抱紧对的大腿等于成功一半)
指挥者只有对项目划分、前端设计、后台搭建、框架使用有了足够系统的学习,且对算法的理解达到一定深度,对一个项目的每一部分有一个大致的、关键的了解,才能在很短时间内将每项子任务精确到个人,于是即便他不参加到项目进程当中,工作也会有条不紊的开展起来。

2. 工具选择(“实际”-“最优”≡“浪费”)

在敲定作品主题是手机游戏之后,小组开始了漫长而又坎坷的摸索历程。
在最终的总结中我写到:

“我们挑选了两款当今使用较多的游戏设计特别是2D游戏设计领域的软件——cocos2D-x与unity3D。
由于许多人们耳熟能详的游戏都出自cocos之手,我们欣然优先选择了cocos。但后期的学习中,我们渐渐发现,cocos的设计较为死板,且可利用资源较少,同时由于网上搜寻到的资料是推荐在mac上运行的,这并不符合我们项目小组的设备现状。
于是我们转而选择了现今游戏开发走在前列的unity。Unity作为3D游戏设计的扛把子,在2D与3D游戏领域都有着受欢迎的代表作品,尽管unity涉足2D时间较晚,但是由于其3D投影2D的思路,使得它在2D游戏领域发展极快。
可视化界面,优秀的资源调配,游戏过程实时校验,以及项目最后的android导出,堪称一条龙服务。”
初见就惊艳到我的U3D

要在有限的时间内要创造出最高的价值,就意味着我们不应当浪费时间在许多无意义的工作中:
虽然对于问题的摸索是难能可贵的经历,但在严格规定deadline的竞赛中,摸索的代价却是最为珍贵的时间和人力,这是任何一个队伍都承受不起的。
所以,认清浪费的本质,尽可能避免错误的深入与摸索,急流勇退并非明哲保身,而是为了以退为进。

3. 决赛准备(万里挑一的灵魂亦需好看的皮囊包装)

软件设计大赛的得分点其实主要还是在创新。相较于程序大牛,我们的代码无论是整体性能还是结构美观都相差太多。能够打动评审的,是别出心裁的思路以及天马行空的想象。
这也意味着演示文档变成了很重要的一项工作,只有在演示过程中(无论视频还是PPT)都力争先声夺人,力求给评审留下好的第一印象。
这并不意味着只需要功利的只关注界面设计,好的用户体验也包括响应时间,作品的易学性,正确性等等,我们需要的,只是一个能激起他人探索欲望的契机罢了。

万里挑一的灵魂亦需好看的皮囊包装

好的作品永远需要需要足够优秀的外在来撩动用户的好奇,促使他们对真正有趣的内在进行探索。

4. 总结

一个项目小组成果的优劣直接取决于小组的代码水准,默契程度,分工合理与否,以及设计创意提出。但是最重要的部分还是取决于是否团结,人终归还是一个团队的基础。
必须承认,参与这样的程序设计是对个人能力的一种考验,也是对自己的编程思想以及理论实践能力的拷问。
拢总算来,收获良多。










另附:
加权创建五子棋AI代码:

class AI
{
    // 15*15共有572种五子连珠的可能性
    const int MaxFiveChainCount = 572;

    //玩家的可能性
    bool[,,] _ptable = new bool[Board.CrossCount, Board.CrossCount, MaxFiveChainCount];

    //电脑的可能性
    bool[, ,] _ctable = new bool[Board.CrossCount, Board.CrossCount, MaxFiveChainCount];

    //记录2位玩家所有可能的连珠数,-1则为永远无法5连珠
    int[,] _win = new int[2, MaxFiveChainCount];

    //记录每格的分值
    int[,] _cgrades = new int[Board.CrossCount, Board.CrossCount];
    int[,] _pgrades = new int[Board.CrossCount, Board.CrossCount];

    //记录棋盘
    int[,] _board = new int[Board.CrossCount, Board.CrossCount];

    int _cgrade, _pgrade;
    int _icount, _m, _n;
    int _mat, _nat, _mde, _nde;

    public AI( )
    {
        for ( int i = 0;i<Board.CrossCount;i++)
        {
            for ( int j = 0;j<Board.CrossCount;j++)
            {
                _pgrades[i, j] = 0;
                _cgrades[i, j] = 0;
                _board[i, j] = 0;
            }
        }

        //遍历所有的五连子可能情况的权值  
        //横  
         for ( int i = 0;i<Board.CrossCount;i++)
         {
             for ( int j = 0;j<Board.CrossCount - 4 ;j++)
             {
                 for( int k = 0;k < BoardModel.WinChessCount;k++)
                 {
                     _ptable[j + k, i, _icount] = true;
                     _ctable[j + k, i, _icount] = true;
                 }

                 _icount++;
             }
         }

         //横  
         for (int i = 0; i < Board.CrossCount; i++)
         {
             for (int j = 0; j < Board.CrossCount - 4; j++)
             {
                 for (int k = 0; k < BoardModel.WinChessCount; k++)
                 {
                     _ptable[i, j + k,  _icount] = true;
                     _ctable[i, j + k,  _icount] = true;
                 }

                 _icount++;
             }
         }

         // 右斜
         for (int i = 0; i < Board.CrossCount - 4; i++)
         {
             for (int j = 0; j < Board.CrossCount - 4; j++)
             {
                 for (int k = 0; k < BoardModel.WinChessCount; k++)
                 {
                     _ptable[j+k, i + k, _icount] = true;
                     _ctable[j + k, i + k, _icount] = true;
                 }

                 _icount++;
             }
         }

         // 左斜
         for (int i = 0; i < Board.CrossCount - 4; i++)
         {
             for (int j = Board.CrossCount - 1; j >= 4; j--)
             {
                 for (int k = 0; k < BoardModel.WinChessCount; k++)
                 {
                     _ptable[j - k, i + k, _icount] = true;
                     _ctable[j - k, i + k, _icount] = true;
                 }

                 _icount++;
             }
         }

         for (int i = 0; i < 2; i++)
         {
             for (int j = 0; j < MaxFiveChainCount; j++)
             {
                 _win[i, j] = 0;
             }
         }

         _icount = 0;    
    }




    void CalcScore( )
    {
        _cgrade = 0;
        _pgrade = 0;
        _board[_m, _n] = 1;//电脑下子位置     

        for (int i = 0; i < MaxFiveChainCount; i++)
        {
            if (_ctable[_m, _n, i] && _win[0, i] != -1)
            {
                _win[0, i]++;//给白子的所有五连子可能的加载当前连子数  
            }

            if (_ptable[_m, _n, i])
            {
                _ptable[_m, _n, i] = false;
                _win[1, i] = -1;
            }
        }
    }

    void CalcCore( )
    {
        //遍历棋盘上的所有坐标  
        for (int i = 0; i < Board.CrossCount; i++)
        {
            for (int j = 0; j < Board.CrossCount; j++)
            {
                //该坐标的黑子奖励积分清零  
                _pgrades[i, j] = 0;

                //在还没下棋子的地方遍历  
                if (_board[i, j] == 0)
                {
                    //遍历该棋盘可落子点上的黑子所有权值的连子情况,并给该落子点加上相应奖励分  
                    for (int k = 0; k < MaxFiveChainCount; k++)
                    {
                        if (_ptable[i, j, k])
                        {
                            switch (_win[1, k])
                            {
                                case 1://一连子  
                                    _pgrades[i, j] += 5;
                                    break;
                                case 2://两连子  
                                    _pgrades[i, j] += 50;
                                    break;
                                case 3://三连子  
                                    _pgrades[i, j] += 180;
                                    break;
                                case 4://四连子  
                                    _pgrades[i, j] += 400;
                                    break;
                            }
                        }
                    }

                    _cgrades[i, j] = 0;//该坐标的白子的奖励积分清零  
                    if (_board[i, j] == 0)//在还没下棋子的地方遍历  
                    {
                        //遍历该棋盘可落子点上的白子所有权值的连子情况,并给该落子点加上相应奖励分  
                        for (int k = 0; k < MaxFiveChainCount; k++)
                        {
                            if (_ctable[i, j, k])
                            {
                                switch (_win[0, k])
                                {
                                    case 1://一连子  
                                        _cgrades[i, j] += 5;
                                        break;
                                    case 2: //两连子  
                                        _cgrades[i, j] += 52;
                                        break;
                                    case 3://三连子  
                                        _cgrades[i, j] += 130;
                                        break;
                                    case 4: //四连子  
                                        _cgrades[i, j] += 10000;
                                        break;
                                }
                            }
                        }

                    }


                }
            }
        }

    }

    // AI计算输出, 需要玩家走过的点
    public void ComputerDo(int playerX, int playerY, out int finalX, out int finalY )
    {
        setPlayerPiece(playerX, playerY);

        CalcCore();

        for (int i = 0; i < Board.CrossCount; i++)
        {
            for (int j = 0; j < Board.CrossCount; j++)
            {
                //找出棋盘上可落子点的黑子白子的各自最大权值,找出各自的最佳落子点 
                if (_board[i, j] == 0)
                {
                    if (_cgrades[i, j] >= _cgrade)
                    {
                        _cgrade = _cgrades[i, j];
                        _mat = i;
                        _nat = j;
                    }

                    if (_pgrades[i, j] >= _pgrade)
                    {
                        _pgrade = _pgrades[i, j];
                        _mde = i;
                        _nde = j;
                    }

                }
            }
        }

        //如果白子的最佳落子点的权值比黑子的最佳落子点权值大,则电脑的最佳落子点为白子的最佳落子点,否则相反  
        if (_cgrade >= _pgrade)
        {
            _m = _mat;
            _n = _nat;
        }
        else
        {
            _m = _mde;
            _n = _nde;
        }


        CalcScore();
       
        finalX = _m;
        finalY = _n;
    }

    void setPlayerPiece( int playerX, int playerY )
    {
        int m = playerX;
        int n = playerY;

        if ( _board[m, n ] == 0 )
        {
            _board[m, n] = 2;

            for( int i = 0;i<MaxFiveChainCount;i++)
            {
                if ( _ptable[m, n, i ] && _win[1, i] != -1 )
                {
                    _win[1, i]++;
                }
                if (_ctable[m,n,i])
                {
                    _ctable[m, n, i] = false;
                    _win[0, i] = -1;
                }
            }
        }
    }
    
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值