仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3549|回复: 7
打印 上一主题 下一主题

[C++基础] 带来一篇C++ 很风趣:编写一个井字游戏 (Tic Tac Toe)

[复制链接]
逍遥一派 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-16 11:05:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
要明白学好linux不是一件一蹴而就的事,一定要能坚持使用它,特别是在使用初期。
  这个风趣的C++系列盘算展现一下利用C++写代码能够和其他支流言语一样高效而风趣。在第二部分,我将向你展现利用C++从无到有的创立一个井字游戏。这篇文章,和全部系列都是针对那些想进修C++大概对这个言语功能猎奇的开辟者。
  很多年老人想进修编程来写游戏。C++是用的最多的用来写游戏的言语,只管在写出下个恼怒的小鸟之前,必要学会良多的编程履历。一个井子游戏是入手下手进修的一个好选择,现实上,在很多年前我入手下手进修C++后,他是我写的地一个游戏。我但愿这篇文章能够匡助到那些还不熟习C++的初学者和有履历的开辟者。
  我利用的是VisualStudio2012来写这篇文章的源代码。
 游戏先容

  假如你没有玩过井字游戏大概其实不熟习这个游戏,上面是来自维基百科的形貌.
井字游戏(大概"圈圈和叉叉",XsandOs)是一个两人的纸笔游戏,两团体轮番在3X3的网格内画圈和叉.当一位玩家安排的标记在程度,垂直大概对角线上成一条线即取得成功.


  这个游戏也能够人机对战,先手不流动.
  创立这个程序的时分有2个关头的器材:程序的逻辑和程序的UI界面.有很多在windows中创立用户UI的办法,包含Win32API,MFC,ATL,GDI+,DirectX,etc.在这篇文章中,我将展现利用多种手艺来完成统一个程序逻辑.我们将新建2个使用,一个利用Win32API另外一个利用C++/CX.
  游戏逻辑

  假如一个玩家在网格上放下一个标志时,遵守几个复杂的划定规矩,那他就能够玩一个完善的游戏(意味着赢大概平手)。在Wikipedia上写有这些划定规矩,在内里你也能够找到先手玩家的最优战略。


  在xkcddrawing上有先手和先手玩家的最优战略。只管有几个毛病(在几种情形下没有走必胜的步骤,最少在一个情形下丧失了一个X标志),我将利用这个版本作为游戏战略(修复了那些我能找到的毛病)。记着电脑老是玩一个完善的游戏。假如你完成了如许一个游戏,你大概也想让用户赢,这类情形下你必要一个分歧的办法。当对本文的目标,这个战略应当充足了。
  提出的第一个成绩是在C++程序顶用甚么数据布局来暗示图象的模子。这能够有分歧的选择,好比树、图、数组大概位字段(假如真有人对内存损耗很在乎)。网格有9个单位,我选择的最复杂的利用对每一个单位利用一个包括9个整数的数组:0暗示空的单位,1暗示单位被标志为X,2暗示单位被标志为O。让我们看下图和它将被怎样编码。


  这幅图能够这么了解:


  • 在单位(0,0)放X。网格能够编码为:1,0,0,0,0,0,0,0,0
  • 假如敌手在单位(0,1)安排O,那末在单位(1,1)安排X。如今网格编码为:1,2,0,0,1,0,0,0,0
  • 假如敌手在单位(0,2)安排O,那末在单位(2,2)安排X。如今网格编码为:1,2,2,0,1,0,0,0,1
  • ...
  • 假如敌手在单位(2,2)安排O,那末在单位(2,0)安排X。如今网格编码为:1,2,0,0,1,0,1,0,2。这时候,不管敌手怎样做,X都将博得竞赛。
  • 假如敌手在单位(0,2)安排O,那末在单位(1,0)安排X。如今网格编码为:1,2,2,1,1,0,1,0,2。这暗示的是一个博得竞赛的一步。
  • ...
  记着这个我们就能够入手下手在程序中对其编码了。我们将利用一个std::array来暗示一个9格板。这是个流动巨细的容器,在编译时就已知的巨细,在一连的内存地区存储元素。为了不一遍又一遍的利用不异数组范例,我将界说一一般名来简化。
  1. #include<array>typedefstd::array<char,9>tictactoe_status;
复制代码
  下面形貌的最优战略用如许的数组行列(另外一个数组)来暗示。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};
复制代码
  strategy_x是先手玩家的最优战略,strategy_o是先手玩家的最优战略。假如你看了文中的源代码,你将注重到这两个数组的实在界说和我后面展现的分歧。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};
复制代码
  这是个小技能,我的来由是,它同意我们把实在的很长的数组内容放在分隔的文件中(这些文件的扩大性不主要,它能够不单单是C++头文件,也能够是其他任何文件),包管源码文件和界说复杂洁净。strategy_x.h和strategy_o.h文件在编译的预处置阶段就被拔出到源码文件中,好像一般的头文件一样。上面是strategy_x.h文件的片段。
  1. //http://imgs.xkcd.com/comics/tic_tac_toe_large.png//similarversiononhttp://upload.wikimedia.org/wikipedia/commons/d/de/Tictactoe-X.svg//1=X,2=O,0=unoccupied1,0,0,0,0,0,0,0,0,1,2,0,0,1,0,0,0,0,1,2,2,0,1,0,0,0,1,1,2,0,2,1,0,0,0,1,1,2,0,0,1,2,0,0,1,
复制代码
  你应当注重到,假如你利用撑持C++11的编译器,你可使用一个std::vector而不是C范例的数组。VisualStudio2012不撑持这么做,但在VisualStudio2013中撑持。
  1. std::vector<tictactoe_status>strategy_o={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},{2,2,1,1,1,0,2,0,0},};
复制代码
  为了界说这些数字暗示的对应玩家,我界说了一个叫做tictactoe_player的列举范例变量。
  1. enumclasstictactoe_player:char{none=0,computer=1,user=2,};
