How can I pass data to a method in a different class? - c#

I'm a noobie when it comes to programming still, decided I wanted to test my limits and create a tic tac toe game. I'm sure there are much better ways of doing what I'm trying to do but I'm only still learning. When testing what I have so far, I've been running into this problem where a user is asked to input a position (the positions are 1-9, and these positions will eventually be used to tell the program where to put the users X or O). I have 2 classes right now, the Main class and the Board class. After a bit of debugging by putting a stop marker, I've come to realize that when I'm calling a method from my board class in my main class, the data that was put into the arguments for the method isn't carrying over.
Main Class:
class Program {
static void Main(string[] args) {
Board board = new Board();
bool hasWon = false;
string p1;
string p2;
string pos;
int turn = 2;
Console.Write("Please enter a name for player 1: ");
p1 = Console.ReadLine();
Console.Clear();
Console.Write("Please enter a name for player 2: ");
p2 = Console.ReadLine();
Console.Clear();
while (hasWon == false) {
if (turn % 2 == 0) {
Console.WriteLine(p1 + "'s Turn / You are X's");
board.DisplayBoard();
Console.WriteLine();
Console.WriteLine("Please selecet a position: ");
board.SetPos(Console.ReadLine());
Console.WriteLine("Position correctly set: " + board.GetPos());
} else {
Console.WriteLine(p2 + "'s Turn / You are O's");
board.DisplayBoard();
Console.WriteLine();
Console.WriteLine("Please selecet a position: ");
board.SetPos(Console.ReadLine());
Console.WriteLine("Position correctly set: " + board.GetPos());
}
}
}
}
Board Class:
public class Board {
private string pos = "";
private string badPos = "";
public void DisplayBoard() {
Console.WriteLine(" 1 | 2 | 3 ");
Console.WriteLine("-----------");
Console.WriteLine(" 4 | 5 | 6");
Console.WriteLine("-----------");
Console.WriteLine(" 7 | 8 | 9 ");
}
public void SetPos(string pos) {
if (this.pos.Length > 1 || this.pos.Length < 1) {
this.pos = badPos;
IncorrectPosition();
} else if (!this.pos.Contains("1") || this.pos.Contains("2") || this.pos.Contains("3") || this.pos.Contains("4") ||
this.pos.Contains("5") || this.pos.Contains("6") || this.pos.Contains("7") || this.pos.Contains("8") ||
this.pos.Contains("9")) {
this.pos = badPos;
IncorrectPosition();
} else {
this.pos = pos;
}
}
public string GetPos() {
return pos;
}
/*public void setTurn(int turn) {
turn = this.turn;
}*/
private void IncorrectPosition() {
Console.Clear();
Console.WriteLine(badPos + " is not a correct position");
Console.Write("Please enter a position: ");
SetPos(Console.ReadLine());
}
}
To be more specific, the issue is happening in the Main class. When the user is asked to enter a position, they do so by entering a number 1-9. In the Board class, there is a method called SetPos, which will be used to determine where to place the X or the O later on when I develop that. However, I also have a method that makes sure what the user entered was a number 1-9. I don't want to convert it into an integer, I want it to stay a string. Whenever the user enters anything for the position, nothing gets carried over. When using the stop marker and going through the program step by step, in the watch list where I can see what values are being assigned to what variables, my pos variable does get assigned to what I've inputted, but is then lost thus repeating the SetPos and IncorrectPosition. When the IncorrectPosition is being displayed to the console, it shows
is not a correct position
Please enter a position:
Inside the SetPos() method, I have tried a few things to fix this, one of which being I've added a badPos variable, meaning if any of the first two things in my if statement are true, then the value that was passed through the SetPos() method in my Main class would be assigned to badPos, but when printed out to the console, there is no value being displayed on the screen, which is another way of telling me that no value was ever assigned.
I'm not sure how to fix this issue, and any help would be greatly appreciated, thanks!

