Jian's profile星舞PhotosBlogListsMore Tools Help

Blog


    11/30/2007

    中国网络游戏市场:春秋时代&百家争鸣

    各大上市网络游戏公司Q3发布后,座次基本排定:前9名像皇帝一样牢牢的霸占着大半个江山!

    排第一的是盛大网络,收入6.34亿元(曾经靠传奇打下的超雄厚家底,旗下拥有许多实力强劲的开发团队,其中有支最令盛大引以为傲的被史玉柱挖了墙角,从而成就了巨人网络。。。)

    第二是网易,收入4.96亿元(游戏的主要收入来源是旗下的2D游戏,开发出来的3D游戏,玩家貌似都不领情)

    第三是巨人网络,收入4.05亿元,主打产品征途也是2D游戏。

    第4:9城,收入3.16亿元。靠的是魔兽世界和暴雪的名气。说实在的,当时如果有钱的企业组建个游戏运营公司,去买下魔兽世界的运营权,也能变成9城。

    第5:腾讯,2.3亿

    第6:完美时空。1.97亿。旗下新网游赤壁,看来和天畅争商标成功了。不过说实话,暑假里实习的时候,也参与过天畅的赤壁开发,觉得,那款游戏,无论是哪方面,和完美时空的都不在一个档次上。。。

    第7:网龙。1.9亿。

    第8:金山,1.02亿。国产民族网游的探路者,当时也就它有这个能力去做吧

    第9:搜狐,不到1个亿

    其它的都是些零星的中小公司,比如杭州天畅啊,杭州渡口什么的。

    由此可见,目前中国游戏市场上,最赚钱的还是2D类型的游戏。3D的时代还没有真正开始。主要原因,是目前国内的3D技术还不是特别成熟,特别是在网游上的运用,网络因素也是制约3D网游的一大主因。而且,中国玩家喜欢多开,喜欢在游戏的同时聊天,所以,2D网游比3D网游在这方面有很大的优势。所以,还有点时间,我并不用特别着急的入行。史玉柱预测2009年才是3D网游的天下,我觉得时间还要往后推,2009-2011年都可能是2.5D的天下,也就是类似于SY6,7系列的模式。而且那时候2D网游还会保持着很强劲的市场,因为回合制游戏,对中国玩家而言有不可替代的重要性。

    另外,很多中等规模的游戏公司,基本上都存在员工和投资商之间的矛盾。所以,夹在中间的游戏制作人,亲投资商,会被员工唾弃,亲员工,更有可能被投资商勒令滚蛋。实在是两面难做人。比如天畅的宁资海,那时候在实习的时候就嗅出味道不怎么对,老自己一个人关在门里,不和团队里的几个主策沟通,搞得整个公司的气氛都阴沉沉的(和写字楼也有关系)楼不高,层多,搞得每层单位都很矮。。。

    所以,要办好理想中的公司。。我自己一定要能出足够多的钱。。。如果到时候要找风险投资,也要尽量不能被别人牵着鼻子走,否则,会严重限制公司的发展。。。毕竟,那些个风险投资商没几个了解游戏的。。。眼里只有:钱!

    11/27/2007

    作品完成,可以松口气了。。。

    本人第一幅超现实主义作品。从起稿到完成,一共花了将近5个小时,哎。。。真是要命啊。。。

    本来打算用色彩的,不过想想就为了那么个作业,就去买齐一套材料,那就真是个大傻X了!所以,拿CONTE将就吧,反正还有好几只呢,以后也不会再用。。。

    The Dream of Easter Island

    The Dream of Easter Island

    至于sketch book的作业。。。一学期积累下来了N多。。。不过还好完成了应该完成的后,别的随便你画。。。所以,全部拿钢笔速写充数。。。平均10分钟一张,没几个小时就搞定了。。。呵呵。。。暂时可以缓口气了~

    11/23/2007

    忙里偷闲

    今天无意中看了篇有关三国的文章,呵呵,观点很独到,想我自打认字起就摸着三国演义的书皮,自诩三国演义里出现过的千把号有名有姓的人里没有几个不认识的,更没理由写不出三国背后的“野史”!

    呵呵,等期末结束了,静下心来好好挖掘点三国的故事~

    11/17/2007

    周农民穷途末路了

    一张2年前的年画,已经被证实是真的,年画中的老虎,也被证实是和周农民照片中的老虎是同一只,铁一般的证据表明,周老虎是只纸老虎,该照片,作假!

    于是乎周农民狗急跳墙了,一大清早领着一群专家上山去寻虎,不过结果怎么样,照片作假是被认定了的事实,就算真有老虎,也救不了他了。这会,全国几十万人正翘首以待的看周农民的洋相,特别是色影无忌论坛上的那群人,估计对周农民恨的是咬牙切齿吧,因为他强奸了论坛里这一大群高手们的专业修为。拿一张色温如此变态的照片,硬要充说是真老虎,等同于一个玩了个把月游戏的菜鸟级玩家跑到一群资深游戏策划面前要瞎嚷嚷,哎,是可忍孰不可忍啊!

    那个关克也很有意思,他是坚定的挺虎者,所以,就算是多么铁的证据,他也要给它来个胡搅蛮缠。哎,人被逼急了就疯癫,此话一点不假,越是爱面子的人,在越是对自己不利的条件下越是不知道悔改,给个台阶下也不下,那就等着摔死吧!

    这个把月的老虎门事件,剧情跌宕起伏,使得我这种局外人,看得可谓是酣畅淋漓。好了,到最终高潮了,安心坐下来等结局吧。亲爱的媒体同志们,别把周农民给逼死了啊,人家可是拿脑袋硬抗的!

    (hoho,我这种搬板凳看热闹的心态真阴险~)

    11/16/2007

    华南虎事件终于快要终结了

    从第一张照片公布到现在,已经过去了1个月零4天,期间两派人马相互攻击,此消彼长,各有胜负,不过,一张疑似老虎原型的年画被发现,很有可能会终结这1个多月以来的闹剧!

    打从第一眼看到老虎照片,我就很坚定的觉得是假的,原因有三:1.照片看着不自然,2.老虎肚子太白,不可能是野生的, 3.周正龙让我瞧着不舒服。

    如果照片是假的,那这个“老实巴交”的农民,为什么会去作假呢?这个,网上有很多推测,不过在最后的决定性证据出来之前,没人能说清楚。我个人觉得吧,不外乎两种可能:周财迷心窍,或是他后面有人指使。

    有一点不可忽视,关克在年画出现后,一再强调,只要发现了华南虎在当地存在的证据,人们还会再质疑这张照片的真假吗?假照片和真老虎,这完全是两码事,为什么要说是强盗逻辑呢?其实,他是怕了。他把宝压在当地有老虎身上,希望通过后继的调查,能够发现真的华南虎。我觉得关克,是个无比狡诈,阴险,但是非常有手段的人。目前事情闹成这样,无论是什么样的结果,他都是稳赚不赔:

    1.发现真老虎:陕西省林业厅能获得国家和国际上的资金援助来建设保护区。

    2.发现真老虎,但是照片被证实是假的:倒霉的也只有周正龙而已,陕西省林业厅还是能得到实际的利益。

    3.没发现真老虎,照片也是假的:倒霉的还是只有周正龙,关克和林业厅大可以以目前的调查还没结果为由,拖延时间,保护自己。

    之所以说关克有手腕,还是因为他善于把握机会。周正龙很有可能是自己一时犯晕,做假骗钱,没想到后来骑虎难下,只能硬着头皮往前抗。而关克一看这是个机会,就死死咬住周,表面上挺虎,背地里确一直把自己保持在一个安全的范围外,不让周倒时候败露了,反咬自己一身毛。

    当然,这一切都是假设周正龙作假的技巧并不是关克指示为前提的。但就真是关克指使的,他也应该有能力摆平这个“老实巴交”的农民的吧。

    11/15/2007

    西湖8号公馆

    今年暑假后半段经常跑去天风商厦那上班,每次开车从九曜山隧道插到南山路,再插进四宜路后,就会看见个小工地,项目名叫:西湖8号公馆。

    暑假哪会听我妈说,估计开盘后要4万左右,她那会对这个盘子还挺有兴趣的。昨天一看新浪新闻首页:杭州最贵楼盘12.2万/㎡,当时绝对没想到竟然是这个西湖8号公馆。。。

    这地方离西湖是近,不过走5分钟只能走到柳浪闻莺而已,离最黄金的景点还有很长的距离。而且从楼上望出去,是可以看到西湖,不过应该只能有一个角。吴山广场,是个面向所有小市民的平民广场,综合档次和湖滨路那块是不能比的。而且要论修身养性,这块地方也远远不及北山街,或者西湖西线的大片地区。哎,这样的地方,都12.2万/㎡,这楼市真是疯了!

    住西湖边,最理想的地方是北山街那一片,可惜,现在那除了民国时留下的老别墅,省委大院,剩下的都是没有产权的房子。如果哪家开发商能在那拿一小块地起个别墅,那这别墅的售价毫无疑问能进中国豪宅前3。

    哎,这年头,即使是对身价上亿的人来说,能住在西湖边也是种奢侈了。。。

    11/12/2007

    呼一口气

    人吧,总是有高潮和低谷,而在这高潮和低谷的转换中,人就会得到成长。

    这段时间对我,绝对是低谷期。应该就是从上次编程期中考后开始的吧,虽然目前没有什么大不了的后果,不过总觉得做什么事都缺少激情,缺少干劲。我,虽然这几年在各方面都取得了长足的进步,不过唯独惰性上,还是那个7年前刚上高一的我。。。

    我,目前仍然缺乏毅力,玩不了命。每次和方舟喝开了,都会在最后关头松下口劲。还是不够爷们。

    我,很强,应该可以说超强。不过没有毅力的话,肯定会一事无成的。这是我自己对自己的深刻了解,也应该是我一切苦恼的根源。

    有时候我会静默下来,用心去感受身边一切事物的细小变化,去感受那来自地心的引力和地球自转带来的哪怕是一丁点的离心力。这对我而言,这是与自然合而为一的精神法则。通过这种方法,我的思维会提升到一个很不错的高度,可惜,很难有后继的动力去将这种思维变成很实在的东西。我真正安静的时候,也会打心里责怪自己,可是,也仅仅是心理上的憎恶而已。。。

    我,还是相当的不成熟啊!

    国外这几年,很复杂的感情。。。从道明,EAP,一直到现在的U,前后光学费就花了40多万了,再加上近30万的生活费,呵呵,现在这样的半吊子,就已经花掉了别人可以读完大学的钱。这笔钱花得值吗?不值,如果不是那年死在魔力里,我已经可以马上彻底回国了!但是,也挺值,如果不是死在魔力里又活回来了,我就在国外白待了。

    很多事情,当你从最低点眺望最高点的时候,会绝望。但是当你一步步走上去,就会发现也还可以,走累了,歇一歇,大不了小半步小半步的爬,只要还在走,就还是可以到顶点的。

    这几天看完本电视剧,《士兵突击》,觉得拍的很完美,编剧的水准相当高,演员演的也不错。看后感触很深。。。我和许三多只有一点是相像的:都是男的。另外硬要攀上点关系的话,我和他都不做没有意义的事。只不过,许三多觉得好好活就是有意义,有意义就是好好活,而我?说不准。。。我觉得拿绿卡没意义,所以就算送到我面前我也不要。我觉得读研没意义,所以我绝对不会读。但是,有的时候我又觉得一些别人觉得没有意义的事很有意义,会去很认真的做。这,在别人眼里,就成了固执。所以,我,不是个常人,而非常人只有两种活法:人上人,或是人下人。

    但我,总得来说还是幸运的,有个中上的智商,有个上等的家庭条件,而且又经历过悲惨的失败,算是马马虎虎有个相对完整的人生序曲。相较同龄人,应该可以站在个比较靠前的位置。下一步,要踏踏实实培养自己的毅力了,这回,怕是要动点真格的了。

    11/7/2007

    凑活

    妈的,编程考试竟然有30分的名词解释!!!那老师脑子进水!!!

    我的90+飞了。。。

    哎,算了,现在总算稍微空点了,开始专心投入到游戏策划中去吧

    11/5/2007

    本人历史上第一幅自画像

    呵呵,这是本人第一幅自画像,用的材料是Conte色粉笔。虽然是第一次使用这样的材料,不过还是很快就掌握了这种材料的特性。在画这幅画的过程中,自己领悟了些比较独特的方法,觉得比较满意,应该可以上90,周四晚交之前,再把一些感觉比较怪的地方好好改改。

    PS:本人画第2幅自画像最早也要等我减肥成功以后,画那么胖的自己,简直是种煎熬!

    11/4/2007

    本空间改版成功

    今后,本空间将重点发表有游戏开发有关的内容(包括程序,代码,CG,策划,策划所需的历史,天文地理,民俗,神话等资料)。所有的资料都可以在空间首页上的索引处找到。

    PHOTOSHOP手绘教程:漆黑之牙—约修亚

    本空间要转型成为一个提供资讯,资源为主的游戏开发类个人blog,所以整理了以前在此空间发表过的一些东西。这是本人第一幅手绘作品,以后会陆续发表更新的成果。

    使用工具:photoshop cs2, intous 3 9*12 数位板

    1. 线稿,因为是临摹的,所以咬型不会太差。

    线稿

    2. 上色,并活用加深减淡工具画(曝光值10%左右,流量50%)

    上色1

    3.还是上色

    上色2

    4.注意将每个不同的物件用新的图层来分开,这样方便修改

    上色3

    5. 上色,修改各部分颜色上的差异

    上色4

    6. 画头发,这里用的办法是先自定义笔刷,随便点几个点,然后用新定义的笔刷来画。不过效果不好,以后的作品会尝试用钢笔工具勾线,然后模拟压力描边

    头发

    个人代码资源库索引

    编程语言选项:

    C++, C#: 点击此处

    个人代码资源库索引(C++,C#)

     

    OOP实例1:点击此处 <描述:该代码中模块之间的构造关系非常有参考价值>

    链表递归反序:点击此处 <描述:viod型单参数读入链表递归反序算法>

    OOP实例2:点击此处 <描述:Client/Server模式模拟>

    图操作:点击此处 <描述:实现了一些图的基本操作>

    Keyframe System:点击此处 <描述:实现了一个关键帧与关键帧之间的smooth过程>

    C++配合openGL做成的飞行射击小游戏:点击此处 <描述:内详>

    面向对象编程<实例1>PART0

    下一部分链接:面向对象编程<实例1>PART1

    项目描述:OOP第2份作业,剑桥大学教授John Conway提出的一个关于细胞生存的数学模型。

    项目UML图示:UML diagram

    代码:

    头文件"Cell.h"声明

    #pragma once

    #include "common.h"

    namespace game {

    class Cell
    {
    public:
        // Constructor: this cell is dead by default.
        Cell(void);
        // Destructor.
        virtual ~Cell(void);
       // Sets the alive-ness of this cell to the value of `liveness'
        void setAlive(bool liveness);
        // Returns true if this cell's alive, or false, otherwise.
        bool isAlive(void);
        // Returns true if this cell's dead, or false, otherwise.
        bool isDead(void);
    private:
        bool m_alive;

    };
    };

    头文件"Cell.h"算法:"Cell.cpp"

    #include "Cell.h"

    using namespace game;

    Cell::Cell(void)
    : m_alive(false) // A Cell object starts life as being dead :)
    {
    }

    Cell::~Cell(void)
    {
    }

    void Cell::setAlive(bool liveness)
    {
        m_alive = liveness;
    }

    bool Cell::isAlive(void)
    {
        if (m_alive == false)
        return false;
        else
        return true;
    }

    bool Cell::isDead(void)
    {
        if (m_alive == false)
        return true;
        else
        return false;
    }

    头文件"common.h"声明

    #ifndef _COMMON_H_
    #define _COMMON_H_

    #include <iostream>
    #include <cassert>
    #include <cstdlib>

    using namespace std;

    #endif//_COMMON_H_

    头文件"DrawingArea.h"声明

    #pragma once

    namespace game
    {
        class DrawingArea;
    }

    #include "common.h"

    namespace game
    {

    // This class defines the region of the WorldModel that a View object will
    // draw on the screen. Its top-left co-ordinate is (row, col) and has a width
    // 'width' and height 'height'.
    // 
    // (row,col)
    //  +-----------------------------------+  -
    //  |                                   |  ^
    //  |                                   |  |  height
    //  |                                   |  v
    //  +-----------------------------------+  -
    //  |<---------------width------------->|
    class DrawingArea
    {
    public:
        // Constructor. Box is located at (0,0) by default and has width 0 and height 0.
        DrawingArea(void);
        // Destructor
        ~DrawingArea(void);
        // Sets the horizontal position of the top-left of the drawing area to `r'.
        void setRow( int r ) { m_row = r; }
        // Gets the horizontal position of the top-left of the drawing area.
        int getRow() { return m_row; }
        // Sets the vertical position of the top-left of the drawing area to `c'.
        void setCol( int c ) { m_col = c; }
        // Gets the vertical position of the top-left of the drawing area.
        int getCol() { return m_col; }
        // Sets the drawing area's width to `w'.
        void setWidth( int w ) { m_width = w; }
        // Gets the drawing area's width.
        int getWidth() { return m_width; }
        // Sets the drawing area's height to `h'.
        void setHeight( int h ) { m_height = h; }
        // Gets the drawing area's height.
        int getHeight() { return m_height; }
        // Prints out a representation of the drawing area.
        void print();
    private:
        int m_row;
        int m_col;
        int m_width;
        int m_height;
    };

    };

    头文件"DrawingArea.h"算法:"DrawingArea.cpp"

    #include "DrawingArea.h"

    using namespace game;

    DrawingArea::DrawingArea(void) :
        m_row(0),
        m_col(0),
        m_width(0),
        m_height(0)
    {
    }

    DrawingArea::~DrawingArea(void)
    {
    }

    void DrawingArea::print()
    {
        cout << "Drawing Area object" << endl;
        cout << "\trow   = " << m_row << endl;
        cout << "\tcol   = " << m_col << endl;
        cout << "\twidth = " << m_width << endl;
        cout << "\theight= " << m_height << endl;
    }

    面向对象编程<实例1>PART1

    下一部分链接:面向对象编程<实例1>PART 2

    头文件"GameOfLifeController.h"声明

    #pragma once

    namespace game
    {
        class GameOfLifeController;
    }

    #include "worldmodel.h"
    #include "common.h"
    #include "graphicscontext.h"
    #include "view.h"

    namespace game {

    #define DEFAULT_ROWS            150
    #define DEFAULT_COLS            150
    #define DEFAULT_SCREEN_WIDTH    80
    #define DEFAULT_SCREEN_HEIGHT    25

    class GameOfLifeController
    {
    public:
        GameOfLifeController(int rows=DEFAULT_ROWS, int cols=DEFAULT_COLS);
        virtual ~GameOfLifeController(void);
    private:
        void run(void);
        void initialize(void);
    private:
        WorldModel m_model;
        View* m_view;
    };

    };

    头文件"GameOfLifeController.h"算法:"GameOfLifeController.cpp"

    #include "GameOfLifeController.h"

    #include <iostream>
    using namespace std;
    using namespace game;

    GameOfLifeController::GameOfLifeController(int rows, int cols) :
        m_model(rows, cols)
    {
       // Instantiate a new View object as `m_view'
        m_view = new View(m_model);
        initialize();
        run();
    }

    GameOfLifeController::~GameOfLifeController(void)
    {
        // finalize view.
        m_view->finalize();

       // ALWAYS `DELETE' WHAT YOU `NEW'
        delete m_view;
    }

    void GameOfLifeController::initialize(void)
    {
        // assign view to the model.
        m_model.setView(m_view);
        // initialize model. (`m_model' is an object.)
        m_model.initialize();
        // initialize view. (`m_view' is a pointer to an object.)
        m_view->initialize();
    }

    void GameOfLifeController::run(void)
    {
        int continueLooping = true;
        GraphicsContext gc;
        DrawingArea a;
        a.setRow(0); a.setCol(0);
        a.setWidth( DEFAULT_SCREEN_WIDTH );
        a.setHeight( DEFAULT_SCREEN_HEIGHT - 1 );
        m_view->setDrawingArea(&a);
        m_view->draw();

        while (continueLooping)
        {
            // Process user input
            int keycode;
            gc.waitForKeystroke(keycode);
            keycode = toupper(keycode);

            switch( keycode )
            {
            case KC_SPACE: // the SPACE bar means "evolve" the game to the next generation.
                m_model.evolve();
                break;
            case KC_LEFT_ARROW: // `left arrow' means scroll left and redraw.
                a.setRow( a.getRow() - 1);
                m_view->draw();
                break;
           // add code for right, down, up arrows.
            case KC_RIGHT_ARROW:
                a.setRow( a.getRow() + 1);
                m_view->draw();
                break;
            case KC_DOWN_ARROW:
                a.setCol( a.getCol() - 1);
                m_view->draw();
                break;
            case KC_UP_ARROW:
                a.setCol( a.getCol() + 1);
                m_view->draw();
                break;
            case KC_PG_LEFT: // `left arrow' means scroll left and redraw.
                a.setRow( a.getRow() - a.getWidth()/2);
                m_view->draw();
                break;
            // add code for page right, down, up.
            case KC_PG_RIGHT:
                a.setRow( a.getRow() + a.getWidth()/2);
                m_view->draw();
                break;
            case KC_PG_DOWN:
                a.setCol( a.getCol() - a.getHeight()/2);
                m_view->draw();
                break;
            case KC_PG_UP:
                a.setCol( a.getCol() + a.getHeight()/2);
                m_view->draw();
                break;
            case KC_ENTER: // 'up arrow' means go home.
                a.setCol(0);
                a.setRow(0);
                m_view->draw();
                break;
            case KC_F1: // 'F1' means help.
                gc.displayModalDialogBox(10,6,60,10,
                    // Dialog title
                    "                         HELP DIALOG               ",
                    // Dialog contents
                    "\n"
                    "\n"
                    "            Scrolling                      Jumping    \n"
                    "           [ARROW UP]                      [PG UP]    \n"
                    "   [ARROW LEFT] [ARROW RIGHT]       [PG LEFT] [PG RIGHT]\n"
                    "          [ARROW DOWN]                    [PG DOWN]   \n"
                    "\n"
                    "        [F1]  - Help            [ENTER] - Return to origin.\n"
                    "        [ESC] - Exit            [SPACE] - *** EVOLVE! ***\n"
                    );
                m_view->draw();
                break;
            case KC_ESC: // 'Esc' means quit.
                continueLooping = false;
            default: // unknown key. Do nothing.
                break;
            }
        }
    }

    头文件"GraphicsContext.h"声明

    #pragma once

    namespace game
    {
        class GraphicsContext;
    }

    #include "common.h"
    #include "win32console.h"
    #include <string>

    using namespace w32c;

    namespace game
    {

    // special Keyboard scan codes
    const int KC_RIGHT_ARROW    =39;
    const int KC_LEFT_ARROW        =37;
    const int KC_UP_ARROW        =38;
    const int KC_DOWN_ARROW        =40;
    const int KC_PG_UP            =33;
    const int KC_PG_DOWN        =34;
    const int KC_PG_LEFT        =166; // that's the "previous webpage in browser history" key on your Thinkpad keyboard. (or whatever it's called)
    const int KC_PG_RIGHT        =167; // that's the "next webpage in browser history" key on your Thinkpad keyboard.
    const int KC_SPACE            =32;
    const int KC_F1                =80;
    const int KC_ESC            =27;
    const int KC_ENTER            =13;
    // It does not make sense to use an enum, since the values are not sequential.

    class GraphicsContext
    {
    public:
        // Constructor
        GraphicsContext(void);
        // Destructor
        ~GraphicsContext(void);
       // Clears the screen, setting the background to blue and the foreground to yellow.
        void initializeScreen(void);
        // Clears the screen, restoring the colors back to the original values.
        void finalizeScreen(void);
       // Clears the screen.
        void clearScreen(void);
        // Draws a character `c' at co-ordinates ('row','col'), where 'row' is
        // the HORIZONTAL position and 'col' is the VERTICAL position (not the
        // other way around, as you might think).
        void drawChar(int row, int col, char c);
        // Draws a colored block at co-ordinates ('row','col'), where 'row' is
        // the HORIZONTAL position and 'col' is the VERTICAL position (not the
        // other way around, as you might think). The color of this block is 'c',
        // and the type is DOS_COLORS, which is an enum type found in Win32Console.h.
        void draw(int row, int col, DOS_COLORS c);
        // Pause until the user presses a key. The normal ascii code is returned,
        // but the special keyboard codes (relating to KC_PG_UP, KC_PG_DOWN, etc) is
        // returned in the parameter `keycode', which is pass-by-reference.
        int  waitForKeystroke(int& keycode);
        // Prints a modal dialog box on the screen at co-ordinate (row,col) where 'row' is
        // the HORIZONTAL position and 'col' is the VERTICAL position (not the
        // other way around, as you might think), and having width `width' and height `height'.
        // It gives it a title 'title', and fills it in with the text `text'. `text' should point
        // to an object containing carriage return characters (`\n') for text that should appear on
        // multiple lines. Any text appearing between '[' and `]' appears highlighted.
        // Precondition: the total number of lines used does not exceed `height', and
        // `title' and `text' point to valid null-terminated C strings.
        void displayModalDialogBox(int row, int col, int width, int height, char* title, char* text );
        // Draws a string on the screen starting at co-ordinate (row,col) where 'row' is
        // the HORIZONTAL position and 'col' is the VERTICAL position (not the
        // other way around, as you might think)
        void drawStringAt( int row, int col, char* s );
    private:
        Win32Console m_console;
    };

    };

    头文件"GraphicsContext.h"算法:"GraphicsContext.cpp"

    #include "graphicscontext.h"
    #include <wchar.h>

    using namespace game;

    GraphicsContext::GraphicsContext(void) :
        m_console()
    {
    }

    GraphicsContext::~GraphicsContext(void)
    {
    }

    void GraphicsContext::initializeScreen(void)
    {
        m_console.backcolor(w32c::BLUE);
        m_console.textcolor(w32c::YELLOW);
        clearScreen();
        m_console.caret(CARET_NONE);
    }

    void GraphicsContext::finalizeScreen(void)
    {
        m_console.backcolor(w32c::BLACK);
        m_console.textcolor(w32c::WHITE);
        clearScreen();
        m_console.caret(CARET_NORMAL);
    }

    void GraphicsContext::clearScreen(void)
    {
        m_console.clrscr();
    }

    void GraphicsContext::draw(int row, int col, DOS_COLORS c)
    {
        m_console.gotoxy(row+1,col+1);
        m_console.backcolor(c);
        m_console.outtext(_T(" "));
        m_console.backcolor(BLUE);
    }

    void GraphicsContext::drawChar(int row, int col, char c)
    {
        TCHAR pws[2];
        pws[0] = btowc(c);
        pws[1] = 0;
        m_console.gotoxy(row+1,col+1);
        m_console.outtext(pws);
    }

    void GraphicsContext::drawStringAt( int row, int col, char* s )
    {
        size_t origsize = strlen(s) + 1;
        size_t convertedChars = 0;
        wchar_t* wcstring = new wchar_t [strlen(s)+2];
        mbstowcs_s(&convertedChars, wcstring, origsize, s, _TRUNCATE);
        m_console.gotoxy(row+1,col+1);
        m_console.outtext(wcstring);
        delete[] wcstring;
    }

    int GraphicsContext::waitForKeystroke(int& special)
    {
        int retval = 0;
        special= 0;
        m_console.flush();
        while( ! m_console.kbhit() )
            ;

        retval = m_console.getch(special);
        return retval;
    }

    void GraphicsContext::displayModalDialogBox(int row, int col, int width, int height, char* title, char* text)
    {
        assert(text != NULL);
        assert(title != NULL);
        assert( row >= 0 );
        assert( col >= 0 );
        assert( width > 0 );
        assert( height > 0 );
        RECT r;
        r.left=row; r.right=row+width+1;
        r.top=col; r.bottom=col+height+1;
        m_console.textattr(BLUE,LIGHT_GRAY);
        m_console.clrscr(&r);
        m_console.gotoxy(row+1,col+1);
        m_console.textattr(LIGHT_CYAN,GREEN);
        m_console.hline(_T(' '), width+1);
        drawStringAt(row,col,title);
        m_console.textattr(LIGHT_GREEN,BLUE);
        m_console.frame( r, _T("/-\\|\\-/") );
        m_console.textattr(BLUE,LIGHT_GRAY);
        int x = 0; int y = 0;
        for( int j=0; j < (int)strlen(text); j++ )
        {
            if( text[j] == '\n' )
            {
                y++;
                x = 0;
                continue;
            }
            if( y > width )
            {
                y = 0;
                x++;
            }
            assert( y < height );
            if( text[j] == '[' )
                m_console.backcolor(WHITE);
            drawChar(x+row,y+col,text[j]);
            if( text[j] == ']' )
                m_console.backcolor(LIGHT_GRAY);
            x++;
        }
        m_console.textattr(YELLOW,BLUE);
        m_console.pause();
    }

    面向对象编程<实例1>PART 2

    下一部分链接:面向对象编程<实例1>PART 3

    头文件"View.h"声明

    #pragma once

    namespace game
    {
        class View;
    }

    #include "common.h"
    #include "graphicscontext.h"
    #include "worldmodel.h"
    #include "drawingarea.h"
    #include "worldmodel.h"

    namespace game
    {

        const int ALIVE_CHAR = '#';
        const int DEAD_CHAR  = ' ';

        // View objects are responsible for drawing on the screen the part of
        // the WorldModel grid that is inside a specified Drawing Area.
        class View
        {
        public:
            // Constructor: `m' is a reference to the world model that this
            // View object is responsible for representing on the screen.
            View(WorldModel& m);
            // Destructor
            virtual ~View(void);
            // Initializes the View. Sets a blue background and yellow foreground.
            void initialize();
            // Finalizes the View. Restores the console colours back to normal.
            void finalize();
            // Tells this View object what area of the world model should be drawn
            // on the screen. `a' is a pointer to a DrawingArea object.
            void setDrawingArea( DrawingArea* a );
            // Draw the region of the associated WorldModel that lies within the
            // drawing area.

            void draw();
        private:
            // A pointer to a GraphicsContext object for drawing on the console.
            GraphicsContext* m_pGC;
            // A reference to this View's associated World Model. The Object that
            // this references should have this View as its associated View object,
            // too. If a client calls evolve() on this View's associated World Model
            // object, then it will notify this View to draw() the screen.
            WorldModel& m_model;
            // A pointer to a DrawingArea object that represents the region of the
            // associated World Model that should actually be drawn on the screen.
            DrawingArea* m_pDrawingArea;
        };

    };

    头文件"View.h"算法:"View.cpp"

    #include "View.h"
    #include <string>

    using namespace game;
    using namespace w32c;

    #pragma warning(push)
    #pragma warning( disable : 4996 )

    View::View(WorldModel& m) :
        m_model(m),
        m_pDrawingArea(NULL)
    {
       // instantiate a new GraphicsContext object and make `m_pGC' point to it.
        m_pGC = new GraphicsContext;
        // "m_pGC" should be read as "Member variable: Pointer to a Graphics Context"
        assert( m_pGC != NULL );
    }

    View::~View(void)
    {
        // ALWAYS `DELETE' WHAT YOU `NEW'
        delete m_pGC;   
    }

    void View::initialize()
    {
       // Initialize the screen using the GraphicsContext object m_pGC
        // This should give the console a blue background and yellow foreground.

        m_pGC->initializeScreen();
    }

    void View::finalize()
    {
        // Finalize the screen using the GraphicsContext object m_pGC
        // This should give the console the original colours.
        m_pGC->finalizeScreen();
    }

    void View::setDrawingArea( DrawingArea* a )
    {
        // `a' points to a DrawingArea object.
        assert( a != NULL );
        m_pDrawingArea = a;
        // `m_pDrawingArea is assigned `a';
        assert( m_pDrawingArea == a );
    }

    void View::draw()
    {
        assert( m_pDrawingArea->getWidth() > 0 );
        assert( m_pDrawingArea->getHeight() > 0 );
        // Put all drawing code here!
        for( int row = 0; row<m_pDrawingArea->getWidth(); row++ )
        {
            for( int col=0; col<m_pDrawingArea->getHeight(); col++ )
            {
                // assign `currentCellIsAlive' to `true' if the cell at location (m_pDrawingArea->getRow() + row, m_pDrawingArea()->getCol() + col)
                // is alive. Otherwise, it should be set to `false'.
                bool currentCellIsAlive = m_model.getCell(  m_pDrawingArea->getRow() + row, m_pDrawingArea->getCol() + col  )-> isAlive() ;
                if( currentCellIsAlive )
                {
                    // tell the GraphicsContext object to draw `ALIVE_CHAR' at location (row, col)
                    m_pGC->draw(row,col,w32c::YELLOW);
                }
                else
                {
                    // tell the GraphicsContext object to draw `DEAD_CHAR' at location (row, col)
                    m_pGC->draw(row,col,w32c::BLUE);
                }
            }
        }

        // Create a string and display it on the screen.
        char pBuffer[32];
        sprintf( pBuffer, "Generation count: %ld", m_model.getGenerationCount() );
        // Draw the message.
        m_pGC->drawStringAt(0, m_pDrawingArea->getHeight(), pBuffer );
    }

    #pragma warning(pop)

    面向对象编程<实例1>PART 3

    下一部分连接:面向对象编程<实例1> PART 4

    头文件"Win32Console.h"声明

    // Win32Console.h: interface for the xxiConsole class.
    //
    //////////////////////////////////////////////////////////////////////

    #if !defined(AFX_XXICONSOLE_H__B1C2B6F4_5918_40C4_A4EE_569D989ED079__INCLUDED_)
    #define AFX_XXICONSOLE_H__B1C2B6F4_5918_40C4_A4EE_569D989ED079__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    #include <windows.h>
    #include <tchar.h>

    namespace w32c
    {

    // -------------------------------------------------------------------------
    // All [x,y] locations and RECT coordinates are 1-based.
    // -------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // Values for 'uiShapeAndVisibility' in a call to 'xxiConsole::caret()':
    // -------------------------------------------------------------------------
    #define CARET_NONE    0    // Hide console cursor
    #define CARET_SOLID    1    // Show cursor as a 100% filled character cell
    #define CARET_NORMAL    2   // Show cursor as an underlined character cell

    // -------------------------------------------------------------------------
    // Values for 'iUpDown' in a call to 'xxiConsole::scroll()':
    // -------------------------------------------------------------------------
    #define SCROLL_UP    1
    #define SCROLL_DOWN    2

    // -------------------------------------------------------------------------
    // Values for 'uiFlags' in a call to 'xxiConsole::cgets_numeric()':
    // -------------------------------------------------------------------------
    #define NUMERIC_NEGATIVE    0x0001    // Allows to enter '-' sign before the value
    #define NUMERIC_FP    0x0002    // Allows to enter float point values (including scientific notation: 3.784e-4)

    // -------------------------------------------------------------------------
    // Colors for 'textattr()', 'textcolor()', 'backcolor()':
    // -------------------------------------------------------------------------
    enum DOS_COLORS {
        BLACK,
        BLUE,
        GREEN,
        CYAN,
        RED,
        MAGENTA,
        BROWN,
        LIGHT_GRAY,
        DARK_GRAY,
        LIGHT_BLUE,
        LIGHT_GREEN,
        LIGHT_CYAN,
        LIGHT_RED,
        LIGHT_MAGENTA,
        YELLOW,
        WHITE
    };

    // -------------------------------------------------------------------------
    class W32CTextImage
        {
        public:
        int m_iRows;
        int m_iColumns;
        CHAR_INFO* m_pData;
        };

    // -------------------------------------------------------------------------
    class W32CKeyItem
        {
        public:
        BOOL m_bLastSlot;
        UINT m_uiVirtKeyCode;
        TCHAR m_chAscii;
        };

    // -------------------------------------------------------------------------
    class Win32Console
        {
        public:
            // Constructor
            Win32Console (int iMaxEvents=128);

            // Copy constructor. MUST NEVER BE CALLED!
            Win32Console (const Win32Console& );

            // Destructor
            virtual ~Win32Console ();

            // Blank out full screen or just an area (using active back color).
            void clrscr (RECT* pArea=NULL); // Long live Turbo C!..

            // Draws text from current cursor location using
            // current color attributes of a console. Use '\n' to
            // separate lines as in standard 'printf()'.
            void outtext (TCHAR* pstrText, int iChars=-1);

            void endl (); // Next line on output.

            // For drawing the string with highlighted symbol(s).
            // The symbols after 'chHighLighter' will be painted with 'iHotCharColor'.
            // EXAMPLE: "Open &File..."
            void outtext_hot_char (TCHAR* pstrText, int iHotCharColor, TCHAR chHighLighter=_T ('&'));

            // For drawing the string with one or more highlighted text parts.
            // The key surrounded with 'chHighLighters' will be painted with 'iHotTextColor'.
            // EXAMPLE: "Press &F1& to get help"
            void outtext_hot_text (TCHAR* pstrText, int iHotTextColor, TCHAR chHighLighters=_T ('&'));

            // Helpers (using active colors and both modifying caret position):
            void hline (TCHAR chAscii, int iChars); /* Horizontal line */
            void vline (TCHAR chAscii, int iChars); /* Vertical line */

            // Get text from a console. The input will be completed by
            // pressing ENTER key. Return value is a result of 'strlen (pstrBuf)'.
            // Use 'cgets()' to provide better controlled input.
            int intext (TCHAR* pstrBuf, int iBufChars /*including null terminator*/);

            // Low level I/O:
            BOOL kbhit (); // Returns TRUE if some key is in the buffer.
            void flush (); // Clears input buffer (including mouse events).

            // This function will extract any key WITHOUT calling it twice
            // as it is required by the standard. I find it very annoying. Some
            // keys will generate zero as a return code, but 'ref_iVirtKeyCode'
            // will contain the VK_xxx codes defined in Windows.h. Example
            // of such keys: F1..F12. Some keys will return both ASCII value
            // and 'ref_iVirtKeyCode' too. Example: ESC, ENTER keys.
            // This function also will 'pick' such keys as SHIFT, ALT, CTRL.
            // Notice the internal use of that function in 'cgets()'.
            int getch (int& ref_iVirtKeyCode);

           // Simple 'getch()' wrapper.
            // Waits for any symbol generating key.
            void pause ();

            // Does not return until the ASCII from a character set is pressed.
            // If you want to make a menu selection: 'wait_for_ascii ("123456");'
            TCHAR wait_for_ascii (TCHAR* pstrCharSet);

            // Controlling cursor attributes:
            void caret (UINT uiShapeAndVisibility);
            void gotoxy (int iColumn, int iRow); // [1,1] is a left, top screen cell.

            // Returns current caret position (1-based)
            void wherexy (int* piColumn/*can be NULL*/, int* piRow/*can be NULL*/);

            // Controlling I/O color:
            void textattr (int iTextColor, int iBackColor);
            void textcolor (int iColor);
            void backcolor (int iColor);

            // High-Level I/O:

            // Adds "Y/N" to 'pstrPrompt' and waits for response.
            // Returns TRUE if 'Y' or 'y' was specified.
            BOOL verify (TCHAR* pstrPrompt, int iHotKeyColor=LIGHT_GREEN);

            // Input/Edit a string from console (returns zero if empty string entered):
            int cgets (TCHAR* pstrBuf, /*make sure this buffer contains the text to be edited or empty*/
                int iMaxChars /*not including null terminator*/,
                TCHAR* pstrValidCharSet=NULL, /*by default - do not filter anything*/
                BOOL bPassword=FALSE); /*TRUE will turn output symbols into '*' */

            // That function will not return until valid numeric value (according to 'uiFlags')
            // will be entered. Make sure the 'iMaxChars' is enough room to hold your value
            // plus additional string "ERR: " - 5 symbols more. In case invalid input will be
            // entered the editor will display "ERR: invalid_value_here" and you will have to erase
            // "ERR: " and also fix the bad format of the value.
            int cgets_numeric (TCHAR* pstrBuf, int iMaxChars, UINT uiFlags=0);

           // Some validator helpers:
            BOOL is_double (TCHAR* pstrValue);
            BOOL is_integer (TCHAR* pstrValue);

            // Wrapper for 'frame()' with 4 predefined border types:
            void frame_byid (RECT& area, int iBorderID /*in range [1..4]*/);

            // pstrFrameCharSet [0] - left, top corner
            // pstrFrameCharSet [1] - top side
            // pstrFrameCharSet [2] - right, top corner
            // pstrFrameCharSet [3] - left and right sides
            // pstrFrameCharSet [4] - left, bottom corner
            // pstrFrameCharSet [5] - bottom side
            // pstrFrameCharSet [6] - right, bottom corner
            void frame (RECT& area /*borders are included*/, TCHAR* pstrFrameCharSet);

            // Scrolls the contents of 'area' up/down by 'iLines'.
            // The released room filled with blanks with active color.
            void scroll (RECT& area, int iUpDown, int iLines=1);

            // Good helper for menu implementation.
            void select (int x, int y, int iBackColor, int iTextColor, int iChars);

            // Imaging. Use it when you need to move images or
            // save/restore text areas if needed (popup menus, etc.).
            W32CTextImage* alloc_text_image (RECT& area);

            // First call 'alloc_text_image()' and then use returned value
            // as 'pImage' in these functions.
            void get_text_image (W32CTextImage* pImage, RECT& area);
            void put_text_image (int x, int y, W32CTextImage* pImage);

           // Deallocates object allocated by 'alloc_text_image()':
            void release_text_image (W32CTextImage* pImage);

            // Formatting helpers (or use '_stprintf (buf, fmt, ...);' instead):
            void fmt_int (int iValue, TCHAR* pstrFmt=_T("%d"));
            void fmt_bin (UINT uiValue, int iGroups=4, int iGroupWidth=8);
            void fmt_dbl (double dblValue, TCHAR* pstrFmt=_T("%f"));

            // In addition to 'cgets_numeric()' some exotic input.
            // These methods return FALSE in case user entered empty string.
            BOOL read_hex (UINT& uiOutValue);
            BOOL read_bin (UINT& uiOutValue);

        private:
            HANDLE m_hInput;
            HANDLE m_hOutput;

            // Limits for 'gotoxy()':
            SHORT m_iMaxRow;
            SHORT m_iMaxColumn;

            // Active color attribute:
            WORD m_wCellAttr;

           // Low-level input buffer:
            INPUT_RECORD* m_arrLowLevelEvents;
            int m_iMaxEvents;

            // Low-level buffer for 'getch()':
            W32CKeyItem* m_pWheelBuffer;
            W32CKeyItem* m_pWheelReadKey;
            W32CKeyItem* m_pWheelWriteKey;
        };

    }; // end namespace w32c.

    #endif // !defined(AFX_XXICONSOLE_H__B1C2B6F4_5918_40C4_A4EE_569D989ED079__INCLUDED_)

    面向对象编程<实例1> PART 4

    头文件"WorldModel.h"声明

    #pragma once

    namespace game
    {
        class WorldModel;
    }

    #include "common.h"
    #include "Cell.h"
    #include "view.h"

    namespace game {

    #define MAX_ROWS        1024
    #define MAX_COLS        1024

    class WorldModel
    {
    public:
        // Constructor: creates a 2d grid of Cell objects for the Game of Life having
        // number of rows `rows' and number of cols `cols'
        WorldModel(int rows=10, int cols=10);
        // Destructor.
        virtual ~WorldModel(void);
        // Prints the state of the cell at `row',`col' to stdout. If it's alive, it prints a '#'.
        // Otherwise, it prints a `-'.
        void print(int row, int col);
        // Prints a 2d grid representing the state of the entire Game of Life world to stdout.
        // If a cell is alive, it prints a `#'; otherwise, it prints a `-'.
        void print();
        // Returns the number of rows in the World Model.
        int getRowCount(void);
       // Returns the number of columns in the World Model.
        int getColCount(void);
        // Returns a pointer to the cell at (`row', `col').
        Cell* getCell(int row, int col);
       // Initializes the grid. Cells are randomly selected to be either alive or dead.
        void initialize(void);
        // Applies the Game of Life rules to the current generation of cells, and updates
        // the cells.
        void evolve(void);
       // Returns the number of generations that have passed.
        long getGenerationCount() { return m_generationCount; }
        // Assigns/attaches/registers (whatever word you like) a View object to this model.
        void setView( View* v );
    private:
        // Copies the states of Cells in `m_nextData' to the current generation of Cells in
        // `m_data'.
        void updateGeneration();
        // Returns the array index corresponding to the cell located at row `row' and column `col'.
        // Recall that `m_data' and `m_nextData' are really 1d arrays, but the client thinks that this
        // object is maintaining a 2d grid!
        // A "helper function".
        int computeArrayIndex(int row, int col);
        // This function should be called whenever the state of this model object is changed. For example,
        // if the model is "evolved" one iteration, its associated View object needs to be updated.
        // When this member function is called, the View object associated with this model is notified
        // that a change has occurred and that it has to redraw its "view" of the model on the screen.
        void notifyView(void);
        // returns the Cell at row `row' and column `col' in `m_nextData'.
        // A "helper function".
        Cell* getNextDataCell(int row, int col);
    private:
        // The number of generations that have passed.
        long m_generationCount;

       // The number of rows.
        int m_rowCount;

        // The number of columns.
        int m_colCount;

       /** the 2d grid is implemented as a 1d array of pointers to Cell objects **/
        // the Cells of the current generation.
        Cell** m_data;
        // the Cells of the next generation.
        Cell** m_nextData;
        // a pointer to this WorldModel's associated View object. The View object is responsible for drawing
        // the portion of the Game of Life grid in its Drawing Area. When a WorldModel object is changed
        // (say, if the client calls evolve()), then this View object needs to be notified of the change
        // so that it knows to redraw the screen to reflect the new change.
        // The View object should have this WorldModel object as its associated World Model, too.
        View* m_pView;
    };

    };

    头文件"WorldModel.h"算法:"WorldModel.cpp"

    #include "WorldModel.h"
    #include "Cell.h"

    using namespace game;

    WorldModel::WorldModel(int rows, int cols) :
       // Initialize `generationCount'.
        m_generationCount(0),
        // Initialize pointers.
        m_data(NULL),
        m_nextData(NULL),
        m_pView(NULL), // add a `,' when you make the change below.
        // Assign `rows' to `m_rowCount'.
        m_rowCount(rows),
        // Assign `cols' to `m_colCount'.
        m_colCount(cols)
    {
        assert( 0 < rows && rows < MAX_ROWS );
        assert( 0 < cols && cols < MAX_COLS );

        // Allocate memory for an array `m_data' of pointers to Cell objects of size `rows*cols'.
        m_data = new Cell* [rows*cols];
        // Allocate memory for an array `m_nextData' of pointers to Cell objects of size `rows*cols'.
        m_nextData = new Cell* [rows*cols];
        // Add `rows*cols' Cell objects for both `m_data' and `m_nextData', all of which are `false'.
        for (int i = 0; i<rows*cols; i++)
        {
            m_data[i] = new Cell;
            m_nextData[i] = new Cell;
            m_data[i]->setAlive(false);
            m_nextData[i]->setAlive(false);
        }
    }

    WorldModel::~WorldModel(void)
    {
        // YOU MUST ALWAYS `DELETE' WHAT YOU `NEW'
        // deallocate each Cell object in both `m_data' and `m_nextData' using the `delete' operator.
        int rbc = m_rowCount*m_colCount;
        for (int j = 0; j<rbc; j++)
        {
            delete m_data[j];
            delete m_nextData[j];
        }
       // deallocate the arrays `m_data' and `m_nextData' using the `delete[]' operator.
        delete [] m_data;
        delete [] m_nextData;
    }

    void WorldModel::setView( View* v )
    {
        // precondition: `v' is a valid object
        assert( v != NULL );

        m_pView = v;

        // postcondition: m_pView now points to `v'.
        assert( m_pView == v );
    }

    int WorldModel::computeArrayIndex(int row, int col)
    {
        int index;

        // PART B

        // If row is not in between 0 and `m_rows', change its value so that
        // it "wraps around" to the other side of the column. E.G. If `row' == -1,
        // then `row' should be set to m_rows. If `row' == -10, then `row'
        // should be set to `m_rows` - 10. If `row' == 3*m_rows + 5, then `row'
        // should be set to 5.
        while (row < 0 || row >= m_rowCount)
        {
           if (row >= m_rowCount)
               row = row - m_rowCount;
           while (row < 0)
           {
               row = row + m_rowCount;
               continue;
           }
           continue;
        }
        // We also need to do the same sort of thing for `col', except that we
        // need to "wrap it around" to the other side of the row.
        while (col< 0 || col >= m_colCount)
        {
           if (col >= m_colCount)
               col = col - m_colCount;
           while (col < 0)
           {
               col = col+ m_colCount;
               continue;
           }
           continue;
        }
        // PART C

        // Use `row' and `column' to compute the index of the corresponding bool
        // in the vector `m_vector'. Hint: how many cells are there between
        // cell (i,j) and cell (i,j+1) in the 1D array? Draw it out on a piece of paper
        // to think about it more concretely.

        index = row*m_colCount + col;
        return index;
    }

    void WorldModel::print(int row, int col)
    {
        cout << (getCell( row, col )->isAlive() ? "#" : "-") ;
    }

    void WorldModel::print()
    {
        for( int i=0; i<getRowCount(); i++ )
        {
            for( int j=0; j<getColCount(); j++ )
            {
                print(i,j);
            }
            cout << endl;
        }
    }

    int WorldModel::getRowCount(void)
    {
        return m_rowCount;
    }

    int WorldModel::getColCount(void)
    {
        return m_colCount;
    }

    Cell* WorldModel::getCell(int row, int col)
    {
        assert( m_data != NULL );

        int index = computeArrayIndex(row,col);
        if (m_data[index] != NULL)
            return m_data[index];
        else
        return NULL;
    }

    Cell* WorldModel::getNextDataCell(int row, int col)
    {
        // hint: this function is like above.
        assert( m_nextData != NULL );

        int index = computeArrayIndex(row,col);
        if (m_nextData[index] != NULL)
            return m_nextData[index];
        else
        return NULL;
    }

    void WorldModel::initialize(void)
    {
        // Make the pseudorandom number generator below
        // always generate exactly the same sequence of
        // random numbers on every run.
        srand(1);

        // "Randomly" set some Cells as alive.
        for( int i=0; i< m_rowCount * m_colCount; i++ )
            m_data[i]->setAlive( rand() > RAND_MAX/2.0 );
    }

    void WorldModel::updateGeneration()
    {
        // Make next generation the new current generation.
        for( int i=0; i<m_rowCount*m_colCount; i++ )
        {
            // Get the state of each cell in the nextData array and
            // set its corresponding cell in the data array to this same
            // state.
            m_data[i]->setAlive( m_nextData[i]->isAlive() );
        }

        // We've just advanced the World by one generation.
        m_generationCount++;
    }

    void WorldModel::evolve(void)
    {
        for( int row=0; row<m_rowCount; row++ )
        {
            for( int col=0; col<m_colCount; col++ )
            {
                // (Keep these)
                int neighborCount = 0;
                Cell* cell = getCell(row,col);
                Cell* nextDataCell = getNextDataCell(row,col);

                // make `neighborCount' equal the number of this cell's
                // neighbors that are alive.
                if (cell->isAlive())
                {
                    for (int i=row-1; i<row+2;i++)
                    {
                        for (int j=col-1; j<col+2; j++)
                        {
                            Cell* cellTwo = getCell(i,j);
                            if (cellTwo->isAlive())
                                neighborCount++;
                        }
                    }
                    neighborCount = neighborCount - 1;
                }
                else
                {
                    for (int i=row-1; i<row+2;i++)
                    {
                        for (int j=col-1; j<col+2; j++)
                        {
                            Cell* cellTwo = getCell(i,j);
                            if (cellTwo->isAlive())
                                neighborCount++;
                        }
                    }
                }
                // 0. By default, we assume that a cell's state is unchanged.
                nextDataCell->setAlive( cell->isAlive() );
                // 1. Any living cell with fewer than two living neighbours dies, as if by loneliness.
                if (neighborCount < 2)
                    nextDataCell->setAlive(false);
                // 2. Any living cell with more than three living neighbours dies, as if by overcrowding.
                else if (neighborCount > 3)
                    nextDataCell->setAlive(false);
               // 3. Any living cell with two or three neighbours continues to live, unchanged, to the next generation.
                // 4. Any dead cell with exactly three living neighbours comes to life.
                else if (neighborCount == 3)
                    nextDataCell->setAlive(true);
            }
        }

        // make the next generation the new current generation
        updateGeneration();
        // notify the view that it's time to redraw the screen.
        notifyView();
    }

    void game::WorldModel::notifyView()
    {
       // if there is no View object, then just do nothing.
        if( m_pView == NULL )
            return;
        // tell the View object to re-draw the screen.
        m_pView->draw();
    }