复制代码
  游戏的逻辑部分将会在被称之为tictactoe_game的类中完成。最基础的,这个class应当有上面的形态:


  • 一个布尔值用来暗示游戏是不是入手下手了,定名为started。
  • 游戏确当前形态(网格上的标志),定名为status。
  • 依据以后的形态失掉的以后能够举行的下法的汇合,定名为strategy
  1. classtictactoe_game{boolstarted;tictactoe_statusstatus;std::set<tictactoe_status>strategy;//...};
复制代码
  在游戏的过程当中,我们必要晓得游戏是不是入手下手了、停止了,假如停止了,必要判断是不是有哪一个玩家赢了大概终极两团体打平。为此,tictactoe_game类供应了三个办法:


  • is_started()来暗示游戏是不是入手下手了
  • is_victory()来反省是不是有哪位玩家在游戏中得胜
  • is_finished()来反省游戏是不是停止。当个中某位玩家在游戏中得胜大概当网格被填满玩家不克不及再下任何的棋子的时分,游戏停止。
  1. boolis_started()const{returnstarted;}boolis_victory(tictactoe_playerconstplayer)const{returnis_winning(status,player);}boolis_finished()const{
复制代码
  关于办法is_victory()和is_finished(),实践上是依附于两个公有的办法,is_full(),用来暗示网格是不是被填满而且不克不及再放下任何的棋子,和办法is_winning,用来暗示在该网格上是不是有某玩家胜出。它们的完成将会很简单被读懂。is_full经由过程盘算网格中空的(在暗示网格的数组中值为0)格子的数目,假如没有如许的格子那末将前往true。is_winning将会反省这些连线,网格的行、列、和对角线,依此来检察是不是有哪位玩家已得胜。
  1. boolis_winning(tictactoe_statusconst&status,tictactoe_playerconstplayer)const{automark=static_cast<char>(player);return(status[0]==mark&&status[1]==mark&&status[2]==mark)||(status[3]==mark&&status[4]==mark&&status[5]==mark)||(status[6]==mark&&status[7]==mark&&status[8]==mark)||(status[0]==mark&&status[4]==mark&&status[8]==mark)||(status[2]==mark&&status[4]==mark&&status[6]==mark)||(status[0]==mark&&status[3]==mark&&status[6]==mark)||(status[1]==mark&&status[4]==mark&&status[7]==mark)||(status[2]==mark&&status[5]==mark&&status[8]==mark);}boolis_full(tictactoe_statusconst&status)const{return0==std::count_if(std::begin(status),std::end(status),[](intconstmark){returnmark==0;});}
复制代码
  当一个玩家得胜的时分,我们想给他所连成的线(行、列、大概对角线)上画一条夺目的线段。因而起首我们得晓得那条线使得玩家得胜。我们利用了办法get_winning_line()来前往一对tictactoe_cell,用来暗示线段的两头。它的完成和is_winning很类似,它反省行、列和对角线上的形态。它大概会看起来有点冗杂,可是我信任这个办法比利用轮回来遍历行、列、对角线加倍复杂。
  1. structtictactoe_cell{introw;intcol;tictactoe_cell(intr=INT_MAX,intc=INT_MAX):row(r),col(c){}boolis_valid()const{returnrow!=INT_MAX&&col!=INT_MAX;}};std::pair<tictactoe_cell,tictactoe_cell>constget_winning_line()const{automark=static_cast<char>(tictactoe_player::none);if(is_victory(tictactoe_player::computer))mark=static_cast<char>(tictactoe_player::computer);elseif(is_victory(tictactoe_player::user))mark=static_cast<char>(tictactoe_player::user);if(mark!=0){if(status[0]==mark&&status[1]==mark&&status[2]==mark)returnstd::make_pair(tictactoe_cell(0,0),tictactoe_cell(0,2));if(status[3]==mark&&status[4]==mark&&status[5]==mark)returnstd::make_pair(tictactoe_cell(1,0),tictactoe_cell(1,2));if(status[6]==mark&&status[7]==mark&&status[8]==mark)returnstd::make_pair(tictactoe_cell(2,0),tictactoe_cell(2,2));if(status[0]==mark&&status[4]==mark&&status[8]==mark)returnstd::make_pair(tictactoe_cell(0,0),tictactoe_cell(2,2));if(status[2]==mark&&status[4]==mark&&status[6]==mark)returnstd::make_pair(tictactoe_cell(0,2),tictactoe_cell(2,0));if(status[0]==mark&&status[3]==mark&&status[6]==mark)returnstd::make_pair(tictactoe_cell(0,0),tictactoe_cell(2,0));if(status[1]==mark&&status[4]==mark&&status[7]==mark)returnstd::make_pair(tictactoe_cell(0,1),tictactoe_cell(2,1));if(status[2]==mark&&status[5]==mark&&status[8]==mark)returnstd::make_pair(tictactoe_cell(0,2),tictactoe_cell(2,2));}returnstd::make_pair(tictactoe_cell(),tictactoe_cell());}
复制代码
  如今我们只剩下增加入手下手游戏功效和为网格放上棋子功效(电脑和玩家二者).
  关于入手下手游戏,我们必要晓得,由谁入手下手下第一个棋子,因而我们能够接纳对照符合的战略(两种体例都必要供应,电脑先手大概玩家先手都要被撑持)。同时,我们也必要重置暗示网格的数组。办法start()对入手下手新游戏举行初始化。能够下的棋的战略的汇合被再一次的初始化,从stategy_x大概strategy_o举行拷贝。从上面的代码能够注重到,strategy是一个std::set,而且strategy_x大概strategy_o都是有反复单位的数组,由于在tictoctoe内外面的一些地位是反复的。这个std::set是一个只包括独一值的容器而且它包管了独一的大概的地位(比方关于strategy_o来讲,有一半是反复的)。<algorithm>中的std::copy算法在这里被用来举行数据单位的拷贝,将以后的内容拷贝到std::set中,而且利用办法assign()来将std::array的一切的元素重置为0。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};0
复制代码
  当玩家走一步时,我们必要做的是确保选择的网格是空的,并安排符合的标志。move()办法的吸收参数是网格的坐标、玩家的暗号,假如这一步无效时前往真,不然前往假。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};1
