Reputation: 43
Hey I am stuck with a problem. I want to parse a string into a integer because I am making a console game where the player should choose which move to use. So far I defined the parse but I can't seem to find out how I would iterate over my list to see if the move is actually valid. I have a list called Move where each pokemon has its own elemental but how would I reference this here is the code
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"));
Here is the other part. The last two lines I think it's right but I don't get how I would make the console understand that when 1 is pressed move no 1 is used
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;
}
}
}
}
}
Upvotes: 0
Views: 148
Reputation: 13773
I think the real answer here is not so much how you iterate, but how you should've designed your move class to work. Whil you could ignore the design flaw now and work around it, it's much better to fix it now and do it the right way from the start.
I'm going to address issues that you may not have been facing now, but they are better examples of why your design is flawed, and they will become issues if you're building a Pokémon style game.
roster.Add(new Pokemon("Charmander", 3, 52, 50, 39, Elements.Fire, FireMoves));
Here, you say that Charmander is a Elements.Fire
type, and has a certain List<Move>
.
However, the application has no way of knowing whether these are moves that Charmander can actually perform. What is stopping me from doing:
roster.Add(new Pokemon("Charmander", 3, 52, 50, 39, Elements.Fire, WaterMoves));
To you, this doesn't look like an issue right now. You can read the name of the list, so its type is defined, right? Since you're responsible for adding this list to the pokémon's moveset, you know you're doing the right thing. Right?
So let's imagine that when your application gets bigger, you have the following method:
public void PerformAttack(Move move, Pokemon attacker, Pokemon defender)
{
}
// Example
PerformAttack(ember, charmander, bulbasaur);
Because Bulbasaur is a grass type, he takes extra damage from fire attacks. But how do we know that the chosen move is actually a fire move? Without the context of the list it is stored in, you have no way of knowing if a certain move is of a certain type. (And you can't use attacker.Type
because if Charmander performs a Normal attack, Bulbasaur does not take extra damage from that since Bulbasaur does not have a weakness to Normal attacks).
You have nothing in place to check if a Pokémon is able to perform the move it is told to do, and you have nothing in place to check if a Pokémon has a certain weakness/resistance to certain moves. These are essential elements of the Pokémon games that you are going to run into sooner rather than later, but your design is making it impossible to do this.
This all comes from a bad design decision in the Move
class: moves don't have a type. To combat this, you've tried to name your lists:
List<Move> FireMoves = new List<Move>();
List<Move> WaterMoves = new List<Move>();
List<Move> GrassMoves = new List<Move>();
Move must have a type of its own:
public class Move
{
public string Name { get; set; }
public Elements Type { get; set; }
}
Now, you can fix all the problems I showcased. All you have to do is set up the type when you create the move:
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));
This also means that you no longer need to have separate type-based lists, you can have one big list.
List<Move> Moves = new List<Move>();
Moves.Add(new Move("Ember", Elements.Fire));
Moves.Add(new Move("Bubble", Elements.Water));
And because all moves are now part of the same list, your question becomes much easier to answer:
So far I defined the parse but I cant seem to find out how I would iterate over my list to see if the move is actually valid.
public bool IsMove(Pokemon target, string userCommand)
{
return target.Moves.Any(move => move.Name.ToLower() == userCommand.ToLower());
}
Which you can then use like this:
string userCommand = Console.ReadLine();
if(IsMove(userCurrentPokemon, userCommand))
{
// Handle attack logic
}
else
{
// Handle non-attack logic
}
Note that if you still want to have separate lists for a particular reason, you can still filter the move list:
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();
If anyone wishes to comment that this answer is focusing on existing Pokémon features rather than OP's game: that is correct, but I chose to approach it this way because OP is workig in this context. I could've given a more neutral "add a property instead of naming a variable" example, but that's not as easy to understand, and I'm inferring that OP is a beginner to the field of programming who may struggle with independently implementing an overly generalized answer.
Upvotes: 1
Reputation: 23732
you need to iterate only through the player moves. Since the choice has been made
for (int i = 0; i < player.Moves.Count; i++)
{
Console.WriteLine(i + " " + player.Moves[i].Name);
}
"to see if the move is actually valid" and "I dont get how I would make the console understand that when 1 is pressed move no 1 is used"
any positive move number that is smaller then the amount of items in your list is a valid input. If you present the user the index as choice then you can use the index to access the item/move.
if(moveNo >= 0 && moveNo < player.Moves.Count)
{
//access move by index
var move = player.Moves[moveNo]
}
else
{
// not a valid move
}
Upvotes: 0