public void SetPos(string pos)
{
if (this.pos.Length > 1 || this.pos.Length < 1)
{
// by using "this" you are checking "pos" in the class and not the provided value
// I'll assume that that "badPos" here is a placeholder as this would result in this.pos getting set to null because a variable named badPos has yet to be declared in this scope
this.pos = badPos;
IncorrectPosition();
}
else if (!this.pos.Contains("1") || this.pos.Contains("2")
|| this.pos.Contains("3") || this.pos.Contains("4")
|| this.pos.Contains("5") || this.pos.Contains("6")
|| this.pos.Contains("7") || this.pos.Contains("8")
|| this.pos.Contains("9"))
{
// why not just use an int here? also if I'm reading this correctly 2 through 9 will make this true and then tell the player that this is a bad position.
this.pos = badPos;
IncorrectPosition();
}
else
{
this.pos = pos;
}
}
Here is how I would do it:
public void SetPos(int pos)
{
if (pos > 0 && pos < 10)
{
// when you devise a way to store the board state you would check if the position is occupied here and any other checks you want to do - before assigning the value
this.pos=pos;
}
else
{
this.pos = null;
IncorrectPosition();
}
}
So, I used an int and you said you didn't want to use that - I think you will find when you try to construct a data structure to hold your board state - math will be unavoidable. For you use there is no difference between the string "1" and the int 1 except that one is a lot harder to validate then the other
I digress
The reason your checks always went to "bad position" is that in your first if clause by using 'this' you check if the class's copy of pos.length is greater or less than 1 - as it is null at the time of the check its length is 0 and so the clause returns true.
you need to refer the passed variable by just doing pos without the this in front of it.

Related

C# slotmachine supposed to keep one continuous score, somehow keeps multiple separate scores

