井字游戏 - 检测胜利、失败或平局

6

这是一个井字棋生成器。只有电脑对电脑,与通常的玩家对电脑略有不同。我已经写了大部分代码,但我的问题是有时当我生成游戏时,整个棋盘会填满X和O,并且会出现一行X和一行O,它将被视为平局。有时会生成两行X或两行O,第一行出现3个连续棋子后游戏并不会停止...有什么建议吗?谢谢。

namespace TicTacToe
{
    public partial class Form1 : Form
    {
        private Random rn = new Random();

        const int SIZE = 9;
        char[] cell = new char[SIZE];
        char firstPlayer = ' ', secondPlayer = ' ';

        private void button1_Click(object sender, EventArgs e)
        {
            //Clear the labels and starting values

            for (int i = 0; i < SIZE; i++)
            {
                cell[i] = ' ';
            }
            label10.Text = "";

            //Pick X or O to go first
            switch (rn.Next(2))
            {
                case 0: firstPlayer = 'O'; secondPlayer = 'X'; break;
                case 1: firstPlayer = 'X'; secondPlayer = 'O'; break;
            }

            //Get five non-repeating numbers from 0 to 8
            int[] positions = new int[5];
            positions[0] = rn.Next(9);
            for (int i = 1; i < 5; i++)
            {
                int temp = rn.Next(9);
                for (int j = 0; j < i; j++)
                {
                    if (temp == positions[j])
                    {
                        i--;
                        break;
                    }
                    else
                    {
                        positions[i] = temp;
                    }
                }
            }

            //Set each position found to have first players letter
            for (int i = 0; i < 5; i++)
            {
                cell[positions[i]] = firstPlayer;
            }

            for (int i = 0; i < SIZE; i++)
            {
                if (cell[i] != firstPlayer)
                {
                    cell[i] = secondPlayer;
                }
            }
            //Place cell values into the labels
            label1.Text = cell[0].ToString();
            label2.Text = cell[1].ToString();
            label3.Text = cell[2].ToString();
            label4.Text = cell[3].ToString();
            label5.Text = cell[4].ToString();
            label6.Text = cell[5].ToString();
            label7.Text = cell[6].ToString();
            label8.Text = cell[7].ToString();
            label9.Text = cell[8].ToString();

            //Check for a winner
            switch(checkWinner())
            {
                case 'T' : label10.Text = "It's a tie!"; break;
                case 'O' : label10.Text = "O Wins!"; break;
                case 'X' : label10.Text = "X Wins!"; break;
                default: label10.Text = "This will never appear"; break;
            }
        }

        private char checkWinner()
        {
            //return either 'T' for tie, 'O' for O wins, and 'X' for X wins
            char winner = ' ';
            int winning_line = 0;
            //check for a row win
            if(cell[0].Equals(cell[1]) && cell[0].Equals(cell[2]))
            {
                winning_line++;
                winner = cell[0];
            }
            if (cell[3].Equals(cell[4]) && cell[3].Equals(cell[5]))
            {
                winning_line++;
                winner = cell[3];
            }
            if (cell[6].Equals(cell[7]) && cell[6].Equals(cell[8]))
            {
                winning_line++;
                winner = cell[6];
            }

            //check for column wins
            if (cell[0].Equals(cell[3]) && cell[0].Equals(cell[6]))
            {
                winning_line++;
                winner = cell[0];
            }
            if (cell[1].Equals(cell[4]) && cell[1].Equals(cell[7]))
            {
                winning_line++;
                winner = cell[1];
            }
            if (cell[2].Equals(cell[5]) && cell[2].Equals(cell[8]))
            {
                winning_line++;
                winner = cell[2];
            }
            //check for diagonal winner
            if (cell[0].Equals(cell[4]) && cell[0].Equals(cell[8]))
            {
                winning_line++;
                winner = cell[0];
            }
            if (cell[2].Equals(cell[4]) && cell[2].Equals(cell[8]))
            {
                winning_line++;
                winner = cell[2];
            }

            if (winning_line == 0 || winning_line > 1)
            winner = 'T';

            return winner;
        }

        public int i { get; set; }
    }
}

3
您的对角线有一个错误,您正在检查0 == 4 == 8,但也应该检查2 == 4 == 8(而不是6) - Nolonar
2
如果你想练习的话,我建议你尝试将所有游戏逻辑与UI分开实现。你可以为游戏本身、玩家、每个获胜规则等创建类。然后你就可以更轻松地玩弄AI等内容了。这只是一个建议... - Jobo
如果可以的话,我会点赞Jobo的评论。如果您创建一个处理游戏的类,您可以将其放置在不同的UI中,例如一个用于计算机对计算机,或者一个用于玩家对玩家或玩家对计算机的不同UI中。 - SteveP
4个回答

3
if (winning_line == 0 || winning_line > 1)

如果有两条线,它会报告平局。如果你想在一条线被画出后停止游戏,你需要在每次移动后检查赢家,而不是在整个棋盘被填满后检查。

是的,如果您每次放置符号时都进行检查,那么您只需要检查自上一个放置符号以来的行。 - MrFox
@SteveP - 我在这方面还很新,因为这是我正在阅读的书推荐的初学者练习。如果您可以帮助我更好地理解每个语句之后的检查,那将不胜感激。我知道您的意思,只是在把它们组合在一起方面有些困难...谢谢。 - TomandGeriatric
基本上,为了模拟真实的游戏,您需要获取当前位置,应用玩家的移动,并检查该移动是否赢得了游戏。您可以优化获胜检查,因为任何获胜行都必须包括刚刚进行的移动。 - SteveP
我一直盯着这个看了几个小时了,很难过,我知道。我放弃了。 - TomandGeriatric

2
第二个对角线胜利者的检查应该是6而不是8。
您当前正在检查:
X O O
O X O
O O X
和:
O O X
O X O
O O X
显然最后的x应该在左边。
此外,正如其他人发表的那样。制作两条线不应该导致平局。一个玩家甚至可以独自制作两条线,导致平局。 更改函数以在找到获胜行时立即返回结果,并在每次移动后检查它。

1

这个可以生效: 你需要摆脱...

if (winning_line == 0 || winning_line > 1)

用以下三行代码替换那行代码:

    if (winnerX == " X ")
    {
        theWinner = winnerX;
    }
    if (winnerO == " O ")
    {
        theWinner = winnerO;
    }
    if(winnerX == " X " && winnerO == " O ")
    {
        winnerT = " T ";
        theWinner = winnerT;
    }

所以我做的是改变了一些东西。我没有使用 "winning_line++;" 这一行代码,而是对每个 if 语句检查都做了类似于这样的事情。

    if (cell[2, 0].Equals(cell[1, 1]) && cell[2, 0].Equals(cell[0, 2]))
        {
            if (cell[2, 0] == 0)
            {
                winnerX = " X ";
            }

            else if (cell[2, 0] == 1)
            {
                winnerO = " O ";
            }
        }

所以我有4个字符串被使用,一个用于跟踪X是否拥有获胜线,同样的还有O。然后我有一个winnerT字符串来跟踪平局,它只在你原先的平局检查语句的位置使用。
如果您决定使用字符串而不是整数,您还需要更改switch语句。
    switch (checkWinner())
        {
            case " X ": 
                textBox1.Text = "X Wins!";
                break;
            case " O ":
                textBox1.Text = "O Wins!";
                break;
            case " T ": 
                textBox1.Text = "It's a tie!";
                break;
        }

0

嗨,我认为你应该有一个函数,给定一个网格和一个新的棋子,告诉你游戏是否结束。 然后,如果游戏结束了,你就知道赢家是最后一个下的棋子。

我认为Marthyi的开源项目MikMak对此有完美的实现,请参见

bool IsFinished(Grid currentState, Pawn newPawn)

输入:

https://github.com/Marthyi/MikMak/blob/master/MikMakSolution/Morpion/MorpionManager.cs

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接