我编写了一个函数,用于检查网格中给定的单元格是否符合棋盘游戏Reversi(也称为Othello)的规则。规则是,只有当新放置的圆和先前放置的圆限制了对手的圆之一时,才能在网格上放置圆。大多数情况下,函数给出了正确的输出(即,当它是合法移动时为真,而当它是合法移动时为假),但是根据先前所述规则合法的一些移动不被该函数视为合法移动。
我试着在每一步都使用控制台来检查函数当前正在查找的单元格,以及单元格的值是什么,以确定哪里出错了,这只会让我更加困惑。
下面的代码是doomed-function:
bool legalMove(int row, int col)
{
// Check if the cell is occupied
if (board[row,col] != 0)
return false;
// Check if there's an opponents circle somewhere around it
for (int i = -1; i<=1; i++)
for (int j = -1; j<=1; j++)
{
if (i == 0 && j == 0)
continue;
int currentRow = row + i;
int currentCol = col + j;
if (currentRow >= 0 && currentRow < board.GetLength(0) && currentCol >= 0 && currentCol < board.GetLength(1) && board[currentRow,currentCol] == -turn)
{
// Now we know that there's an opponents circle somewhere around this space, we now check if it can be captured
while(true)
{
currentRow += i;
currentCol += j;
Console.WriteLine($"currentRow: {currentRow}, currentCol: {currentCol}, value: {board[currentRow,currentCol]}");
if (currentRow < 0 || currentRow >= board.GetLength(0) || currentCol < 0 || currentCol >= board.GetLength(1) || board[currentRow, currentCol] == 0)
return false; // Outside of the board or an empty space
else if (board[currentRow,currentCol] == turn)
return true; // No empty spaces between our cell and another cell of ours
}
}
}
return false; // No cell found around ours
}
我错过了什么?
先谢了!
编辑:整个程序如下(希望能有所帮助):
/* TO-DO
* Make function out of no legal move and tidy up
* Calculate amount of circles of player to determine the winner
* Make victory label better
!!!Tidy up flipCircles method and fix legalMove method
Create a slider and make it change the gridSize
Make GUI change empty space when board gets smaller or bigger
Tidy up the 2x calling to check what the score is
*/
// Library imports
using System;
using System.Drawing;
using System.Security.Policy;
using System.Windows.Forms;
// Game class
class Game : Form
{
// Declare variables
private Board board;
private Button newGame, help;
private Font font;
private Label countRed, countBlue, gameState;
private TrackBar sizeBoard;
public int gridSize = 6;
public Game()
{
// Set the form properties
ClientSize = new Size(520, 670); Text = "Reversi";
// Creating the GUI and adding it to the form
newGame = new Button(); Controls.Add(newGame);
help = new Button(); Controls.Add(help);
font = new Font("Arial", 14);
countBlue = new Label(); Controls.Add(countBlue); countBlue.Font = font;
countRed = new Label(); Controls.Add(countRed); countRed.Font = font;
gameState = new Label(); Controls.Add(gameState); gameState.Font = font;
board = new Board(gridSize); Controls.Add(board);
// Settings of the GUI
newGame.Size = new Size(100, 30); newGame.Location = new Point(150, 10); newGame.Text = "New Game"; newGame.BackColor = Color.LightSlateGray;
help.Size = new Size(100, 30); help.Location = new Point(270, 10); help.Text = "Help"; help.BackColor = Color.LightSlateGray;
countBlue.Size = new Size(110, 30); countBlue.Location = new Point(150, 50); countBlue.Text = $"{board.countBlue} stones"; countBlue.ForeColor = Color.CornflowerBlue;
countRed.Size = new Size(110, 30); countRed.Location = new Point(150, 90); countRed.Text = $"{board.countRed} stones"; countRed.ForeColor = Color.Firebrick;
gameState.Size = new Size(150, 30); gameState.Location = new Point(270, 90); gameState.Text = $"{board.playersTurn}";
// Events //
// Label events
newGame.Click += reset;
help.Click += calculateHelp;
// Board events
board.MouseClick += clicked;
//Paint event
Paint += paint;
}
// Event-handlers //
// Label event-handlers
private void reset(object e, EventArgs ea)
{
board.Reset();
countBlue.Text = $"{board.countBlue} stones";
countRed.Text = $"{board.countRed} stones";
gameState.Text = $"{board.playersTurn}";
}
private void calculateHelp(object e, EventArgs ea)
{
board.SetHelp();
}
// Board event-handlers
private void clicked(object e, MouseEventArgs mea)
{
board.Clicked(mea.Location);
countBlue.Text = $"{board.countBlue} stones";
countRed.Text = $"{board.countRed} stones";
gameState.Text = $"{board.playersTurn}";
// Now check if there's a legalMove if not
//if (timesNoLegalMove > 1)
gameState.Text = $"{board.playersTurn}";
}
// Paint event-handler
private void paint(object e, PaintEventArgs pea)
{
Graphics gr = pea.Graphics;
gr.FillEllipse(Brushes.CornflowerBlue, 100, 45, 31, 31);
gr.FillEllipse(Brushes.Firebrick, 100, 85, 31, 31);
}
}
// Board class
class Board : Label
{
// Declare all global variables used in this class
private int[,] board;
private int size;
private int turn = 1; // 1 is blue, -1 is red
private bool legalMoveExists = true;
public int timesNoLegalMove = 0;
private bool help = false;
// Create the board and set settings + events
public Board(int gridSize)
{
size = gridSize;
Size = new Size(size * 50, size * 50);
Location = new Point(10 + (25 * (10 - size)), 120 + (25 * (10 - size)));
BackColor = Color.White;
board = new int[size, size];
startingState();
Paint += Draw;
}
// Sets the values of the center 4 squares to that of the starting circles
private void startingState()
{
board[(size / 2)-1, (size / 2)-1] = 1;
board[(size / 2), (size / 2)] = 1;
board[(size / 2), (size / 2) - 1] = -1;
board[(size / 2) - 1, (size / 2)] = -1;
}
// Resets the board when New Game is clicked
public void Reset()
{
for (int row = 0; row < board.GetLength(0); row++)
for (int col = 0; col < board.GetLength(1); col++)
board[row, col] = 0;
startingState();
turn = 1;
Invalidate();
}
public void SetHelp()
{
if (help)
help = false;
else
help = true;
Invalidate();
}
public string playersTurn
{
get
{
if (turn == 1)
return "It's Blue's turn";
if (turn == -1)
return "It's Red's turn";
else
{
if (countBlue > countRed)
return "Blue has won the game!";
if (countRed > countBlue)
return "Red has won the game!";
else
return "It's a draw!";
}
}
}
public int countRed
{
get
{
return board.Cast<int>().Count(n => n == -1);
}
}
public int countBlue
{
get
{
return board.Cast<int>().Count(n => n == 1);
}
}
bool legalMove(int row, int col)
{
// Check if the cell is occupied
if (board[row,col] != 0)
return false;
// Check if there's an opponents circle somewhere around it
for (int i = -1; i<=1; i++)
for (int j = -1; j<=1; j++)
{
if (i == 0 && j == 0)
continue;
int currentRow = row + i;
int currentCol = col + j;
if (currentRow >= 0 && currentRow < board.GetLength(0) && currentCol >= 0 && currentCol < board.GetLength(1) && board[currentRow,currentCol] == -turn)
{
// Now we know that there's an opponents circle somewhere around this space, we now check if it can be captured
while(true)
{
currentRow += i;
currentCol += j;
if (currentRow < 0 || currentRow >= board.GetLength(0) || currentCol < 0 || currentCol >= board.GetLength(1) || board[currentRow, currentCol] == 0)
return false; // Outside of the board or an empty space
else if (board[currentRow,currentCol] == turn)
return true; // No empty spaces between our cell and another cell of ours
}
}
}
return false; // No cell found around ours
}
private void flipCircles(int row, int col)
{
// Check all eight directions from the current position
for (int r = row - 1; r <= row + 1; r++)
{
for (int c = col - 1; c <= col + 1; c++)
{
// Skip the current position
if (r == row && c == col)
continue;
int rr = r;
int cc = c;
// Check if the next position in this direction is a valid position on the board
// and if it is occupied by the opponent's piece
if (rr >= 0 && rr < board.GetLength(0) && cc >= 0 && cc < board.GetLength(1) && board[rr, cc] == -turn)
{
// Keep moving in this direction until we find the current player's piece or an empty cell
while (true)
{
rr += r - row;
cc += c - col;
// If we have reached an invalid position or an empty cell, break out of the loop
if (rr < 0 || rr >= board.GetLength(0) || cc < 0 || cc >= board.GetLength(1) || board[rr, cc] == 0)
break;
// If we have found the current player's piece, flip all the pieces between the current position and the player's piece
if (board[rr, cc] == turn)
{
while (rr != r || cc != c)
{
rr -= r - row;
cc -= c - col;
board[rr, cc] = turn;
}
break;
}
}
}
}
}
}
// Sets the value of a clicked cell to either 1 (Blue), or -1 (Red)
public void Clicked(Point mea)
{
int rowClicked = mea.X / 50;
int colClicked = mea.Y /50;
if (legalMove(rowClicked, colClicked))
{
board[rowClicked, colClicked] = turn;
flipCircles(rowClicked, colClicked);
help = false;
turn = -turn;
legalMoveExists = false;
Invalidate();
}
}
// Draws the entire board and all circles
void Draw(object e, PaintEventArgs pea)
{
Graphics gr = pea.Graphics;
legalMoveExists = false;
for (int row = 0; row < board.GetLength(0); row++)
for (int col = 0; col < board.GetLength(1); col++)
{
// Draw the background tiles
if (row % 2 == 0 && col % 2 == 0 || row % 2 != 0 && col % 2 != 0)
gr.FillRectangle(Brushes.DarkGray, 50 * row, 50 * col, 50, 50);
// Draw circles
if (board[row, col] == 1) // Blue circles
gr.FillEllipse(Brushes.CornflowerBlue, 50 * row - 1, 50 * col - 1, 51, 51);
else if (board[row, col] == -1) // Red circles
gr.FillEllipse(Brushes.Firebrick, 50 * row - 1, 50 * col - 1, 51, 51);
// Check for legal moves and draw help circles if the help button has been pressed
else if (legalMove(row, col))
{
legalMoveExists = true;
timesNoLegalMove = 0;
if (help) // Help circles
gr.DrawEllipse(Pens.Black, 50 * row + 9, 50 * col + 9, 31, 31);
}
}
// Make this a function
if (!legalMoveExists)
{
turn = -turn;
timesNoLegalMove++;
Invalidate();
if (timesNoLegalMove > 1)
turn = 0;
}
}
}
// Main run
class Program
{
static void Main()
{
Application.Run(new Game());
}
}
1条答案
按热度按时间z6psavjg1#
你的问题是,你编写的扫描周围细胞的函数偶尔会出现故障,而且很难诊断。通过运行你的代码很容易重现故障,但我无法找到有效调试它的明显方法。
它“可能”更有效地 * 改进算法 *,在那里它在如何检查周围的细胞摆在首位更有条理,如果必要的话,这也会更容易调试。一个可靠的方法是使用定制的迭代器,在那里你可以使用标准的
foreach
模式来检查在八个方向上辐射的虚拟“线”。在每个“yield”可以检查以查看是否可以根据“法律的移动”或“捕获”来做出确定。这是一个概念验证网格,旨在演示迭代器是如何工作的。它 * 不会 * 以任何方式从游戏的Angular 评估单元格,但您可以看到它是如何帮助自己做到这一点的。这里的想法是单击任何单元格并观察U-R-D-L的标记。它也可能有助于查看它的工作,以便您可以clone此示例并设置断点。
显示了左、右、上、下迭代器示例-对角线将遵循相同的模式。鼠标按下控件将起始单元格坐标位置作为Point传递:
该代码为从任何给定点向外进行系统扫描奠定了基础。
出于测试目的,演示板被模拟成这样: