c# - String to int 回答要做什么
问题描述
嘿,我遇到了一个问题。我想将一个字符串解析为一个整数,因为我正在制作一个控制台游戏,玩家应该选择使用哪个动作。到目前为止,我定义了解析,但我似乎无法找出我将如何遍历我的列表以查看移动是否真的有效。我有一个名为 Move 的列表,其中每个口袋妖怪都有自己的元素,但我将如何在这里引用它是代码
List<Move> FireMoves = new List<Move>();
FireMoves.Add(new Move("Ember"));
FireMoves.Add(new Move("Fireblast"));
List<Move> WaterMoves = new List<Move>();
WaterMoves.Add(new Move("Bubble"));
WaterMoves.Add(new Move("Bite"));
List<Move> GrassMoves = new List<Move>();
GrassMoves.Add(new Move("Cut"));
GrassMoves.Add(new Move("Megadrain"));
GrassMoves.Add(new Move("Razor Leaf"));
这是另一部分。最后两行我认为是正确的,但我不明白如何让控制台理解当按下 1 时移动不使用 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pokemon
{
class Program
{
static void Main(string[] args)
{
List<Move> FireMoves = new List<Move>();
FireMoves.Add(new Move("Ember"));
FireMoves.Add(new Move("Fireblast"));
List<Move> WaterMoves = new List<Move>();
WaterMoves.Add(new Move("Bubble"));
WaterMoves.Add(new Move("Bite"));
List<Move> GrassMoves = new List<Move>();
GrassMoves.Add(new Move("Cut"));
GrassMoves.Add(new Move("Megadrain"));
GrassMoves.Add(new Move("Razor Leaf"));
List<Pokemon> roster = new List<Pokemon>();
// INITIALIZE YOUR THREE POKEMONS HERE
//Tilføj moves
roster.Add(new Pokemon("Charmander", 3, 52, 50, 39, Elements.Fire,FireMoves));
roster.Add(new Pokemon("Squirtle", 2, 48, 65, 44, Elements.Water, WaterMoves));
roster.Add(new Pokemon("Bulbasaur", 3, 49, 49, 45, Elements.Grass, GrassMoves));
Console.WriteLine("Welcome to the world of Pokemon!\nThe available commands are list/fight/heal/quit");
while (true)
{
Console.WriteLine("\nPlese enter a command");
switch (Console.ReadLine())
{
case "list":
// PRINT THE POKEMONS IN THE ROSTER HERE
Console.WriteLine("These are the pokemons that are currently active");
foreach(Pokemon g in roster)
{
Console.WriteLine(roster.IndexOf(g)+" "+g.Name);
}
break;
case "fight":
//PRINT INSTRUCTIONS AND POSSIBLE POKEMONS (SEE SLIDES FOR EXAMPLE OF EXECUTION)
Console.Write("Choose who you should fight against and the pokemon you want to control is mentionened last\n");
Console.Write("To chose your pokemon is mentioned first example of 'Charmander Squirtle', where Squirtle is the opponent\n");
//Console.Write("1=Charmander vs Squirtle\n2=Squirtle vs Charmander\n3=Charmander vs Bulbasaur\n4=Bulbasaur vs Squirtle\n5=Bulbasaur vs Charmander\n6=Squirtle vs Bulbasaur\n");
//READ INPUT, REMEMBER IT SHOULD BE TWO POKEMON NAMES
string input = Console.ReadLine();
//BE SURE TO CHECK THE POKEMON NAMES THE USER WROTE ARE VALID (IN THE ROSTER) AND IF THEY ARE IN FACT 2!
List<String> inputs = new List<string>(input.Split(" ".ToCharArray()));
//BE SURE TO CHECK THE POKEMON NAMES THE USER WROTE ARE VALID (IN THE ROSTER) AND IF THEY ARE IN FACT 2!
Pokemon player = null;
Pokemon enemy = null;
foreach (Pokemon p in roster)
{
if (inputs[0] == p.Name)
{
player = p;
}
if (inputs[1] == p.Name)
{
enemy = p;
}
}
//if everything is fine and we have 2 pokemons let's make them fight
if (player != null && enemy != null && player != enemy)
{
Console.WriteLine("A wild " + enemy.Name + " appears!");
Console.Write(player.Name + " I choose you! ");
//BEGIN FIGHT LOOP
while (player.Hp > 0 && enemy.Hp > 0)
{
//PRINT POSSIBLE MOVES
Console.Write("What move should we use?\n");
foreach(Pokemon p in roster) {
if (player.Name == p.Name)
foreach (Move n in p.Moves)
{
Console.WriteLine(p.Moves.IndexOf(n)+" "+n.Name);
}
}
//GET USER ANSWER, BE SURE TO CHECK IF IT'S A VALID MOVE, OTHERWISE ASK AGAIN
string moveInput = Console.ReadLine();
int moveNo = int.Parse(moveInput);
int move = -1;
//CALCULATE AND APPLY DAMAGE
int damage = -1;
//print the move and damage
Console.WriteLine(player.Name + " uses " + player.Moves[move].Name + ". " + enemy.Name + " loses " + damage + " HP");
//if the enemy is not dead yet, it attacks
if (enemy.Hp > 0)
{
//CHOOSE A RANDOM MOVE BETWEEN THE ENEMY MOVES AND USE IT TO ATTACK THE PLAYER
Random rand = new Random();
/*the C# random is a bit different than the Unity random
* you can ask for a number between [0,X) (X not included) by writing
* rand.Next(X)
* where X is a number
*/
int enemyMove = -1;
int enemyDamage = -1;
//print the move and damage
Console.WriteLine(enemy.Name + " uses " + enemy.Moves[enemyMove].Name + ". " + player.Name + " loses " + enemyDamage + " HP");
}
}
//The loop is over, so either we won or lost
if (enemy.Hp <= 0)
{
Console.WriteLine(enemy.Name + " faints, you won!");
}
else
{
Console.WriteLine(player.Name + " faints, you lost...");
}
}
//otherwise let's print an error message
else
{
Console.WriteLine("Invalid pokemons");
}
break;
case "heal":
//RESTORE ALL POKEMONS IN THE ROSTER
Console.WriteLine("All pokemons have been healed");
break;
case "quit":
Environment.Exit(0);
break;
default:
Console.WriteLine("Unknown command");
break;
}
}
}
}
}
解决方案
我认为这里真正的答案不是你如何迭代,而是你应该如何设计你的移动类来工作。虽然您现在可以忽略设计缺陷并解决它,但最好现在修复它并从一开始就以正确的方式进行。
我将解决您现在可能没有遇到的问题,但它们是您设计存在缺陷的更好例子,如果您正在构建神奇宝贝风格的游戏,它们将成为问题。
问题:
roster.Add(new Pokemon("Charmander", 3, 52, 50, 39, Elements.Fire, FireMoves));
在这里,您说 Charmander 是一种Elements.Fire
类型,并且具有一定的List<Move>
.
但是,应用程序无法知道这些动作是否是 Charmander 可以实际执行的动作。是什么阻止我做:
roster.Add(new Pokemon("Charmander", 3, 52, 50, 39, Elements.Fire, WaterMoves));
对你来说,这现在看起来不是问题。您可以读取列表的名称,因此定义了它的类型,对吗?由于您负责将此列表添加到神奇宝贝的移动中,因此您知道自己在做正确的事情。正确的?
所以让我们想象一下,当你的应用程序变大时,你有以下方法:
public void PerformAttack(Move move, Pokemon attacker, Pokemon defender)
{
}
// Example
PerformAttack(ember, charmander, bulbasaur);
因为Bulbasaur是草类,所以他会受到火焰攻击的额外伤害。但是我们怎么知道选择的招式实际上是火招呢?如果没有存储它的列表的上下文,您将无法知道某个移动是否属于某种类型。(而且你不能使用attacker.Type
,因为如果 Charmander 进行普通攻击,Bulbasaur 不会受到额外伤害,因为 Bulbasaur 对普通攻击没有弱点)。
你没有任何东西可以检查神奇宝贝是否能够执行它被告知要做的动作,你也没有任何东西可以检查神奇宝贝是否对某些动作有一定的弱点/抵抗力。这些是您迟早会遇到的神奇宝贝游戏的基本元素,但是您的设计使您无法做到这一点。
这一切都来自Move
班级中一个糟糕的设计决策:moves don't have a type。为了解决这个问题,您尝试命名您的列表:
List<Move> FireMoves = new List<Move>();
List<Move> WaterMoves = new List<Move>();
List<Move> GrassMoves = new List<Move>();
解决方案:
Move 必须有自己的类型:
public class Move
{
public string Name { get; set; }
public Elements Type { get; set; }
}
现在,您可以解决我展示的所有问题。您所要做的就是在创建移动时设置类型:
List<Move> FireMoves = new List<Move>();
FireMoves.Add(new Move("Ember", Elements.Fire));
List<Move> WaterMoves = new List<Move>();
WaterMoves .Add(new Move("Bubble", Elements.Water));
这也意味着您不再需要单独的基于类型的列表,您可以拥有一个大列表。
List<Move> Moves = new List<Move>();
Moves.Add(new Move("Ember", Elements.Fire));
Moves.Add(new Move("Bubble", Elements.Water));
而且因为所有动作现在都在同一个列表中,所以你的问题变得更容易回答:
到目前为止,我定义了解析,但我似乎无法找出如何遍历我的列表以查看移动是否真的有效。
public bool IsMove(Pokemon target, string userCommand)
{
return target.Moves.Any(move => move.Name.ToLower() == userCommand.ToLower());
}
然后您可以像这样使用它:
string userCommand = Console.ReadLine();
if(IsMove(userCurrentPokemon, userCommand))
{
// Handle attack logic
}
else
{
// Handle non-attack logic
}
请注意,如果您出于特定原因仍希望拥有单独的列表,您仍然可以过滤移动列表:
var fireMoves = Moves.Where(move => move.Type == Elements.Fire).ToList();
var waterMoves = Moves.Where(move => move.Type == Elements.Water).ToList();
var grassMoves = Moves.Where(move => move.Type == Elements.Grass).ToList();
如果有人想评论这个答案专注于现有的神奇宝贝功能而不是 OP 的游戏:那是正确的,但我选择以这种方式处理它,因为 OP 在这种情况下是有效的。我本可以给出一个更中性的“添加属性而不是命名变量”示例,但这并不容易理解,我推断 OP 是编程领域的初学者,可能难以独立实现过于笼统的答案。
推荐阅读
- java - 为什么Controller应该在MVC模式中调用View?
- excel - 过滤具有随机项目范围的数据透视表(连接到外部源)
- postgresql - Postgresql 何时使用 JOIN 列进行分区修剪?
- python - 从数据框中获取特定单元格
- c# - 如何将 ViewModel 中的命令绑定到不属于自己的文件中的 DataTemplate
- apache-spark - Spark 或 Flink 中的 reduce、reduceByKey、reduceGroups
- db2 - Db2 Warehouse控制台打开问题
- ios - 无法将对象附加到闭包内的数组
- visual-studio - Winforms 控件(ObjectListview)在表单托盘中显示为组件,而不是画布上的可视控件
- c# - 当 wpf 立方体旋转时单击一个按钮