复制代码
  电脑走一步时必要更多的事情,由于我们必要找到电脑应当走的最好的下一步。重载的move()办法在大概的步骤(战略)汇合中查询,然后从当选择最好的一步。在走完这步后,会反省电脑是不是博得这场游戏,假如是的话标志游戏停止。这个办法前往电脑走下一步的地位。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};2
复制代码
  lookup_strategy()办法在以后大概的挪动地位中迭代,来找到从以后地位往那里挪动是可行的。它使用了如许的一种现实,空的网格以0来暗示,任何已填过的网格,不是用1就是用2暗示,而这两个值都年夜于0。一个网格的值只能从0变成1大概2。不成能从1变成2或从2变成1。
  当游戏入手下手时的网格编码为0,0,0,0,0,0,0,0,0来暗示而且以后情形下任何的走法都是大概的。这也是为何我们要在thestart()办法里把全部步数都拷贝出来的缘故原由。一旦玩家走了一步,那能走的步数的set便会削减。举个例子,玩家在第一个格子里走了一步。此时网格编码为1,0,0,0,0,0,0,0,0。这时候在数组的第一个地位不成能再有0大概2的走法因而必要被过滤失落。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};3
复制代码
  在选择下一步时我们必要确保我们选择的走法必需与以后的标志分歧,假如以后的形态是1,2,0,0,0,0,0,0,0而我们如今要为玩家1选择走法那末我们能够从余下的7个数组单位当选择一个,能够是:1,2,1,0,0,0,0,0,0或1,2,0,1,0,0,0,0,0...或1,2,0,0,0,0,0,0,1。但是我们必要选择最优的走法而不是仅仅只任意走一步,一般最优的走法也是博得竞赛的关头。因而我们必要找一步能使我们走向成功,假如没有如许的一步,那就任意走吧。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};4
复制代码
  做完了这一步,我们的游戏的逻辑部分就完成了。更多细节请浏览game.hgame.cpp中的代码
 一个用Win32API完成的游戏

  我将用Win32API做用户界面来创立第一个使用程序。假如你不是很熟习Win32编程那末如今已有大批的资本你能够使用进修。为了使人人了解我们怎样创立一个终极的使用,我将只报告一些需要的方面。别的,我不会把每行代码都展示并注释给人人,可是你能够经由过程下载这些代码来浏览扫瞄它。
  一个最基础的Win32使用必要的一些内容:


  • 一个出口点,一般来讲是WinMain,而不是main。它必要一些参数比方以后使用实例的句柄,命令行和唆使窗口怎样展现的标记。
  • 一个窗口类,代表了创立一个窗口的模板。一个窗口类包括了一个为体系所用的属性汇合,比方类名,classstyle(分歧于窗口的作风),图标,菜单,背景刷,窗口的指针等。一个窗口类是历程公用的而且必需要注册到体系优先级中来创立一个窗口。利用RegisterClassEx来注册一个窗口类。
  • 一个主窗口,基于一个窗口类来创立。利用CreateWindowEx能够创立一个窗口。
  • 一个窗口历程函数,它是一个处置一切基于窗口类创立的窗口的动静的办法。一个窗口历程函数与窗口相联,可是它不是窗口。
  • 一个动静轮回。一个窗口经由过程两种体例来承受动静:经由过程SendMessage,间接挪用窗口历程函数直到窗口历程函数处置完动静以后才前往,大概经由过程PostMessage(或PostThreadMessage)把一个动静投送到创立窗口的线程的动静行列中而且不必守候线程处置间接前往。因而线程必需一向运转一个从动静行列吸收动静和把动静发送给窗口历程函数的轮回
  你能够在MSDN中找到关于Win32使用程序怎样注册窗口类、创立一个窗口、运转动静轮回的例子。一个Win32的使用程序看起来是如许的:
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};5
复制代码
  固然,这还不敷,我们还必要一个窗口历程函数来处置发送给窗口的动静,好比PAINT动静,DESTORY动静,菜单动静和别的的一些需要的动静。一个窗口历程函数看起来是如许的:
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};6
复制代码
  我更喜好写面向工具的代码,不喜好面向历程,以是我用几个类封装了窗口类、窗口和设备形貌表。你能够在附件的代码framework.hframework.cpp找到这些类的完成(它们十分玲珑)。


  • WindowClass类是对窗口类相干资本初始化的封装,在机关函数中,它初始化了WNDCLASSEX的布局而且挪用RegisterClassEx办法。在析构函数中,它经由过程挪用UnregisterClass移除窗口的注册。
  • Window类是经由过程对HWND封装一些诸如Create,ShowWindow和Invalidate的函数(它们的名字已告知了你他们是做甚么的)。它另有几个虚成员代表动静句柄,它们会被窗口历程挪用(OnPaint,OnMenuItemClicked,OnLeftButtonDown)。这个window类将会被承继来并供应详细的完成。
  • DeviceContex类是对设备形貌表(HDC)的封装。在机关函数中它挪用BeginPaint函数而且在析构函数中挪用EndPaint函数。
  这个游戏的次要窗口是TicTacToeWindow类,它是从Window类承继而来,它重载了假造办法来处置动静,该类的声明是如许的:
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};7
复制代码
  MethodOnPaint()函数用来绘制窗口,它用来绘制窗口背景,网格线,添补的单位格(假如有的话),假如在游戏停止,玩家赢了,一条红线在得胜行,列或对角线的标志。为了不闪灼,我们利用了双缓冲手艺:创立一个内存设备文本(经由过程挪用toBeginPaint函数筹办窗口的设备文原本婚配),一个内存中的位图婚配内存设备文本,绘制该位图,然后用窗口设备文原本复制内存设备文本。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};8
复制代码


  我不会在这里列出DrawBackground,DrawGridand和DrawMarksfunctions的内容。他们不是很庞大,你能够浏览源代码。DrawMarksfunction利用两个位图,ttt0.bmp和tttx.bmp,绘制网格的陈迹。



  我将只显现怎样在得胜行,列或对角线绘制红线。起首,我们要反省游戏是不是停止,假如停止那末检索得胜线。假如两头都无效,然后盘算该两个小区的中央,创立和选择一个画笔(实心,15像素宽的白色线)而且绘制两个小区的两头之间的线。
  1. tictactoe_statusconststrategy_x[]={{1,0,0,0,0,0,0,0,0},{1,2,0,0,1,0,0,0,0},{1,2,2,0,1,0,0,0,1},{1,2,0,2,1,0,0,0,1},//...};tictactoe_statusconststrategy_o[]={{2,0,0,0,1,0,0,0,0},{2,2,1,0,1,0,0,0,0},{2,2,1,2,1,0,1,0,0},{2,2,1,0,1,2,1,0,0},//...};9
复制代码
  主窗口有三个项目菜单,ID_GAME_STARTUSER在用户先挪动时启动一个游戏,ID_GAME_STARTCOMPUTER在当电脑先挪动时启动一个游戏,ID_GAME_EXIT用来封闭使用。当用户点击两个启动中的任何一个,我们就必需入手下手一个游戏义务。假如电脑先挪动,那末我们应当是不是挪动,而且,在一切情形中,都要从头绘制窗口。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};0
复制代码
  如今只剩下一件事了,就是寄望在我们的窗口中处置用户单击鼠标的举动。当用户在我们的窗口客户区内按下鼠标时,我们要往反省是鼠标按下的中央是在哪个网格内,假如这个网格是空的,那我们就把用户的标志添补上往。以后,假如游戏没有停止,就让电脑举行下一步的挪动。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};1
复制代码
  最初,我们必要完成WinMain函数,这是全部程序的出口点。上面的代码与这部分隔始我给出的代码十分类似,分歧的的地方是它利用了我对窗口和窗口类举行封装的一些类。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};2
复制代码
  固然我以为我放在这里的代码是相称的短小精焊,但假如你不熟习Win32API程序计划,你仍旧大概会以为这些代码有点庞大。不管怎样,你都必定要分明的懂得工具的初始化、怎样创立一个窗口、怎样处置窗口动静等。希望你会以为下一部分更风趣。
 一个WindowsRuntime的游戏app

  WindowsRuntime是Windows8引进的一个新的Windows运转时引擎.它依靠于Win32而且有一套基于COM的API.为WindowsRuntime创立的app一般很糟,被人称为"Windows商铺"使用.它们运转在WindowsRuntime上,而不是Windows商铺里,可是微软的市场营销职员大概已没甚么制造力了.WindowsRuntime使用和组件能够用C++完成,不论是用WindowsRuntimeC++TemplateLibrary(WTL)大概用C++ComponentExtensions(C++/CX)都能够.在这里我将利用XAML和C++/CX来创立一个功效上和我们之前完成的桌面版使用相似的使用。
  当你创立一个空的WindowsStoreXAML使用时导游创立的项目实践上并非空的,它包括了一切的WindowsStore使用构建和运转所必要的文件和设置。可是这个使用的mainpage是空的。
  我们要体贴对这篇文章的目标,独一的就是主界面。XAML代码能够在使用在文件MainPage.xaml中,和面前的MainPage.xaml.hMainPage.xaml.cpp的代码。,我想创建复杂的使用程序以下图。


  上面是XAML的页面大概看起来的模样(在一个实在的使用中,你大概要利用使用程序栏来操纵,如启动一个新的游戏,主页上没有按键,但为了复杂起见,我把它们在页面上)
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};3
复制代码
  与win32桌面版的游戏分歧,在WindowsRuntime的程序中,我们不用体贴用户界面的绘制,但我们还得创立UI元素。好比,当用户在玩游戏的时分,在个中一个格子里单击了鼠标,我们就必需创立一个UI元从来暗示一个标志。为此,我会用在桌面版(too.bmpandttx.bmp)顶用过的位图,而且在图象控件中显现它们.。我还会在得胜的行、列、或对角线上画一个白色的线,为此,我会用到Lineshape类。
  我们能够间接把tictactoe_game的源代码(game.h,game.cpp,strategy_x.handstrategy_o.h)增加到工程里。大概我们能够把它们导出成一个独自的DLL。为了便利,我利用了不异的源文件。然后我们必需增加一个tictactoe_game工具到MainPage类中。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};4
复制代码
  这里有3类基础的事务处置handler必要我们本人完成:


  • 处置“Startuser”按钮的theClickedevent事务的handler
  • 处置“Startcomputer”按钮的theClickedevent事务的handler
  • 处置面板网格的thePointerReleasedevent事务的handler,当指针(鼠标大概手势)从网格开释时被挪用。
  对这两个按钮点击的handler,在逻辑上与我们在Win32桌面使用中完成的相似。起首,我们必需要重置游戏(一会会看到这代表甚么意义)。假如玩家先入手下手,那末我们仅仅只必要用准确的战略来初始化游戏工具。假如是电脑先入手下手,那我们除要初始化战略,还要让电脑出现出真正走了一步而且在电脑走的那一步的单位格上做上标志。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};5
复制代码
  PlaceMark()办法创立了一个newImagecontrol控件,设定它的Source是tttx.bmp大概ttt0.bmp,而且把它增加到所走的那一步的面板网格上。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};6
复制代码
  当入手下手一场新游戏时,这些在游戏过程当中被增加到网格上的Imagecontrol控件必要被移撤除。这恰是theResetGame()method办法所做的事变。别的,它还移除游戏成功时显现的红线和显现游戏了局的笔墨。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};7
复制代码
  当玩家在一个单位格上点击了一下指针,而且这个单位格是没有被占有的,那我们就让他走这一步。假如这时候游戏还没有停止,那我们也让电脑走一步。当游戏在玩家大概电脑走过一步以后停止,我们会在一个textbox中显现了局而且假如有一方成功,会在成功的行,列或对角上划上红线。
  1. tictactoe_statusconststrategy_x[]={#include"strategy_x.h"};tictactoe_statusconststrategy_o[]={#include"strategy_o.h"};8
复制代码
  到这里就全体停止了,你能够build它了,启动它然后玩吧。它看起来像如许:


 总结

  在这篇文章中,我们已看到了,我们能够在C++中利用分歧的用户界面和利用分歧的手艺创立一个复杂的游戏。起首我们写游戏思绪是利用尺度的C++,来用它来构建利用完整分歧的手艺创立的两个使用程序:在这里我们不能不利用Win32API来做一些事情,好比创立一个绘制窗口,而且可以在运转时利用XAML。在那边,框架做了年夜部分的事情,以是我们能够专注于游戏逻辑(在前面的代码里我必需申明我们不能不往计划UI,而不单单利用XAML)。个中包含我们看到的怎样可以利用尺度的容器asstd::arrayandstd::setand,我们怎样利用纯C++逻辑代码在C++/CX中完善的运转。
  原文地点:http://www.codeproject.com/Articles/678078/Cplusplus-is-fun-Writing-a-Tic-Tac-Toe-Game
为什么我使用一个命令的时候,系统告诉我找不到该目录,我要如何限制使用者的权限等问题,这些问题其实都不是很难的。
小妖女 该用户已被删除
沙发
发表于 2015-1-18 07:47:34 | 只看该作者
天将降大任与斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,.......理解得人自然会在心中默念,不理解得会笑我土。
admin 该用户已被删除
板凳
发表于 2015-1-25 20:29:43 | 只看该作者
我也学习了几天VB,然后不敢示弱得心把我拉回去,也不知道怎么回事,有一天灵感光顾,就这样,轻松进门,只用了一周。以后学习数据库编程,Socket编程也遇到类似得情况,
山那边是海 该用户已被删除
地板
发表于 2015-2-4 02:39:33 | 只看该作者
类和数据抽类,是类的一些基本知识,这部分很好理解,知识点也不碎,从设计一个类开始,考虑需要哪些成员函数,理一理就清楚了。
蒙在股里 该用户已被删除
5#
发表于 2015-2-9 11:45:32 | 只看该作者
关于C++与C语言的规范化问题。众所周知,C++是从C语言发展而来的,所以在C++中就不可避免的夹杂些C留下来的糟粕(使用C语言的请见谅)。
再现理想 该用户已被删除
6#
发表于 2015-3-9 00:23:16 | 只看该作者
问问自己: 这个软件如果是你下载来的.想用.那应该是怎么样的?
灵魂腐蚀 该用户已被删除
7#
发表于 2015-3-16 20:54:17 | 只看该作者
关于C++与C语言的规范化问题。众所周知,C++是从C语言发展而来的,所以在C++中就不可避免的夹杂些C留下来的糟粕(使用C语言的请见谅)。
变相怪杰 该用户已被删除
8#
发表于 2015-3-23 04:50:12 | 只看该作者
不该让过渡时期的人感到很郁闷才是,所以所有高校都该停止开C语言课!哈哈!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-11-17 20:33

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表