I've been working on a slotmachine in C# for practise purposes, and the machine itself works as intentional. The points system, however, does not. The game starts at 100 points, and if, for example, the player lose three 5-point bets and wins 40 points on the fourth bet, the expected points would be 100-20+40=120 points. For some reason however, the code treats ALL the previous bets as being 40 point wins as well, bringing the total to 100-20+160=240 points. If the player then lose the fifth 5-point bet, the score jumps to 75.
I start by setting the 'points' value to 100, which should then update everytime the 'game()' function is called upon.
public static void Main()
{
int points = 100;
int num = 0;
Console.WriteLine("Welcome to 'Slotmachine'!\nThe aim of this game is to get a score of 1000 or higher.\nYou lose if you reach 0 or lower.\nPress enter to play");
Console.ReadLine();
Console.Clear();
points = points + game(100);
while(points<1000 && points>0)
{
num = num + 1;
Console.WriteLine("You've played for "+num+" number of round(s)");
points = points + game(points);
}
}
The 'game()' funtion returns the players winnings, which is used to update the 'points' value (Suspect nr 1?).
Inside the game function I have a 'usrbet' which takes an input from the user (1-10), which is then fed into the 'slots()' function to determine the winnings (the 'points' that are fed from 'Main()' are checked to see what the user can bet)
Console.WriteLine("Here are your current points: "+points+"\nHow much would you like to bet?\nmin bet: 1\nmax bet: 10");
try
{
usrbet = Convert.ToInt32(Console.ReadLine());
}
catch
{
usrbet = 1;
}
winnings = slots(usrbet);
int RetWin = winnings - usrbet;
return RetWin;
Here's what the 'slots()' function does, with some examples of the winnings calculations
public static int slots(int usrbet)
{
int Win;
int x;
int y;
int z;
Random slot = new Random();
x = slot.Next(2,10);
y = slot.Next(2,10);
z = slot.Next(2,10);
Console.WriteLine(x+""+y+""+z);
Example 1
if(x == y && y == z && x== 7)
{
Win = usrbet*250;
Console.WriteLine("WOW! That's incredible, you just won "+Win+"!");
}
Example 2
else if(x == z)
{
Win = usrbet*5;
Console.WriteLine("Congratulations, you win "+Win+".");
}
Example 3
else
{
Win = 0;
Console.WriteLine("Ah, bummer. You didn't win anything this time.");
}
After that, the 'Win' value is sent back to 'game()', updating 'winnings'.
I apologize for poor formatting of the question. I'll include a link to the code, in case my problem lies elsewhere in the code: https://dotnetfiddle.net/D5TwL0
I've tried making arrays of the 'bet' and 'usrbet' variables, in an attempt to have a "new" value to update the 'points' with at every run of 'game()', but that changed absolutely nothing other than limiting how many times 'game()' can run before getting an overflow error.
It turns out that the problem wasn't with the code, but with the compiler. Dotnetfiddle is where I made the code and had the issue, but trying it in another compiler, it managed to count just fine.

How to do while loop/Do while loop with sentinel value with switch

Hello I am trying to figure out why my program is not working, it's supposed to output a program in which department codes would be entered and followed by a prompt to enter a mark and so on until Q is entered. I can't seem to get that part working at all. If anyone could help please I will appreciate it.
// declare variables
char deptCode = ' ';
int count = 0;
double markVal, sum = 0, average = 0.0;
{
Console.WriteLine("Enter a department code: ‘C’ or ‘c’ for Computer Science,‘B’ or ‘b’ for History, ‘P’ or ‘p’ for Physics, or enter ‘Q’ or ‘q’ to quit:");
deptCode = Convert.ToChar(Console.ReadLine());
while (char.ToUpper(deptCode) != 'Q')
do
{
Console.Write("Enter a mark between 0 and 100 => ");
markVal = Convert.ToDouble(Console.ReadLine());
{
Console.WriteLine("Enter a department code: ‘C’ or ‘c’ for Computer Science,‘B’ or ‘b’ for History, ‘P’ or ‘p’ for Physics, or enter ‘Q’ or ‘q’ to quit:");
deptCode = Convert.ToChar(Console.ReadLine());
} while (markVal >= 0 && markVal <= 100);
count++;
average = (double)sum / count;
Console.WriteLine("***Error, Please Enter Valid Mark");
Console.WriteLine("The Average mark for Computer Science Students is {0}", average);
Console.WriteLine("The Average mark for Biology Students is {0}", average);
Console.WriteLine("The Average mark for Physics Students is {0}", average);
Console.ReadLine();
{
I am sympathetic to your dilemma and know it can be challenging to learn coding when you are not familiar with it. So hopefully the suggestions below may help to get you started at least down the right path. At the bottom of this is a basic “shell” but parts are missing and hopefully you will be able to fill in the missing parts.
One idea that you will find very helpful is if you break things down into pieces (methods) that will make things easier to follow and manage. In this particular case, you need to get a handle on the endless loops that you will be creating. From what I can see there would be three (3) possible endless loops that you will need to manage.
An endless loop that lets the user enter any number of discipline marks.
An endless loop when we ask the user which discipline to use
And an endless loop when we ask the user for a Mark between 0 and 100
When I say endless loop I mean that when we ask the user for a Discipline or a Mark… then, the user MUST press the “c”, “b” “p” or “q” character to exit the discipline loop. In addition the user MUST enter a valid double value between 0 and 100 to exit the Mark loop. The first endless loop will run allowing the user to enter multiple disciplines and marks and will not exit until the user presses the q character when selecting a discipline.
And finally when the user presses the ‘q’ character, then we can output the averages.
So to help… I will create two methods for you. One that will represent the endless loop for getting the Mark from the user… i.e.…. a number between 0 and 100. Then a second endless loop method that will get the Discipline from the user… i.e. … ‘c’, ‘b’, ‘p’ or ‘q’… and it may look something like…
private static char GetDisciplineFromUser() {
string userInput;
while (true) {
Console.WriteLine("Enter a department code: ‘C’ for Computer Science,‘B’ for Biology, ‘P’ for Physics, or enter ‘Q’ to quit:");
userInput = Console.ReadLine().ToLower();
if (userInput.Length > 0) {
if (userInput[0] == 'c' || userInput[0] == 'b' ||
userInput[0] == 'p' || userInput[0] == 'q') {
return userInput[0];
}
}
Console.WriteLine("Invalid discipline => " + userInput + " try again.");
}
}
Note… the loop will never end until the user selects the characters ‘c’, ‘b’, ‘p’ or ‘q’. We can guarantee that when we call the method above, ONLY those characters are returned.
Next is the endless loop to get the Mark from the user and may look something like…
private static double GetMarkFromUser() {
string userInput;
while (true) {
Console.WriteLine("Enter a mark between 0 and 100 => ");
userInput = Console.ReadLine().Trim();
if (double.TryParse(userInput, out double mark)) {
if (mark >= 0 && mark <= 100) {
return mark;
}
}
Console.WriteLine("Invalid Mark => " + userInput + " try again.");
}
}
Similar to the previous method, and one difference is we want to make sure that the user enters a valid number between 0 and 100. This is done using a TryParse method and most numeric types have a TryParse method and I highly recommend you get familiar with it when checking for valid numeric input.
These two methods should come in handy and simplify the main code. So your next issue which I will leave to you, is how are you going to store these values? When the user enters a CS 89 mark… how are you going to store this info? In this simple case… six variables may work like…
int totalsCSMarks = 0;
int totalsBiologyMarks = 0;
int totalsPhysicsMarks = 0;
double totalOfAllCSMarks = 0;
double totalOfAllBiologyMarks = 0;
double totalOfAllPhysicsMarks = 0;
Now you have something to store the users input in.
And finally the shell that would work using the methods above and you should see this uncomplicates things a bit in comparison to your current code. Hopefully you should be able to fill in the missing parts. Good Luck.
static void Main(string[] args) {
// you will need some kind of storage for each discipline.. see above...
char currentDiscipline = 'x';
double currentMark;
while (currentDiscipline != 'q') {
currentDiscipline = GetDisciplineFromUser();
if (currentDiscipline != 'q') {
currentMark = GetMarkFromUser();
switch (currentDiscipline) {
case 'c':
// add 1 to total number of CS marks
// add currentMarkValue to the total of CS marks
break;
case 'b':
// add 1 to total number of Biology marks
// add currentMarkValue to the total of Biology marks
break;
default: // <- we know for sure that only p could be left
// add 1 to total number of Physics marks
// add currentMarkValue to the total of Physics marks
break;
}
}
}
Console.WriteLine("Averages ------");
//Console.WriteLine("The Average mark for Computer Science Students is {0}", totalOfAllCSMarks / totalCSMarks);
//Console.WriteLine("The Average mark for Biology Students is {0}", ...);
//Console.WriteLine("The Average mark for Physics Students is {0}", ...);
Console.ReadLine();
}

While loop breaks unintentionally

I am in my second week of C# training, so I am pretty new to programming. I have to make a program that returns the smallest integer out of a series of random integer inputs. Once the input = 0, the program should break out of the loop. I am only allowed to use while and for loops. For some reason my program breaks out of loop after the second input and it looks like it doesn't even care if there is a "0" or not. Could you please see where I went wrong? I have been busting my head off with this. Sorry if this question has already been posted by somebody else but I did not find an answer to it anywhere.
PS: The zero input should be taken into account for the comparison.
So this is what I've got so far:
class Program
{
static void Main()
{
int i = 0;
int input = Int32.Parse(Console.ReadLine());
int min = default;
while (input != 0)
{
Console.ReadLine();
if (i == 0)
{
min = input;
break;
}
if (input < min && i !=0)
{
input = Convert.ToInt32(Console.ReadLine());
min = input;
}
i++;
}
Console.WriteLine(min);
}
First of all you will want to re-read the documentation for for- and while-loops. There are several useful pages out there.. e.g. for / while.
Problem
The reason why your loop breaks is that you initialize i with 0.
int i = 0;
Inside your loop you are using the if-statment to break the loop if the condition "i is 0" is met.
if (i == 0)
{
min = input;
break;
}
The input that the user has to provide each iteration of the loop is ignored by your program as you are never storing this kind of information to any variable.
while (input != 0)
{
Console.ReadLine();
// ...
}
Possible Solution
As a beginner it is helpful to tackle tasks step by step. Try to write down each of this steps to define a simple algorithm. As there are many solutions to this problem one possible way could be:
Declare minimum value + assign max value to it
Use a while loop and loop till a specific condition is matched
Read user-input and try converting it to an integer
Check whether the value is 0 or not
4.1. If the value is 0, go to step 8
4.2. If the value is not 0, go to step 5
Check whether the value is smaller than the current minimum value
5.1. If the value is smaller, go to step 6
5.2. If the value is not smaller, go back to step 3
Set the new minimum
Go back to step 3
Break the loop
End program
A program that handles the above steps could look like:
using System;
namespace FindMinimum
{
public class Program
{
static void Main(string[] args)
{
// Declare minimum value + assign initial value
int minValue = int.MaxValue;
// Loop until something else breaks out
while (true)
{
Console.WriteLine("Please insert any number...");
// Read io and try to parse it to int
bool parseOk = int.TryParse(Console.ReadLine(), out int num);
// If the user did not provide any number, let him retry
if (!parseOk)
{
Console.WriteLine("Incorrect input. Please insert numbers only.");
continue;
}
// If the user typed in a valid number and that number is zero, break out of the loop
if (parseOk && num == 0)
{
break;
}
// If the user typed in a valid number and that number is smaller than the minimum-value, set the new minimum
if (parseOk && num < minValue)
{
minValue = num;
}
}
// Print the result to the console
Console.WriteLine($"Minimum value: {minValue}.");
// Keep console open
Console.ReadLine();
}
}
}
Try This:
int input;
Console.Write("Enter number:");
input = Int32.Parse(Console.ReadLine());
int min = input;
while(true)
{
if (input == 0)
break;
if (min > input)
min = input;
Console.Write("Enter number:");
input = Int32.Parse(Console.ReadLine());
}
Console.WriteLine(min);
Console.ReadKey();
I hope it helps.

String to int to answer what move to do

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;
}
}
}
}
}
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.
The problem:
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>();
The solution:
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.
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
}

