通信科技/NEWS CENTER

用 C#.NET 编写的一个完整字谜游戏

发布时间:2017-12-30

  用C#.NET编写的完整填字游戏

  [每日科技网]纵横字谜游戏,您可能已经看过很多益智书。试图在您的计算机上编写不同类型的内容难题游戏,并有自定义的单词玩也很有趣。背景我很久以前就使用Turbo C编码游戏,但是我遗失了我的代码。我认为用C#.NET重振它将是一件好事。这种语言在内存,GC,图形方面提供了很大的灵活性,这些是使用C语言时必须小心的事情。但是在C中有一个清晰的焦点允许我们学习很多(这就是为什么C被称为上帝的编程语言)另一方面,因为C#.NET关心这些,我可以专注于其他地方的增强,比如因为这是一个单词的定位,重叠,作弊码,计分,加密等等,所以在这两种语言的欣赏中需要有一个平衡点,在标题中我说这是完整的,原因如下:1)几个介词类别; 2)把文字和分数保存在一个加密的文件中,所以没有人可以篡改文件;如果被篡改,将会恢复到默认值,从头开始打分; 3)有一个作弊码, 4)它有一个评分机制,使用代码游戏提供了以下功能,我将在后面的章节中讨论:1)加载类别和单词:在程序中加载来自硬编码预设的单词。但是,如果玩家提供了一个自定义单词,游戏会自动将所有这些(连同预设)存储在文件中并从那里读取。 2)在网格上:游戏将所有的单词随机放置在18×18矩阵中。方向可以是水平,垂直,左下和右下,如上图所示。 3)评分:对于不同的类别,评分是分开存储的。得分是通过乘以乘数(这里是10)来计算的。同时,在找到所有单词后,将剩余时间(乘以乘数)加到分数上。 4)显示隐藏的单词:如果玩家在时间耗尽后仍然无法找到所有单词,游戏将显示不能以不同颜色显示的单词。 5)作弊码:游戏板中提​​到的游戏作弊码(mambazamba)。作弊码只需设置一天的时间(86,400秒)。但是,应用一个作弊代码也可以将这个运行归零。 1)加载类别和单词:加载预设我们有一个简单的课程举行类别和单词:classWordEntity {publicstringCategory {public; set;} publicstringWord {get;设置;}}我们有一些默认的类别和单词如下。预设是流水线式的,每个第15个单词是一个类别名称,下面的单词是该类别中的单词。 privatestringPRESET_WORDS = COUNTRIES 孟加拉国甘比亚澳大利亚英格兰尼泊尔印度巴基斯坦坦桑尼亚斯里兰卡中国加拿大日本巴西阿根廷音乐粉红金属铁元素NOVA ARTCELL FEEDBACK ORTHOHIN DEFLEPPARD BEATLES ADAMS 杰克逊 PARTON 休斯敦 SHAKIRA + ...我们使用加密在文件中写入这些单词。所以没有人可以篡改文件。为了加密,我使用这里的一个班来学习。易于使用您需要传递字符串和加密的密码进行加密。对于解密,您需要传递加密的字符串和密码。如果文件存在,我们从那里读取类别和单词,或者我们将保存预设(和玩家定义的单词)并从预设中读取。这是在下面的代码中完成的:if(File.Exists(FILE_NAME_FOR_STORING_WORDS))//如果单词文件存在,那么读它.ReadFromFile(); else {//否则创建文件并从那里填充。stringEncryptedWords = StringCipher.Encrypt(PRESET_WORDS,ENCRYPTION_PASSWORD);使用(StreamWriter OutputFile = newStreamWriter(FILE_NAME_FOR_STORING_WORDS))OutputFile.Write(EncryptedWords); ReadFromFile();} ReadFromFile()方法只读取存储单词的文件。它首先尝试解密从文件中读取的字符串。如果失败(由返回的空白字符串确定),则显示有关该问题的消息,然后从内置预置重新加载。否则,它会从字符串中读取,并将它们分类成不同的类别和单词,并将它们放在单词列表中。每个第15个单词是一个类别,下面的单词是该类别下的单词。 (DecryptedWords [0] .Equals())//这意味着文件被篡改。 stringStr = File.ReadAllText(FILE_NAME_FOR_STORING_WORDS); string [] DecryptedWords = StringCipher.Decrypt(Str,ENCRYPTION_PASSWORD).Split(“”); File.Delete(FILE_NAME_FOR_STORING_WORDS); PopulateCategoriesAndWords(); //循环reference.return;} stringCategory = for(inti = 0; i = DecryptedWords.GetUpperBound(0); i ++){if(i%(MAX_WORDS + 1)== 0)//每个第15个单词都是类别名称{Category = DecryptedWords [i]; Categories.Add(Category );} else {WordEntity Word = newWordEntity(); Word.Category = Category; Word.Word = DecryptedWords [i]; WordsList.Add(Word);}}保留一个播放器的自定义单词游戏播放器设备位于同一个加载窗口中,长度至少为3个字符,长度不超过10个字符,需要14个字符很少或不显示,例如JAPAN和JAPANESE,因为前者包含在后者中,所以我将简要地描述一下有效性检查。关于长度,最小长度和SP有三个陈述ACE输入(不允许空格)。这是通过将我们的自定义处理程序Control_KeyPress添加到单词输入网格的EditingControlShowingevent来完成的。 privatevoidWordsDataGridView_EditingControlShowing(objectsender,DataGridViewEditingControlShowingEventArgs e){e.Control.KeyPress - = newKeyPressEventHandler(Control_KeyPress); e.Control.KeyPress + = newKeyPressEventHandler(Control_KeyPress);}每次用户输入内容时,都会调用处理程序,并检查其有效性。完成如下:TextBox tb = sender asTextBox;如果(e.KeyChar ==(char)Keys.Enter){if(tb.Text.Length = MIN_LENGTH)//检查长度{MessageBox.Show(单词至少应为+ MAX_LENGTH +字符长e.Handled = true ; return;}} if(tb.Text.Length = MAX_LENGTH)//检查长度{MessageBox.Show(字长不能超过+ MAX_LENGTH +。e.Handled = true; return; if(e.KeyChar.Equals (“”))//检查空间;不允许空间其他无效的字符检查可以在这里,而不是最后的检查保存按钮点击{MessageBox.Show(没有空间请e.Handled = true;返回;)e .KeyChar = char.ToUpper(e.KeyChar);最后在输入完所有单词后,用户选择保存并使用自定义单词,进行有效性检查,首先检查是否有14个单词,然后遍历全部14个并检查是否有无效的字符,并检查是否有重复的单词。如果检查成功,则将单词添加到列表中。最后,提交另一个迭代检查单词不要包含在另一个单词中(例如,不能有两个单词,如JAPAN和JAPANESE,因为前者包含在后者中。)通过以下代码:publicboolCheckUserInputValidity(DataGridView WordsDataGridView,List WordsByThePlayer){if(WordsDataGridView.Rows.Count! = MAX_WORDS + 1){MessageBox.Show(您需要+ MAX_WORDS +单词在列表中,请添加更多。Returnfalse;} char [] NoLettersList = {“:”,“;”,“@”,“”, “”,“{”,“}”,“[”,“]”,“”,“”,“”,“。”,“”,“1”, “2”,“3”,“4”,“5”,“6”,“7”,“8”,“9”,“0”,“ - ”,“ “#”,“$”,“%”,“^”,“”,“*”,“}; //”foreach(DataGridViewRow Itm inWordsDataGridView.Rows){if(Itm.Cells [0] .Value == null)continue; if(Itm.Cells [0] .Value.ToString()。IndexOfAny(NoLettersList)= 0){MessageBox.Show(应该只包含字母,包含字母以外的字词是:“+ Itm .Cells [0] .Value.ToString()+“returnfalse;} if(WordsByThePlayer.IndexOf(Itm。Cells [0] .Value.ToString())!= -1){MessageBox.Show(不能重复重复的单词是:“+ Itm.Cells [0] .Value.ToString()+ {returnfalse;} WordsByThePlayer.Add(Itm.Cells [0] .Value.ToString());} for inti = 0; i WordsByThePlayer.Count - 1; i ++)//对于列表中的每个单词。 {stringstr = WordsByThePlayer [i];对于(intj = i + 1; j WordsByThePlayer.Count; j ++)//检查是否存在与从下一个单词开始的每一个单词(str.IndexOf(WordsByThePlayer [j])!= -1){MessageBox.Show这样的单词是:+ WordsByThePlayer [i] +“和”+ WordsByThePlayer [j] +“returnfalse;}} returntrue;}玩家列表现有的单词2)放置在网格上:在网格上放置单词单词通过InitializeBoard()方法放置在网格上,我们首先放置单词WORDS_IN_BOARD在字符矩阵(字符的二维阵列)中,然后我们将这个矩阵映射到网格中,遍历所有的字,每个字随机的方向随机(水平/垂直/左下/右下)。这一点,如果我们想象这个词的矩阵看起来有点像这个。用PlaceTheWords()方法来完成,得到四个参数word可怕字,字本身,X坐标和Y坐标。这是一个关键的方法,所以我会一一解释这四个方向。按循环水平运行字符。首先检查单词是否落在网格之外。如果这是真的,那么它返回到调用过程来产生一个新的随机位置和方向。然后,它检查当前字符是否可能与网格上的现有字符重叠。如果发生这种情况,那么检查它是否是相同的字符。如果不是相同的字符,则返回到调用方法,请求另一个随机的位置和方向。在两次检查之后,如果放置是可能的,则将该单词放在矩阵中,并使用StoreWordPosition()方法将位置和方向存储在WordPositions中的列表中。 (inti = 0,j = PlacementIndex_X; i Word.Length; i ++,j ++)//首先我们检查这个单词是否可以放在数组中。为此,它需要空白。 {if(j = GridSize)returnfalse; (如果WORDS_IN_BOARD [j,PlacementIndex_Y]!= Word [i])//如果有重叠,那么我们看看这些字符是否匹配。如果匹配,那么它仍然可以去那里。 {PlaceAvailable = false; (Word,PlacementIndex_X,PlacementIndex_Y,OrientationDecision(Word); WORDS_IN_BOARD [j,PlacementIndex_Y] = Word();}如果(PlaceAvailable){//如果所有的单元格都是空白的,或者一个非冲突的重叠可用,那么这个iWordPosition [i]; StoreWordPosition(Word,PlacementIndex_X,PlacementIndex_Y,OrientationDecision); returntrue;} break;垂直/左下/右下相同的逻辑适用于这三个方向的单词的良好布局,它们在矩阵/边界检查增量/减量当所有的单词放在矩阵中后,FillInTheGaps()方法用随机字母填充矩阵的其余部分,表单打开,Paint()事件被触发,在这个事件中,最后显示为40个40像素的矩形,然后我们将我们的字符矩阵映射到棋盘上。线笔Pen = newPen(Color.FromArgb(255,0,0,0)(inti = 0; i = GridSize; (笔,40,(i + 1)* 40,GridSize * 40 + 40,(i + 1)* 40); e.Graphics.DrawLine //绘制垂直线.for(inti = 0; i = GridSize; i ++)e.Graphics.DrawLine(pen,(i + 1)* 40,40,(i + 1)* 40,GridSize * 40+ 40); MapArrayToGameBoard MapArrayToGameBoard()方法只是将我们的字符矩阵放在板上。我们使用MSDN的绘图代码。这遍历矩阵中的所有字符,将它们放置在40 40个矩形的中间,边缘调整为10像素。 (intti = 0; j GridSize; j ++){if(WORDS_IN_BOARD [i,j]!=“0”){CharacterToMap = + WORDS_IN_BOARD [i,j] ; //需要作为字符转换为string.formGraphics.DrawString(CharacterToMap,drawFont,drawBrush,(i + 1)* 40 + 10,(j + 1)* 40+ 10);}} Word发现和有效性检查鼠标点击位置和释放位置存储在点列表中。在鼠标按钮释放事件(GameBoard_MouseUp())上调用CheckValidity()方法。同时,当用户拖住鼠标的同时按住左键,我们从起始位置画一条线到鼠标指针。这是在GameBoard_MouseMove()事件中完成的。 if(Points.Count 1)Points.Pop();如果(Points.Count 0)Points.Push(e.Location); //顶部= X =距离顶部,左= Y =左边的距离//鼠标的位置X =左边的距离,Y =顶部的距离//需要调整以确定位置。 Point TopLeft = newPoint(Top,Left); Point DrawFrom = newPoint(TopLeft.Y + Points.ToArray()[0] .X + 10,TopLeft.X + Points.ToArray()[0] .Y + 80); Point DrawTo = newPoint(TopLeft.Y + Points.ToArray()[1] .X + 10,TopLeft.X + Points.ToArray()[1] .Y +80); ControlPaint.DrawReversibleLine(DrawFrom,DrawTo,Color.Black); //绘制新行在CheckValidity()方法中检查单词的有效性。它抓住所有的字母来制作这个单词,用鼠标绘制字母来查看相应的字符矩阵。然后检查它是否真的匹配单词列表中的单词。如果匹配,则通过将单元格着色为浅蓝色并在单词列表中使单词灰白化来更新单元格。以下是代码片段的开头和结尾的片段。首先检查线是否超出界限。然后制定词汇并存储矩阵的坐标。同样,它检查垂直,左下角和右下角的单词,并试图相应匹配。如果这真的匹配,那么我们使用AddCoordinates()方法将临时矩形存储在ColouredRectangles点列表中。如果(Points.Count == 1)返回; //这是一个doble点击,没有拖动,因此return.intStartX = Points.ToArray()[1] .X / 40; //检索行的起始位置。 intStartY = Points.ToArray()[1] .Y / 40; intEndX = Points.ToArray()[0] .X / 40;如果(StartX GridSize EndX GridSize StartY GridSize EndY GridSize //边界检查.StartX = 0 EndX = 0 StartY = 0 EndY = 0){StatusLabel。 (); String();开始(EndY)//水平线drawn.for(inti = 0)TextWordIntection.Clear();文字=没有! StatusTimer.Start();返回;} StringBuilder TheWordIntended = newStringBuilder(); List TempRectangles = newList StartX; i = EndX; (TheWordIntended.Append(WORDS_IN_BOARD [i - 1,StartY-1] .ToString()); TempRectangles.Add(newPoint(i * 40,StartY * 40));} 3):对于得分,我们有评分文件。如果缺少,请使用当前分数和类别创建一个。在这里,所有的分数再次被合并在一个大的,以管道分隔的字符串中,然后被加密并放入一个文件中。我们有四个实体。 classScoreEntity {publicstringCategory {get;设置;} publicstringScorer {get;设置;} publicintScore {get;设置;} publicDateTime ScoreTime {获取;设置;} ................... .........高达14分的类别。首先加载得分列表中的所有得分,然后获得当前排序得分的排序子集。在这个子集中,检查当前得分是否大于任何可用得分。如果是,插入当前分数。之后,检查子集数量是否超过14个,如果超过,则删除最后一个子集。所以最后的分数消失了,名单总是有14个分数。这是在CheckAndSaveIfTopScore()方法中完成的。在这里,再次,如果有人篡改了分数文件,它只会启动一个新的。不要让篡改。 4)显示隐藏的单词:如果时间用完,游戏将以绿色显示单词。首先,得到玩家找不到的单词。 (Word)== -1)FailedWords.Add(Word);然后,遍历这些失败的单词位置并制定相应的失败矩阵。 foreach(StringWord in FailedWords){WordPosition Pos = WordPositions.Find(p = p.Word.Equals(Word)); if(Pos.Direction == Direction.Horizo​​ntal )//水平字.for(inti = Pos.PlacementIndex_X + 1,j = Pos.PlacementIndex_Y + 1,k = 0; k Pos.Word.Length; i ++,k ++)FailedRectangles.Add(newPoint(i (40; j * 40)); elseif(PosDirection == Direction。Vertical)// Vertical word.for(inti = Pos.PlacementIndex_X + 1,j = Pos.PlacementIndex_Y + 1,k = 0; k Pos。 Word.Length; j ++,k ++)FailedRectangles.Add(newPoint(i * elsef(PosDirection == Direction.DownLeft)//向左向下word.for(inti = Pos.PlacementIndex_Y + 1,j = Pos .PlacementIndex_X + 1,k = 0; k Pos.Word。Else(PosDirection == Direction.DownRight)// Right right word.for(inti = Pos.PlacementIndex_X(Length * i,j ++,k ++ )FailedRectangles.Add + 1,j = Pos.PlacementIndex_Y + 1,k = 0; k Pos.Word.Length; i ++,j ++,k ++)FailedRectangles.Add(newPoint(i * 40,j * 40));}无效的作弊代码:这是一件小事。这对keyup事件起作用,它把所有击键都抓取到CheatCode变量。事实上,我们将游戏窗口中的玩家类型的击键合并,并查看代码是否与我们的CHEAT_CODE(曼巴桑巴)相匹配。例如,如果玩家按m和a,那么我们将它们保存在CheatCode变量中,因为ma(因为ma仍然匹配cheatcode模式)。同样,如果连续变量与CHEAT_CODE的模式匹配,则添加连续变量。但是,一旦它不能匹配模式(例如,曼比),它会重新开始。最后,如果他们匹配,作弊代码被激活(剩余时间增加到86,400秒),并受到处罚。作弊码不匹配任何部分的作弊码。CheckCode =(+ e.KeyCode ToUpper(); //因此擦除它开始over.elseif(CheatCode.Equals(CHEAT_CODE)WORDS_FOUND。Count!= MAX_WORDS){ Clock.TimeLeft = 86400; / /应用作弊码,从字面上无限的时间86400秒等于这里有趣的是,我们必须使用WordsListView的KeyUp事件,而不是形式这是因为列表框有焦点,而不是表格,在加载游戏窗口之后,环境使用Visual Studio 2015IDE编码,这不是一个需要PC来玩这个游戏的移动版本免责声明这不是一个OOP项目,它遵循程序编程,虽然使用了OOP在一些地方,这个过程被委托给了类对象,这个项目是用RAD方法来完成的,它需要被重构,我没有遵循任何命名规则,我个人的偏好是名字告诉intent ,你可以自动理解徘徊在名称上的类型。我的观点是,变量TheWordIntended是基于一个标准的命名约定,我没有遵循应该有一个像strTheWordIntended这样的名字,这些都是可重构的。未来的工作对于应用程序设计模式OOP,您可以做许多事情。作为软件开发的本质,重构是必须的。窗口,我们需要调用窗口的Invalidate()方法,还需要通过调整窗体的顶部和左侧位置来调整鼠标坐标。有趣的是,表单的坐标定义为:X是屏幕顶部的距离,Y是屏幕左边的距离然而,鼠标坐标是用另一种方式定义的:X是左边的距离窗口和Y是到顶部的距离窗口。因此,为了校准,我们需要仔细调整。私人无效GameGoard_MouseMove(objectsender,MouseEventArgs e){尝试{if(e.Button == MouseButtons.Left){if(Points.Count 1)Points.Pop();如果(Points.Count 0)Points.Push(e.Location); // Form top = X =从左上方的距离,左= Y =从左边的距离。 //鼠标的位置X =从左边开始的距离,Y =从最上面开始的距离//需要进行调整来确定位置。Point TopLeft = PointDrawFrom = newPoint(TopLeft.Y + Points.ToArray()[0] .X + 10 ,TopLeft.X + Points.ToArray()[0] .Y + 80); Point DrawTo = newPoint(TopLeft.Y + Points.ToArray()[1] .X + 10,TopLeft.X + Points.ToArray()[1] .Y + 80); ControlPaint.DrawReversibleLine(DrawFrom,DrawTo,Color.Black); // draw new line}}缺陷如果机器有多个显示器,我发现一个小问题。如果游戏被加载到一个窗口中并被移动到另一个窗口中,则鼠标拖动将在第一个窗口上留下疤痕标记。不要惊慌,游戏关闭后会被删除,到目前为止还没有发现任何bug,如果发现bug,请留言,同时也欢迎提交您的意见总结这是一个字母益智游戏,预设单词,自定义单词和单词分类,请尝试!

伯莱娱乐

2017-12-30

更多内容,敬请关注:

伯莱娱乐官网:/

伯莱娱乐新浪官方微博:@伯莱娱乐

伯莱娱乐发布微信号: