我制作了一个程序,用于在飞镖游戏中保持分数,你可以输入x个玩家,然后每个玩家按照他们输入名字的顺序投掷3个箭头,然后重复自己,直到有人达到501结束游戏的点数。
对于玩家来说,list
似乎工作得很好,但不知何故,我无法获得箭头/得分的list
。我在Visual Studio中没有错误,我可以正常运行该程序,但是如果我尝试使用arrowList
循环打印出foreach
中的值,则不会发生任何事情。据我所知,我完全按照arrowList
players
完成了list
,arrowList
class Program
{
static void Main(string[] args)
{
Game game = new Game();
game.PlayGame();
}
}
class Game
{
public Game()
{
//default constructor that takes 0 arguments
}
int playernumber = 0;
List<Player> players = new List<Player>();
public void PlayGame()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Title = " Dartcounter 3000";
Console.WriteLine("Welcome to the Dartcounter 3000!");
NumberOfPlayers();
Console.WriteLine("");
foreach (var player in players)
{
if (player.ToString() == "Dator")
{
Console.WriteLine("Generating score for the NPC 'Dator'...");
Random random = new Random();
int randomThrow1 = random.Next(0, 60);
int randomThrow2 = random.Next(0, 60);
int randomThrow3 = random.Next(0, 60);
Arrows arrows = new Arrows(randomThrow1, randomThrow2, randomThrow3);
player.CalculatePoints();
}
else
{
Console.WriteLine("It's {0} turn to throw", player.ToString());
System.Threading.Thread.Sleep(500);
Console.WriteLine("Enter your score for the first arrow: ");
int arrowOne = int.Parse(Console.ReadLine());
Console.WriteLine("Your second arrow: ");
int arrowTwo = int.Parse(Console.ReadLine());
Console.WriteLine("Your third arrow: ");
int arrowThree = int.Parse(Console.ReadLine());
Arrows arrows = new Arrows(arrowOne, arrowTwo, arrowThree);
Console.WriteLine(arrows.ToString());
player.CalculatePoints();
}
}
Console.ReadLine();
}
// ------------ START of player methods in class Game ------------
public void NumberOfPlayers()
{
Console.WriteLine("Please enter the number of players: ");
start:
string playernumberinput = Console.ReadLine();
int value;
if (int.TryParse(playernumberinput, out value))
{
playernumber = int.Parse(playernumberinput);
AddPlayer();
}
else
{
Console.WriteLine("You did not input a number. Please try again: ");
goto start;
}
}
public void AddPlayer()
{
for (int i = 0; i < playernumber; i++)
{
Console.WriteLine("Enter name of player {0}:", i + 1);
players.Add(new Player(Console.ReadLine()));
}
}
// ------------ END of player methods in class Game ------------
}
class Arrows
{
public Arrows()
{
//default constructor that takes 0 arguements
}
public int roundScore;
public Arrows(int roundScore)
{
this.roundScore = roundScore;
}
public int arrowOne { get; set; }
public int arrowTwo { get; set; }
public int arrowThree { get; set; }
public Arrows(int Arrow1, int Arrow2, int Arrow3)
{
arrowOne = Arrow1;
arrowTwo = Arrow2;
arrowThree = Arrow3;
Player player = new Player();
player.AddArrows();
}
public int GetScore()
{
return arrowOne + arrowTwo + arrowThree;
}
public override string ToString()
{
return (string.Format("You got a total of {0} this round!", GetScore()));
}
}
class Player
{
public Player()
{
//default constructor that takes 0 arguments
}
public string Name;
public List<Arrows> arrowList = new List<Arrows>();
public Player(string Name)
{
this.Name = Name;
}
public void AddArrows()
{
Arrows arrows = new Arrows();
int roundScore = arrows.GetScore();
arrowList.Add(new Arrows(roundScore));
}
public void CalculatePoints()
{
foreach (var arrow in arrowList)
{
//Calculation to sum up the entry's in arrowList to see if someone has reached 501 points
}
}
public override string ToString()
{
return (string.Format("{0}", Name));
}
}
似乎按预期工作,所以为什么不是{{{1}} 1}}工作??
我已经为我的C#课程坚持了大约一个星期的任务 - 我在这里找到了几个关于非常类似任务的问题,但我仍然无法将这些建议付诸实践用我的代码(我不想复制和粘贴他们的整个程序,毕竟我在这里学习)。 我整个程序的代码:
{{1}}
答案 0 :(得分:3)
为了跟进这一点,我想我会在开发过程中看到我使用的过程,看看它是否有帮助。另外,出于某种原因,这似乎是一个有趣的项目。
首先,我将前一个答案中的伪代码复制/粘贴到Main()方法中的新控制台项目中。很明显,一堆东西是未定义的,所以我开始定义它以便代码编译。
未定义的第一件事是Player
,所以我创建了一个空的Player类:
public class Player { }
接下来,GetPlayers()
方法未定义。这个方法需要获得游戏的所有玩家并将它们返回到List中,所以我创建了一个返回Players
列表的裸骨方法:
public static List<Player> GetPlayers()
{
var players = new List<Player>();
return players;
}
接下来,AnnounceRound
方法未定义。我知道这只会宣布新一轮开始,我决定在每轮开始时清除控制台窗口:
public static void AnnounceRound(int roundNumber)
{
Console.Clear();
var announcement = string.Format("Beginning Round #{0}", roundNumber);
Console.WriteLine(announcement);
// The next line writes out a list of dashes that is the
// exact length of the announcement (like an underline)
Console.WriteLine(new string('-', announcement.Length));
}
接下来,AnnouncePlayer
方法未定义。这将让每个人都知道目前是谁:
private static void AnnouncePlayer(Player player)
{
Console.WriteLine("{0}It's now {1}'s turn.{0}", Environment.NewLine, player.Name);
}
但是当我按照我想要的方式编写代码时,出现了一个问题:Player
类没有Name
属性。所以回到Player
课程。我将使该属性只读(通过使setter私有),并将名称作为构造函数的参数。这样我们就不允许有人创建Player
然后稍后更改他的名字(这就是我想要的方式,但是没有必要。如果我们以后决定让它读写,我们可以轻松地将setter更改为public):
public class Player
{
public string Name { get; private set; }
public Player(string name)
{
Name = name;
}
}
接下来需要定义的是播放器对象上的GetDarts
方法。现在我有一天睡觉,我不喜欢这个名字。以Get
开头的方法通常返回一些对象,我对此方法的意图是它代表玩家走向飞镖板并抓住飞镖。在内部,我想它只会更新一个表示玩家持有多少飞镖的计数器。所以我会用原始的伪代码重命名它,也可以在&#39; Player&#39;中实现:
public class Player
{
public string Name { get; private set; }
private int dartsInHand;
public void GrabDarts()
{
dartsInHand = 3;
}
}
接下来要实施的是&#39; HasUnthrownDarts&#39;属性。这是一个bool,只是表示Player
是否有任何飞镖。
public class Player
{
. . .
public bool HasUnthrownDarts { get { return dartsInHand > 0; } }
}
接下来,我们有ThrowDart
方法。现在突然事情变得有点棘手了。我注意到在你的实现中,你让人类玩家输入他们自己的分数,NPC玩家有一个随机生成的分数。所以这意味着一些事情:
现在最简单的方法是创建一个定义播放器类型的bool属性(并将其添加到构造函数中,默认值为false
)。如果有两种以上类型的玩家,我可能会创建一个枚举来定义该类型的Player
对象上的类型和属性。但就目前而言,这样做:
public class Player
{
. . .
public bool IsNpc { get; private set; }
public Player(string name, bool isNpc = false)
{
. . .
IsNPC = isNpc;
}
}
现在,实现ThrowDart
方法。所有这些方法都会得到0到60之间的分数,将其添加到玩家的分数中,并减少玩家手中的飞镖数量。进一步思考之后,我可能还想要返回这个方法中产生的分数,这样一个&#34;圆形分数&#34;如有必要可以计算,我决定输出飞镖数和分数。像往常一样,我编写了我想要使用的代码,并计划在之后实现它。
public int ThrowDart()
{
if (dartsInHand < 1)
{
throw new Exception(string.Format("Player {0} has no darts to throw.", Name));
}
int dartScore;
int thisDartNumber = (3 - dartsInHand) + 1;
if (IsNpc)
{
// Get a random score for non-player characters
dartScore = rnd.Next(0, 60);
Console.WriteLine("{0} threw dart #{1} for {2} point{3}",
Name, thisDartNumber, dartScore, dartScore == 1 ? "" : "s");
}
else
{
dartScore =
ConsoleHelper.GetIntFromUser(string.Format(
"{0}, please enter the score for dart #{1} (0-60): ",
Name, thisDartNumber), "<Invalid score>",
(i) => i >= 0 && i <= 60);
}
Score += dartScore;
dartsInHand--;
return dartScore;
}
正如我写的那样,我意识到我需要从用户那里得到一个整数。这听起来很简单,但实际上需要一些代码来进行验证。用户可以输入非整数字符串,在这种情况下,我必须再次询问它们。他们也可以输入一个超出我们界限的数字(0-60),在这种情况下我也必须再次问他们。因为这段代码是半复杂的,并且因为我有一种感觉,我们可能需要从用户那里得到其他整数(我们可能需要询问他们想要玩多少NPC玩家),我决定创建一个名为{的新类。 {1}}并在那里添加方法ConsoleHelper
。此方法只是从控制台获取一个字符串,将其转换为整数,应用一些自定义验证(如果需要),然后返回它。我已经添加了一些评论来帮助描述它是如何工作的:
GetIntFromUser
我也意识到我们还需要为NPC玩家获取随机数。为此,我创建了一个私有随机属性并在构造函数中设置它:
public static class ConsoleHelper
{
/// <summary>
/// Gets an integer from the user
/// </summary>
/// <param name="prompt">A prompt to display to the user. Can be null.</param>
/// <param name="errorMessage">An error message to display if
/// the user enters an invalid integer. Can be null</param>
/// <param name="intValidator">A function to run which will validate
/// the integer. The integer will be passed to it, and it should
/// return true if the integer is valid. Can be null</param>
/// <returns>The integer entered by the user</returns>
public static int GetIntFromUser(string prompt, string errorMessage,
Func<int, bool> intValidator)
{
int intEntered;
while (true)
{
if (prompt != null) Console.Write(prompt);
var input = Console.ReadLine();
if (int.TryParse(input, out intEntered))
{
if (intValidator == null || intValidator(intEntered))
{
break;
}
}
if (errorMessage != null) Console.WriteLine(errorMessage);
}
return intEntered;
}
}
我也正在更新此方法中的虚构Score属性,所以现在让我们实现它:
public class Player
{
. . .
private readonly Random rnd;
public Player(string name, bool isNpc = false)
{
. . .
rnd = new Random();
}
}
这也是利用public class Player
{
. . .
public int Score { get; private set; }
}
返回该镖号得分这一事实的好时机。对于每一位球员,对于每轮比赛,我都可以向他们概述他们在那轮比赛中的表现:
ThrowDarts
我决定添加的另一件事是&#39; MaxDarts&#39;属性给玩家。这使我可以在一个地方存储飞镖的数量,而不是在任何地方都有硬编码的飞镖。所以我将它添加到. . .
var roundScore = 0;
while (p.HasUnthrownDarts)
{
roundScore += p.ThrowDart();
. . .
}
if (winner != null) break;
Console.WriteLine("{0} threw for {1} points this round.", p.Name, roundScore);
. . .
类并更新了硬编码值。
Player
所以,既然一切都在编译,那剩下要做的最后一件事就是实现public class Player
{
. . .
public int MaxDarts { get; set; }
public Player(string name, bool isNpc = false)
{
. . .
MaxDarts = 3;
}
}
public void GrabDarts()
{
dartsInHand = MaxDarts;
}
public int ThrowDart()
{
. . .
int thisDartNumber = (MaxDarts - dartsInHand) + 1;
. . .
}
方法。为了从用户那里收集人类和计算机播放器信息而不编写重复的代码,我创建了第二个GetPlayers
方法,它接受一个布尔值,说明它是否应该是计算机播放器。然后,GetPlayers
方法只会调用此重载两次 - 一次使用GetPlayers()
,一次使用false
。以下是两种方法:
true
我决定做的另一件事是,在每轮开始时,显示当前的排名。此代码通常是游戏结束时代码的副本(显示最终分数)。因为如果可能的话我们永远不应该编写重复的代码,我将它包装在一个名为public static List<Player> GetPlayers()
{
var players = GetPlayers(false);
Console.WriteLine();
players.AddRange(GetPlayers(true));
return players;
}
private static List<Player> GetPlayers(bool npcPlayers)
{
var players = new List<Player>();
var playerType = npcPlayers ? "NPC" : "human";
int numberOfPlayers = ConsoleHelper.GetIntFromUser(
string.Format("How many {0} players will be playing? ", playerType),
"<Invalid number>", (x) => x >= 0);
for (int i = 1; i <= numberOfPlayers; i++)
{
string name;
if (npcPlayers)
{
// Generate computer player names
name = string.Format("ComputerPlayer{0}", i);
}
else
{
// Get human names from the user
Console.Write("Enter the name for player #{0}: ", i);
name = Console.ReadLine();
}
players.Add(new Player(name, npcPlayers));
}
return players;
}
的方法中:
ShowScores
然后我添加了代码以在每轮开始时和游戏结束时调用此方法:
public static void ShowScores(string message, List<Player> players)
{
if (message != null) Console.WriteLine(message);
foreach (var p in players.OrderByDescending(p => p.Score))
{
Console.WriteLine(" {0}: {1}", p.Name, p.Score);
}
}
现在我们到了那里。我决定将整个游戏包装在另一个循环中,以便允许用户在每个会话中玩多个游戏。要做到这一点,我做了一些事情。首先,向玩家类添加了private static void Main()
{
. . .
while (winner == null)
{
round++;
AnnounceRound(round);
ShowScores("The current standings are:", players);
. . .
}
Console.Clear();
Console.WriteLine("We have a winner! Congratulations, {0}!!", winner.Name);
ShowScores("The final scores are:", players);
. . .
}
方法,以便他们的分数回归到零:
Reset()
然后我将代码包裹在一个循环中,并重置玩家的分数(如果它们已经存在):
public void Reset()
{
Score = 0;
dartsInHand = 0;
}
希望通过我的大脑这次旅行有所帮助! :)
答案 1 :(得分:1)
该代码需要...一些工作。
要回答你的问题,你问为什么foreach
没有打印任何东西。我假设你指的是这个:
foreach (var arrow in arrowList)
{
//Calculation to sum up the entry's in arrowList to see if someone has reached 501 points
}
添加到该集合的唯一内容是AddArrows
这很奇怪,因为您使用默认构造函数创建箭头;调用GetScore
(因为你从未初始化箭头,它将始终返回0),然后用该分数创建一个 new Arrows
对象。
无论如何,调用 函数的唯一事情就是Arrows
的重载构造函数,它甚至是 weirder ;特别是因为你在这里构造了一个新的Player
对象:
Player player = new Player();
player.AddArrows();
所以你的“新”箭头的范围是该构造函数;然后它们就会超出范围并消失。
你应该在其他地方调用该功能;而且大约有一百万个其他东西应该是不同的(开始时没有goto
语句)。无需为您重新编写代码(您不想要;对您有用!)很难说如何来修复它。老实说,该计划非常小;我会重新开始,也许可以和我的导师讨论如何正确设计它。或许可以在这里提出一些与如何设置相关的好问题。
答案 2 :(得分:1)
你学习编程真是太棒了,我想我花一点时间分享一种方法来解决过去曾帮助过我的问题。
在编写真实世界事件和对象的模拟时(这几乎就是所有程序所做的),我发现首先在脑海中播放场景是有帮助的,弄清楚对象是什么,它们的相关属性是什么并且将采取行动,然后尝试编写代码来代表它们。如果该程序是为其他人编写的,那么这将来自现实世界中的讲师或客户。
在编写任何代码之前,请为代码所代表的方案创建流程图。对于飞镖游戏的例子(让我们假设他们正在玩301),我会想象它将如何在现实生活中发生。许多朋友聚在一起,每人拿起3个飞镖,他们决定他们将投掷的顺序,然后,每次一个,每个玩家投掷他们的飞镖并加上他们的分数。这个'回合'分数被添加到他们的总分中。当玩家投掷飞镖使其总分为501或更高时,游戏结束并且该玩家是胜利者。
定义对象以及它们彼此之间的关系。定义关系(一对多,多对多,is-a,has-a等)。
编写一些示例代码,使用想象的对象来表示您喜欢使用它们的方式。这应该真正让您了解哪些对象应具有哪些属性和方法。
这是我可以想象编写代码的一种方式:
List<Player> players = GetPlayers();
Player winner = null;
int round = 0;
while (winner == null)
{
round++;
AnnounceRound(round);
foreach(Player p in players)
{
AnnouncePlayer(p);
p.GetDarts();
while (p.HasUnthrownDarts)
{
p.ThrowDart();
if (p.Score >= 501)
{
winner = p;
break;
}
}
if (winner != null) break;
}
}
Console.WriteLine("We have a winner! Congratulations, {0}!!", winner.Name);
Console.WriteLine("The final scores are:");
foreach(Player p in players.OrderByDescending(p => p.Score))
{
Console.WriteLine(" {0}: {1}", p.Name, p.Score);
}
现在你必须定义'GetPlayers()'方法如何使用类似的技术,ThrowDart()方法如何更新玩家的得分和他的'HasUnthrownDarts'属性(并且可能输出特定投掷的结果得分) ),以及AnnounceRound()和AnnouncePlayer()方法将输出到屏幕的内容。
希望有所帮助。