[译]具有AI和网络支持的C#TicTacToe
By robot-v1.0
本文链接 https://www.kyfws.com/ai/c-tictactoe-with-ai-and-network-support-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 4 分钟阅读 - 1764 个词 阅读量 0具有AI和网络支持的C#TicTacToe(译文)
原文地址:https://www.codeproject.com/Articles/6574/C-TicTacToe-with-AI-and-network-support
原文作者:Daniel Carvalho Liedke
译文由本站 robot-v1.0 翻译
前言
A TicTacToe game written in C# with AI and network support
用C#编写的带有AI和网络支持的TicTacToe游戏
介绍(Introduction)
这是用C#编写的具有AI和网络支持的Tic Tac Toe游戏的示例.可以与计算机和其他玩家对战.与计算机对战时,难度分为三个等级.与其他播放器对战时,可以在本地或通过LAN或Internet进行对战(它使用TCP套接字进行通信).可以使用NumPad或QWE,ASD,ZXC键,通过鼠标或键盘进行控制.(This is an example of a Tic Tac Toe game with AI and network support, written in C#. It is possible to play against the computer and against another player. There are three levels of difficulty when playing against the computer. When playing against another player, it is possible to play local or over a LAN or Internet (it uses TCP sockets for communication). The control can be either by mouse or keyboard, using the NumPad or QWE, ASD, ZXC keys.)
人工智能支持(AI support)
我试图以最好的方式实现AI,即使代码很长也是如此.它首先尝试赢得比赛,阻止其他玩家获胜,然后尝试采取行动避免"陷阱"并将两台计算机连续放置.如果这一切都不可能,那么将进行随机移动,首先尝试在拐角处,然后在侧面.如果难度设置为"简单"或"平均",我不会每次都执行防御性移动例程来实现难度级别.(I tried to implement AI the best way I could, even with a long code. It tries to win the game at first, preventing the other player to win, and then tries to make a move avoiding “traps” and putting two computer pieces in a row. If none of this is possible, a random move is made, first trying on the corners and then on the sides. I implemented the level of difficulty by not processing the defensive move routine every time if the difficulty was set to easy or average.)
网络支持(Network support)
通过使用以下内容实现了对网络上的两人游戏的网络支持:(Network support for a two-player game over a network was implemented using) TcpListener
和(and) TcpClient
TCP套接字通信的类.通信协议非常简单,只有两个字节的数据包:第一个字节指示行,第二个字节指示列.还有一个带有第一个字节" R"的控制包,用于控制游戏的重启.客户端和服务器都可以随时重新启动游戏.(classes for TCP sockets communication. The protocol for communication is really simple, a two-bytes packet: first byte indicating the row and second byte indicating the column. There is also a control packet with the first byte ‘R’ that controls game restart. Both client and server can restart the game anytime.)
这是用于在服务器中接收数据的线程的代码片段:(Here is a code snippet of the thread for receiving data in the server:)
private void ThreadReceivingServer()
{
//________________________________________________________________________
//
// Thread for receiving packets from client
//________________________________________________________________________
try
{
byte[] buf = new byte[512];
IPHostEntry localHostEntry = Dns.GetHostByName(Dns.GetHostName());
int bytesReceived=0;
tcpListener = new TcpListener(localHostEntry.AddressList[0],SERVERPORT);
tcpListener.Start();
//____________________________________________________________________
//
// Thread is blocked until it gets a connection from client
//____________________________________________________________________
soTcpServer = tcpListener.AcceptSocket();
serverSockStream = new NetworkStream(soTcpServer);
objTicTacToe.RestartGame();
objTicTacToe.SetStatusMessage("Connected!");
wReceivingServer=true;
while (wReceivingServer)
{
//________________________________________________________________
//
// Thread is blocked until receives data
//________________________________________________________________
try
{
bytesReceived=serverSockStream.Read(buf,0,2);
}
catch
{
return;
}
//________________________________________________________________
//
// Processes network packet
//________________________________________________________________
if (bytesReceived>0)
{
//____________________________________________________________
//
// Control packet for game restart
//____________________________________________________________
if (buf[0]==byte.Parse(Asc("R").ToString()))
{
objTicTacToe.RestartGame();
continue;
}
//____________________________________________________________
//
// Packet indicating a game move
//____________________________________________________________
int wRow=int.Parse(Convert.ToChar(buf[0]).ToString());
int wColumn=int.Parse(Convert.ToChar(buf[1]).ToString());
if ((wRow>0 && wRow<4) && (wColumn>0 && wColumn<4))
{
objTicTacToe.wNetworkPlay=true;
objTicTacToe.MakeMove(wRow,wColumn);
}
} //if (bytesReceived>0)
} //while (wReceivingServer)
}
catch (ThreadAbortException) {}
catch (Exception ex)
{
MessageBox.Show("An error ocurred: " + ex.Message + "\n" + ex.StackTrace);
objTicTacToe.mnDisconnect_Click(null,null);
return;
}
}
以下是通过网络发送游戏移动的代码段:(Here is the code snippet for sending a game move over the network:)
public void SendMove(int wRow,int wColumn)
{
//________________________________________________________________________
//
// Sends packet that shows move position
//________________________________________________________________________
byte[] buf = new byte[2];
buf[0]=byte.Parse(Asc(wRow.ToString()).ToString());
buf[1]=byte.Parse(Asc(wColumn.ToString()).ToString());
SendPacketTCP(buf);
}
public void SendPacketTCP(Byte[] pDados)
{
//_________________________________________________________________________
//
// Sends a packet via TCP
//_________________________________________________________________________
try
{
if (objTicTacToe.wClient==true)
{
if (clientSockStream==null)
return;
if (clientSockStream.CanWrite)
{
clientSockStream.Write(pDados, 0, 2);
clientSockStream.Flush();
}
}
else
{
if (serverSockStream==null)
return;
if (serverSockStream.CanWrite)
{
serverSockStream.Write(pDados,0, 2);
serverSockStream.Flush();
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error ocurred: " + ex.Message + "\n" + ex.StackTrace);
objTicTacToe.mnDisconnect_Click(null,null);
return;
}
}
兴趣点(Points of Interest)
在执行此项目时遇到一些问题.第一个是做简单的线条来显示获胜者.我尝试在游戏表单中画一条线,但是(I had some problems while doing this project. The first one was doing the simple line that shows the winner. I tried drawing a line in the game form, but the) PictureBox
我画完线后重新绘制了ES.我尝试在(es were redrawn after I draw the line. I tried drawing in the) PictureBox
es,但是代码过于广泛,结果不佳.所以我想到了用(es but the code was too extensive and the result wasn’t good. So I had the idea of capturing game screen with)GDI32.dll(GDI32.dll) BitBlt
功能,将图像放大(function, putting the image in a big) PictureBox
并简单地画线(and simply drawing the line over this) PictureBox
.(.)
另一个问题,我花了一些时间解决.我有客户端和服务器线程来显示大型(The other problem, I had took some time to solve. I had the client and server thread to show the big) PictureBox
当有赢家时.但是当我使用(when there was a winner. But when I used) picWinner.Visible=True
程序变得不稳定和冻结.我进行了大量研究,发现只有表单的线程可以更新de UI,而其他线程则不能.所以我不得不用(the program got unstable and froze. I researched a lot and found out that only the form’s thread can update de UI and no other thread. So I had to use) Control.Invoke
更新广告的可见度(to update the visibility of the) PictureBox
:(:)
//_____________________________________________________________________________
//
// Show the picure using Invoke because of socket thread
// (locks the game if you set picWinner.Visible=True)
//_____________________________________________________________________________
object[] p = new object[1];
p[0] = picWinner;
picWinner.Invoke(new MakeVisibleHandler(MakeVisible), p);
public delegate void MakeVisibleHandler(Control control);
public void MakeVisible(Control control)
{
//_________________________________________________________________________
//
// Make changes to UI using Invoke because of socket thread
//_________________________________________________________________________
control.Visible = true;
}
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Windows .NET .NET1.1 Visual-Studio VS.NET2003 Dev 新闻 翻译