如何推进我的五个骰子游戏
How to progress my Five Dice game
我正在学习编程,特别是从 C# 开始,我一直在尝试骰子游戏,以便更加熟悉并提高自己。我现在正在尝试以 windows 形式创建一个基本游戏,其中两名玩家掷 5 个骰子并记录他们的得分。
规则:
从 5 个骰子开始
如果出现 1 或 4,则玩家没有得分,这些骰子将被移除。否则将所有骰子加到总计
继续剩余的骰子,直到没有剩余的骰子为止
到目前为止,我有一个图像数组,用于将我所有的骰子图像存储在我的资源中,还有一个用于掷骰子的按钮。我特别需要帮助的是能够移除受罚的骰子(将那个特定的骰子设置回空白)并允许玩家继续滚动剩余的骰子,直到剩下 none。
目前我不确定我可以在哪里进一步,也许我咬得太多了。我热爱编码,如有任何帮助,我们将不胜感激。
这是界面图片:
public partial class Form1 : Form
{
Image[] diceImages;
int[] dice;
int[] diceResults;
Random random;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
diceImages = new Image[7];
diceImages[0] = Properties.Resources.blank;
diceImages[1] = Properties.Resources.one;
diceImages[2] = Properties.Resources.two;
diceImages[3] = Properties.Resources.three;
diceImages[4] = Properties.Resources.four;
diceImages[5] = Properties.Resources.five;
diceImages[6] = Properties.Resources.six;
dice = new int[5] { 0, 0, 0, 0, 0 };
random = new Random();
diceResults = new int[6] { 0, 0, 0, 0, 0, 0 };
}
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
GetResults();
ResetResults();
}
private void RollDice()
{
for (int i = 0; i < dice.Length; i++)
{
dice[i] = random.Next(1, 7);
switch (dice[i])
{
case 1:
diceResults[0]++;
break;
case 2:
diceResults[1]++;
break;
case 3:
diceResults[2]++;
break;
case 4:
diceResults[3]++;
break;
case 5:
diceResults[4]++;
break;
case 6:
diceResults[5]++;
break;
}
}
lbl_dice1.Image = diceImages[dice[0]];
lbl_dice2.Image = diceImages[dice[1]];
lbl_dice3.Image = diceImages[dice[2]];
lbl_dice4.Image = diceImages[dice[3]];
lbl_dice5.Image = diceImages[dice[4]];
}
private void GetResults()
{
bool oneRoll = false, fourRoll = false;
for (int i = 0; i < diceResults.Length; i++)
{
if (diceResults[i] == 1 && diceResults[i] == 4)
{
oneRoll = true;
fourRoll = true;
}
}
}
private void ResetResults()
{
}
}
您 post 编辑的代码至少有几个奇怪的地方似乎不符合您的描述:
- 代码简单地 增加 数组中的元素 (
diceResults
) 当掷出给定的骰子值时(即元素对应于骰子 value,不是游戏中的骰子顺序)。根据您的描述,我本以为代码会简单地将 add 模具值添加到单个总和变量中。
- 在您的
GetResults()
方法中,您的代码将 diceResults
中的各个元素值与值 2
和 5
进行比较。换句话说,对于每个可能的骰子值,如果该值出现两次或五次,则您设置两个标志。这很奇怪有很多原因,但最大、最明显的一个是单个变量(即元素 diceResults[i]
)可以 never 在同时。 IE。该数组元素永远不会像 if
语句所要求的那样既是 2
又是 5
。
考虑到这些问题,我更倾向于关注原始规范,而不是在试图理解代码的预期行为实际是什么方面过于信任代码。 :)
看来基本问题是如何最好地从游戏中移除骰子。使用列表来跟踪骰子的建议(在上面的评论中)当然是可行的。在这种方法中,人们将遍历列表以设置每个元素,如果给定元素的滚动出现 1
或 4
,请在继续之前删除该元素。
完成后,只需再次遍历列表以设置骰子值图像,对超出列表长度的任何骰子使用 "blank" 图像。
但是有一个更简单的方法,根据你的说法"setting that particular one back to blank",这似乎意味着每个空白骰子应该出现在它所在的相同位置已经滚动了,看来你可能更喜欢那种更简单的方法。
具体来说,掷骰子后,只需扫描 dice
数组并将任何 1
和 4
值重置为 0
,然后使用此 0
值作为一个特殊的 "sentinel" 值来表示 die 现在是空白的。
请注意,无论您如何执行此操作(使用列表,或仅将值设置为 0
),还有一个问题是是否向用户显示实际的 1
和 [=22] =] 卷,或立即将这些卷设置为空白骰子。我将假设是前者,但以另一种方式实现它会很容易。 (一如既往,好的代码的开头是一个好的规范……现在,您的规范在细节上有点松散,因此含糊不清)。
采用这种方法,您的代码可能看起来更像这样:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
int[] dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Arrays are always initialized with the elements having their default
// values, so there's no need to specify `0` values for `int` arrays explicitly
dice = new int[5];
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Length; i++)
{
if (checkOnesAndFours)
{
// First, clear any 1 or 4 from the previous roll
if (dice[i] == 1 || dice[i] == 4)
{
dice[i] = 0;
}
// Then, ignore any blank die
if (dice[i] == 0)
{
continue;
}
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = diceImages[dice[i]];
}
}
#endregion
}
注意:当 1
或 4
出现时,我并不完全清楚你的意思。从字面上看你写的,我理解它的意思是如果 any 骰子显示 1
或 4
,那么 [=该卷的骰子数的 96=]。上面的代码是在考虑到这种理解的情况下实现的。
我突然想到,您的意思可能是只有显示 1
或 4
的骰子不计入掷骰,而该掷骰的其他骰子仍包括在内.更改以上内容以适应该替代规范并不难。
注意:您还会注意到,为了解决紧迫的问题,我对代码进行了技术上不需要的其他更改。我在代码本身中添加了注释,以试图解释我进行这些更改的原因,以及为什么我觉得它们使代码变得更好。
只是为了笑,这里有一个使用列表的版本:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
List<int> dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Lists must be initialized explicitly with their initial values, as by default
// they are initially empty.
dice = new List<int>(Enumerable.Repeat(0, 5));
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Count; i++)
{
// Clear any 1 or 4 from the previous roll
if (checkOnesAndFours && (dice[i] == 1 || dice[i] == 4))
{
// Remove this die from play
dice.RemoveAt(i);
// The next list element to examine is now at the current i value
// and the for loop is going to increment i when the continue
// is executed, so decrement i in anticipation of that
// so that the loop moves on to the correct next element
i--;
continue;
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = i < dice.Count ? diceImages[dice[i]] : diceImages[0];
}
}
#endregion
}
最后,请注意以上都没有解决代码的其他几个问题:
- 在游戏开始时初始化骰子标签。
- 游戏结束后重置整个游戏(即没有剩余的骰子)。
我将这两项留作 reader 的练习(当然,如果您 运行 遇到这些特定问题的问题,您可能总是 post 关于 Stack 的另一个问题溢出具体询问每个)。
我正在学习编程,特别是从 C# 开始,我一直在尝试骰子游戏,以便更加熟悉并提高自己。我现在正在尝试以 windows 形式创建一个基本游戏,其中两名玩家掷 5 个骰子并记录他们的得分。
规则:
从 5 个骰子开始
如果出现 1 或 4,则玩家没有得分,这些骰子将被移除。否则将所有骰子加到总计
继续剩余的骰子,直到没有剩余的骰子为止
到目前为止,我有一个图像数组,用于将我所有的骰子图像存储在我的资源中,还有一个用于掷骰子的按钮。我特别需要帮助的是能够移除受罚的骰子(将那个特定的骰子设置回空白)并允许玩家继续滚动剩余的骰子,直到剩下 none。
目前我不确定我可以在哪里进一步,也许我咬得太多了。我热爱编码,如有任何帮助,我们将不胜感激。
这是界面图片:
public partial class Form1 : Form
{
Image[] diceImages;
int[] dice;
int[] diceResults;
Random random;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
diceImages = new Image[7];
diceImages[0] = Properties.Resources.blank;
diceImages[1] = Properties.Resources.one;
diceImages[2] = Properties.Resources.two;
diceImages[3] = Properties.Resources.three;
diceImages[4] = Properties.Resources.four;
diceImages[5] = Properties.Resources.five;
diceImages[6] = Properties.Resources.six;
dice = new int[5] { 0, 0, 0, 0, 0 };
random = new Random();
diceResults = new int[6] { 0, 0, 0, 0, 0, 0 };
}
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
GetResults();
ResetResults();
}
private void RollDice()
{
for (int i = 0; i < dice.Length; i++)
{
dice[i] = random.Next(1, 7);
switch (dice[i])
{
case 1:
diceResults[0]++;
break;
case 2:
diceResults[1]++;
break;
case 3:
diceResults[2]++;
break;
case 4:
diceResults[3]++;
break;
case 5:
diceResults[4]++;
break;
case 6:
diceResults[5]++;
break;
}
}
lbl_dice1.Image = diceImages[dice[0]];
lbl_dice2.Image = diceImages[dice[1]];
lbl_dice3.Image = diceImages[dice[2]];
lbl_dice4.Image = diceImages[dice[3]];
lbl_dice5.Image = diceImages[dice[4]];
}
private void GetResults()
{
bool oneRoll = false, fourRoll = false;
for (int i = 0; i < diceResults.Length; i++)
{
if (diceResults[i] == 1 && diceResults[i] == 4)
{
oneRoll = true;
fourRoll = true;
}
}
}
private void ResetResults()
{
}
}
您 post 编辑的代码至少有几个奇怪的地方似乎不符合您的描述:
- 代码简单地 增加 数组中的元素 (
diceResults
) 当掷出给定的骰子值时(即元素对应于骰子 value,不是游戏中的骰子顺序)。根据您的描述,我本以为代码会简单地将 add 模具值添加到单个总和变量中。 - 在您的
GetResults()
方法中,您的代码将diceResults
中的各个元素值与值2
和5
进行比较。换句话说,对于每个可能的骰子值,如果该值出现两次或五次,则您设置两个标志。这很奇怪有很多原因,但最大、最明显的一个是单个变量(即元素diceResults[i]
)可以 never 在同时。 IE。该数组元素永远不会像if
语句所要求的那样既是2
又是5
。
考虑到这些问题,我更倾向于关注原始规范,而不是在试图理解代码的预期行为实际是什么方面过于信任代码。 :)
看来基本问题是如何最好地从游戏中移除骰子。使用列表来跟踪骰子的建议(在上面的评论中)当然是可行的。在这种方法中,人们将遍历列表以设置每个元素,如果给定元素的滚动出现 1
或 4
,请在继续之前删除该元素。
完成后,只需再次遍历列表以设置骰子值图像,对超出列表长度的任何骰子使用 "blank" 图像。
但是有一个更简单的方法,根据你的说法"setting that particular one back to blank",这似乎意味着每个空白骰子应该出现在它所在的相同位置已经滚动了,看来你可能更喜欢那种更简单的方法。
具体来说,掷骰子后,只需扫描 dice
数组并将任何 1
和 4
值重置为 0
,然后使用此 0
值作为一个特殊的 "sentinel" 值来表示 die 现在是空白的。
请注意,无论您如何执行此操作(使用列表,或仅将值设置为 0
),还有一个问题是是否向用户显示实际的 1
和 [=22] =] 卷,或立即将这些卷设置为空白骰子。我将假设是前者,但以另一种方式实现它会很容易。 (一如既往,好的代码的开头是一个好的规范……现在,您的规范在细节上有点松散,因此含糊不清)。
采用这种方法,您的代码可能看起来更像这样:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
int[] dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Arrays are always initialized with the elements having their default
// values, so there's no need to specify `0` values for `int` arrays explicitly
dice = new int[5];
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Length; i++)
{
if (checkOnesAndFours)
{
// First, clear any 1 or 4 from the previous roll
if (dice[i] == 1 || dice[i] == 4)
{
dice[i] = 0;
}
// Then, ignore any blank die
if (dice[i] == 0)
{
continue;
}
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = diceImages[dice[i]];
}
}
#endregion
}
注意:当 1
或 4
出现时,我并不完全清楚你的意思。从字面上看你写的,我理解它的意思是如果 any 骰子显示 1
或 4
,那么 [=该卷的骰子数的 96=]。上面的代码是在考虑到这种理解的情况下实现的。
我突然想到,您的意思可能是只有显示 1
或 4
的骰子不计入掷骰,而该掷骰的其他骰子仍包括在内.更改以上内容以适应该替代规范并不难。
注意:您还会注意到,为了解决紧迫的问题,我对代码进行了技术上不需要的其他更改。我在代码本身中添加了注释,以试图解释我进行这些更改的原因,以及为什么我觉得它们使代码变得更好。
只是为了笑,这里有一个使用列表的版本:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
List<int> dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Lists must be initialized explicitly with their initial values, as by default
// they are initially empty.
dice = new List<int>(Enumerable.Repeat(0, 5));
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Count; i++)
{
// Clear any 1 or 4 from the previous roll
if (checkOnesAndFours && (dice[i] == 1 || dice[i] == 4))
{
// Remove this die from play
dice.RemoveAt(i);
// The next list element to examine is now at the current i value
// and the for loop is going to increment i when the continue
// is executed, so decrement i in anticipation of that
// so that the loop moves on to the correct next element
i--;
continue;
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = i < dice.Count ? diceImages[dice[i]] : diceImages[0];
}
}
#endregion
}
最后,请注意以上都没有解决代码的其他几个问题:
- 在游戏开始时初始化骰子标签。
- 游戏结束后重置整个游戏(即没有剩余的骰子)。
我将这两项留作 reader 的练习(当然,如果您 运行 遇到这些特定问题的问题,您可能总是 post 关于 Stack 的另一个问题溢出具体询问每个)。