提问人:Frank 提问时间:8/20/2023 更新时间:8/20/2023 访问量:66
C#(或任何其他语言)如何读取代码?我是一个非常新手
How does C# (or any other language) read the code? I'm a very newie
问:
似乎我仍然不明白编程是如何工作的(也许是因为我已经学习了大约 7 天左右的 C#),而且我仍然不知道它如何读取您的代码。
看,我必须使用 c# 和控制台创建井字游戏。当我最终完成任务时,我看了一下正确的方法,当他们使用 200 行时,我使用了 500 行。
关键是他们做了一个“Do While”循环,在循环中,他们使用一个“if”调用一个方法,该方法使用玩家的数量和输入作为参数。当“if”关闭时,他们输入“Console.WriteLine”,要求提供他们之前需要使用的输入。当你运行它时,他们会在做任何事情之前要求你这样做。为什么会这样?
我自己也想不通为什么会这样工作。当他们在关闭时要求您输入时,这个“如果”怎么可能起作用。这是他代码的一部分,我的意思是:
int player = 2;
int input = 0;
bool correctInput = true;
CreateBoard();
do
{
if(player == 2)
{
player = 1;
PutXorO(player, input);
}else if(player == 1)
{
player = 2;
PutXorO(player, input);
}
do
{
Console.WriteLine("\nPlayer{0}, please, select a number...", player);
input = Convert.ToInt32(Console.ReadLine());
} while (!correctInput);
} while (true);
编辑:在写这篇文章时,我认为这并不像我想象的那么难,但希望得到一些帮助。太好了!
在看到答案之前,我所做的是把所有这些东西放在你问的地方,在我的代码的第一行,这就是我的大脑理解这个逻辑的方式,但我需要改变它,这样我才能开始作为一个优秀的程序员思考。
我真的很想进步,相信我。我为此对自己感到不安。
答:
首先,如果不查看代码的其余部分,就不可能再说什么,但我会尝试通过提供一些见解来尽可能多地解释代码。
作为一般经验法则,代码是从上到下和从左到右读取的,外部结构在其嵌套或内部组件之前读取。
守则
正如我之前所说,我不知道代码的其余部分。因此,我将做出一些假设。
循环具有特定用途。当您遇到以下情况时,最常使用它:do-while
为了简单起见,想象一个程序不断提示用户输入一个数字,直到该数字是“有效”数字,即该数字介于 1 和 10 之间。
对于正常循环,这将按如下方式完成:while
Console.WriteLine("Enter a number between 1 and 10: ");
int number = int.Parse(Console.ReadLine());
while (number < 1 || number > 10)
{
Console.WriteLine("Invalid number. Enter a number between 1 and 10: ");
number = int.Parse(Console.ReadLine());
}
Console.WriteLine("You entered a valid number: " + number);
在这个例子中,我们需要在进入循环之前向用户询问号码。或者,这可以使用循环来实现。do-while
int number;
do
{
Console.WriteLine("Enter a number between 1 and 10:");
number = int.Parse(Console.ReadLine());
}
while (number < 1 || number > 10);
Console.WriteLine("You entered a valid number: " + number);
在本例中,循环初始化一次,使用单个 . Console.ReadLine()
在代码中,程序的这一部分
do
{
if(player == 2)
{
player = 1;
PutXorO(player, input);
}else if(player == 1)
{
player = 2;
PutXorO(player, input);
}
do
{
Console.WriteLine("\nPlayer{0}, please, select a number...", player);
input = Convert.ToInt32(Console.ReadLine());
} while (!correctInput);
} while (true);
运行在一个无用的循环上,它与循环没有什么不同。因此,它可以写成:do-while
while(true)
while (true)
{
if(player == 2)
{
player = 1;
PutXorO(player, input);
}else if(player == 1)
{
player = 2;
PutXorO(player, input);
}
do
{
Console.WriteLine("\nPlayer{0}, please, select a number...", player);
input = Convert.ToInt32(Console.ReadLine());
} while (!correctInput);
}
当程序启动时,被初始化为 。因此,它工作正常。但考虑到两个玩家都还没有采取行动,可以假设该方法可以像这样:input
0
PutXorO(player, input)
PutXorO()
public void PutXorO(int player, int input)
{
if(input == 0)
{
return;
}
// The rest of the code
}
接下来,第二个循环开始发挥作用的部分。现在,这部分对我来说不是很清楚,仅仅是因为这一行:do-while
while (!correctInput);
在代码的开头,设置为 。因此,这个 while 循环永远不会起作用,因为变量在循环本身中永远不会改变,这意味着循环条件总是解析为 。我相信方法发生了变化,这不仅令人困惑,而且毫无用处。correctInput
true
correctInput
false
correctInput
PutXorO()
如何替代它?
在这一部分中,我将尝试从头开始编写一个井字游戏。请注意,可能存在一些错误。我相信评论中的人会纠正这些错误。
首先,我将构造一个简单的板,它将是一个一维字符串数组。在形式中:
/* The tic tac toe board looks like this, with locations from 1 to 9:
* -------------------------
* | | | |
* | 1 | 2 | 3 |
* | | | |
* -------------------------
* | | | |
* | 4 | 5 | 6 |
* | | | |
* -------------------------
* | | | |
* | 7 | 8 | 9 |
* | | | |
* -------------------------
*/
string[] TicTacToeBoard = new string[9];
// Initialize board
for (int i = 0; i < TicTacToeBoard.Length; i++)
{
TicTacToeBoard[i] = string.Empty;
}
现在,我想初始化将在控制流中使用的几个变量:
int currentPlayer = 1; // The current player
bool gameOver = false; // Whether or not the game is going on
int moves = 0; // Keeping track of the moves to see if the board is filled
我们需要一个简单的循环来跟踪变量:gameOver
while (!gameOver)
{
}
我们将要求当前玩家提供位置信息
while (!gameOver)
{
Console.WriteLine($"Player {currentPlayer}, it's your turn. Enter a location (1-9):");
int input = Convert.ToInt32(Console.ReadLine());
}
在这一点上,我们将有一种方法将 X 或 O 放入电路板中,如果输入有效,则返回 true,如果输入无效,则返回 false。我想出了这个:
// Returns false if the location is invalid or already taken
static bool PutXorO(string[] board, int player, int location)
{
if (location < 1 || location > 9)
{
return false;
}
if (player == 1 && board[location - 1] == string.Empty)
{
board[location - 1] = "X";
}
else if (player == 2 && board[location - 1] == string.Empty)
{
board[location - 1] = "O";
}
else
{
return false;
}
return true;
}
因此,我们现在可以将输入放入板中,或者如果输入无效,则重复移动
while (!gameOver)
{
Console.WriteLine($"Player {currentPlayer}, it's your turn. Enter a location (1-9):");
int input = Convert.ToInt32(Console.ReadLine());
if(PutXorO(TicTacToeBoard, currentPlayer, input))
{
// Valid Input, proceed with the code
}
// Invalid Input, loop back and ask the same player for an input
}
现在,如果输入无效,代码将循环回并要求同一玩家提供新的输入。您可能会添加错误消息,但我选择不这样做。另一方面,如果输入有效,我们需要增加移动次数,检查获胜或平局,并交换当前玩家。
while (!gameOver)
{
Console.WriteLine($"Player {currentPlayer}, it's your turn. Enter a location (1-9):");
int input = Convert.ToInt32(Console.ReadLine());
if(PutXorO(TicTacToeBoard, currentPlayer, input))
{
moves++;
// TODO: Check for wins
...
//
if(moves == 9)
{
Console.WriteLine("It's a tie!");
gameOver = true;
}
currentPlayer = currentPlayer == 1 ? 2 : 1;
}
}
在这种情况下,如果移动数为 9 并且没有玩家获胜,则为平局。最后,我们所要做的就是检查所有获胜条件的方法。为此,我编写了以下方法:
static bool CheckPlayerWin(string[] board, int player)
{
string playerToken = player == 1 ? "X" : "O";
int[][] winCombos = new int[][]
{
new int[] { 0, 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6, 7, 8 },
new int[] { 0, 3, 6 },
new int[] { 1, 4, 7 },
new int[] { 2, 5, 8 },
new int[] { 0, 4, 8 },
new int[] { 2, 4, 6 }
};
foreach (var combo in winCombos)
{
if (board[combo[0]] == playerToken && board[combo[1]] == playerToken && board[combo[2]] == playerToken)
{
return true;
}
}
return false;
}
此方法检查棋盘上的所有获胜组合。此方法可以进一步包装在一个方法中,该方法将返回具有一个的播放器(如果有或其他)。CheckWin()
0
static int CheckWin(string[] board)
{
if (CheckPlayerWin(board, 1)) return 1;
if (CheckPlayerWin(board, 2)) return 2;
return 0;
}
最后,主循环可以按以下方式完成:
while (!gameOver)
{
Console.WriteLine($"Player {currentPlayer}, it's your turn. Enter a location (1-9):");
int input = Convert.ToInt32(Console.ReadLine());
if(PutXorO(TicTacToeBoard, currentPlayer, input))
{
moves++;
int playerWon = CheckWin(TicTacToeBoard);
if(playerWon != 0)
{
Console.WriteLine($"Player {playerWon} has won the game!");
gameOver = true;
}
else if(moves == 9)
{
Console.WriteLine("It's a tie!");
gameOver = true;
}
currentPlayer = currentPlayer == 1 ? 2 : 1;
}
}
请注意,只有当第九步没有赢家时,此代码才会检查平局。
整个代码变为:
internal class Program
{
/* The tic tac toe board looks like this, with locations from 1 to 9:
* -------------------------
* | | | |
* | 1 | 2 | 3 |
* | | | |
* -------------------------
* | | | |
* | 4 | 5 | 6 |
* | | | |
* -------------------------
* | | | |
* | 7 | 8 | 9 |
* | | | |
* -------------------------
*/
// Returns false if the location is invalid or already taken
static bool PutXorO(string[] board, int player, int location)
{
if (location < 1 || location > 9)
{
return false;
}
if (player == 1 && board[location - 1] == string.Empty)
{
board[location - 1] = "X";
}
else if (player == 2 && board[location - 1] == string.Empty)
{
board[location - 1] = "O";
}
else
{
return false;
}
return true;
}
static bool CheckPlayerWin(string[] board, int player)
{
string playerToken = player == 1 ? "X" : "O";
int[][] winCombos = new int[][]
{
new int[] { 0, 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6, 7, 8 },
new int[] { 0, 3, 6 },
new int[] { 1, 4, 7 },
new int[] { 2, 5, 8 },
new int[] { 0, 4, 8 },
new int[] { 2, 4, 6 }
};
foreach (var combo in winCombos)
{
if (board[combo[0]] == playerToken && board[combo[1]] == playerToken && board[combo[2]] == playerToken)
{
return true;
}
}
return false;
}
static int CheckWin(string[] board)
{
if (CheckPlayerWin(board, 1)) return 1;
if (CheckPlayerWin(board, 2)) return 2;
return 0;
}
static void Main(string[] args)
{
string[] TicTacToeBoard = new string[9];
// Initialize board
for (int i = 0; i < TicTacToeBoard.Length; i++)
{
TicTacToeBoard[i] = string.Empty;
}
int currentPlayer = 1;
bool gameOver = false;
int moves = 0;
while (!gameOver)
{
Console.WriteLine($"Player {currentPlayer}, it's your turn. Enter a location (1-9):");
int input = Convert.ToInt32(Console.ReadLine());
if(PutXorO(TicTacToeBoard, currentPlayer, input))
{
moves++;
int playerWon = CheckWin(TicTacToeBoard);
if(playerWon != 0)
{
Console.WriteLine($"Player {playerWon} has won the game!");
gameOver = true;
}
else if(moves == 9)
{
Console.WriteLine("It's a tie!");
gameOver = true;
}
currentPlayer = currentPlayer == 1 ? 2 : 1;
}
}
}
}
我的初步测试表明,这个程序有点有效。可能有几个更新可以改进此程序。例如,您可以添加一种在每次移动时显示棋盘的方式等。
不要犹豫,提出任何问题或指出我犯的任何错误。
评论
input
player