How do I create a loop for a c# hangman game?

I've made this hangman game but the only problem is I can't figure out which simple loops (For,While, or Do While) I should use to make the program give the user three chances to answer correctly or keep on repeating if they do answer correctly. I was wondering if anyone could guide me in the right direction?
Console.WriteLine("Do you want to play a game?");
string answer = Console.ReadLine();
if (answer == "no")
{
Console.WriteLine("Please Exit Program");
}
System.Threading.Thread.Sleep(1000);
if (answer == "yes")
{
Console.WriteLine(" ");
Console.WriteLine("Welcome to Hangman");
string[] array1 = new string[10];
array1[0] = "hello";
array1[1] = "swami";
array1[2] = "zebra";
array1[3] = "rainbow";
array1[4] = "camp";
array1[5] = "unicycle";
array1[6] = "trivia";
array1[7] = "hockey";
array1[8] = "charlie";
array1[9] = "canada";
Random word = new Random();
int mynumber = word.Next(0, 10);
char[] array2 = array1[mynumber].ToCharArray();
char[] array3 = new char[array2.Length];
Console.WriteLine(array2);
for (int i = 0; i < array2.Length; i++)
{
array3[i] = '*';
}
Console.WriteLine(" ");
Console.WriteLine(array3);
System.Threading.Thread.Sleep(1500);
Console.WriteLine(" ");
int number = 1;
number = number + 1;
Console.WriteLine(" Guess a letter");
char letter = Char.Parse(Console.ReadLine());
Console.WriteLine(" ");
for (int i = 0; i < array2.Length; i++)
{
if (letter == array2[i])
{
Console.Write(letter);
}
else
{
Console.Write("*");
}
}
Console.WriteLine(" ");
}
}
}
Step back from the details of the code for a moment and consider the logic of the game and how the loop would be expressed in human language.
You essentially have two loops:
Repeatedly ask for input within a game.
Repeatedly play a game.
If we were to nest those loops within each other in human language pseudo-code, it might look like this:
while (player wishes to play again)
playGame()
and within playGame():
while (game isn't over)
playTurn()
If you already have the code to conduct a "turn" of the game (the player guesses, the guess is determined to be correct or incorrect, etc.) then all you really need to do is define those conditions.
game isn't over
You can maintain a simple boolean flag for this. Something like:
bool gameIsOver = false;
On any given turn, check the logic of the game. Has the player won? Display a message and set the flag to true. Has the player lost? Same response, just a different message. So the loop ends up being something like:
bool gameIsOver = false;
while (!gameIsOver)
{
// perform turn logic
// when a turn ends the game, set gameIsOver to true
}
The same concept can then be applied to the outer loop. That one needs to define:
player wished to play again
So you might structure it something like:
bool continueWithAnotherGame = true;
while (continueWithAnotherGame)
{
// play a game
// ask the user if they would like to play again
// set continueWithAnotherGame based on the user's reply
}
The physical keywords used to construct the loop become a lot more straightforward once the semantic structure of the loop has been defined. From there you can focus more on the details. For example, you say that a game has 3 "strikes". That doesn't necessitate the use of a counter within a for loop, you can use a separate counter. Something like:
bool gameIsOver = false;
int strikes = 0;
while (!gameIsOver)
{
// perform turn logic
// if the turn is a fail, increment strikes
// if strikes is greater than or equal to 3, set gameIsOver to true
// else if the turn is a pass, continue
// if the game is solved, set gameIsOver to true
}

Categories

Resources