String to int to answer what move to do - c#

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
}

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 can I pass data to a method in a different class?

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.

How do I make a unit test out of my code in C#

So I'm doing a simple poker test in which I have to display the players' names and their hands, and the player who has the higher hand wins. For this test, there are no card suits and ranks (e.g. ten of spades, jack of diamonds), just the type of hand the player is supposed to have (e.g. royal flush, straight, high card, etc). The output should be like this:
Player 1, Jane's hand is: Full House
Player 2, John's hand is: One Pair
Winner: Jane (Full House)
So now, I have all the logic working for this (which you'll see below). However, I'm now supposed to make a unit test for this. I've seen some tutorials but if you see my code below, I don't think it's suitable for a unit test. If anyone can help me fix my code for unit testing, then I highly appreciate it.
Here's the code:
public class PokerGame
{
static void Main(string[] args)
{
// Names of the players
string player1Name, player2Name;
// The array of the poker hands
string[] pokerHands =
{
"High Card", "One Pair", "Two Pair", "Three of a Kind", "Straight", "Flush",
"Full House", "Four of a Kind", "Straight Flush", "Royal Flush"
};
// This will prompt the players to type their name
Console.Write("Enter Player 1: ");
player1Name = Console.ReadLine();
Console.Write("Enter Player 2: ");
player2Name = Console.ReadLine();
// This Random object will deal random hands accordingly
Random randomHand = new Random();
// The random hand index assigned to Player 1
int hand1 = randomHand.Next(pokerHands.Length);
// The random hand index assigned to Player 2
int hand2 = randomHand.Next(pokerHands.Length);
Console.WriteLine("Player 1, " + player1Name + "'s, hand is: " + pokerHands[hand1]);
Console.WriteLine("Player 2, " + player2Name + "'s, hand is: " + pokerHands[hand2]);
// If the random hand index for Player 1 is greater than that for Player 2
if (hand1 > hand2)
{
// Then Player 1 wins
Console.WriteLine("Winner: " + player1Name + " (" + pokerHands[hand1] + ").");
}
// But if it's the opposite
else if (hand1 < hand2)
{
// Player 2 wins
Console.WriteLine("Winner: " + player2Name + " (" + pokerHands[hand2] + ").");
}
// And if they have the same hands
else
{
Console.WriteLine("It's a tie!");
}
Console.ReadLine();
}
}
EDIT: After getting help from some friends and from people on Facebook (LOL), I managed to refactor some of my code into this:
public class PokerDealer
{
string[] hands =
{
"High Card", "One Pair", "Two Pair", "Three of a Kind", "Straight", "Flush",
"Full House", "Four of a Kind", "Straight Flush", "Royal Flush"
};
public void DealCards(int hand1, int hand2, string name1, string name2)
{
Random randomHand = new Random();
hand1 = randomHand.Next(hands.Length);
hand2 = randomHand.Next(hands.Length);
Console.WriteLine("Player 1, " + name1 + "'s hand: " + hands[hand1]);
Console.WriteLine("Player 2, " + name2 + "'s hand: " + hands[hand2]);
CheckWinner(hand1, hand2, name1, name2);
}
public int CheckWinner(int win1, int win2, string name1, string name2)
{
int winner;
if (win1 > win2)
{
winner = win1;
Console.WriteLine("Winner: " + name1 + " (" + hands[winner] + ")");
}
else if (win1 < win2)
{
winner = win2;
Console.WriteLine("Winner: " + name2 + " (" + hands[winner] + ")");
}
else
{
winner = 0;
Console.WriteLine("It's a tie!");
}
return winner;
}
}
DealCards() is basically my randomizer (gives out random cards) and CheckWinner(), well, checks who has the winning card. Also, I've already run unit tests for the winning conditions of both players, and they work! Now here are some problems:
How will I now test if they have the same card? (The last condition)
I'm trying to run a test for DealCards() to see if the players indeed get random cards and to see if it doesn't go out of the range (0 to 9; probably more important). For this one, I don't know how I will assert the latter condition. Here's the testing method:
[TestMethod]
public void RandomHand()
{
// Tests if players are given a random hand within the range
PokerDealer pd = new PokerDealer();
Random randomHand = new Random();
int randomHandIndex = randomHand.Next(10);
pd.DealCards(randomHandIndex, randomHandIndex, "Player 1", "Player 2");
}
To make the code better suited for unit testing, my advice would be: Only the Main() method should print text via Console.Write(). All the other methods should only return values. This way your tests can call the methods and check your assumptions about the return values. For example, CheckWinner() should return the text it currently writes to the console so you can verify in a test that the string returned by CheckWinner() (maybe rename to GetResultText() or something) matches the input parameters.
As for testing certain scenarios like both players having the same hand there are two options:
Create a mockup for Random. This way you can control which values it returns when used within a unittest. This is an advanced topic but it is a very useful technique for unit testing. Google C# mocking.
Use the same seed for the Random-instance every time (of course only when testing!); this way the values returned by the Next() calls will be always the same and you can use them for testing. For example
Random r = new Random(9);
Console.WriteLine(r.Next(10));
Console.WriteLine(r.Next(10));
will give you two fours in a row - every time.
As for your last point, how to test if ranodm returns random numbers within the given range. Why would you do that? Random it is not part of your code, so it does not make sense for you to test it.

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
}

Printing an array in a method, from a different class?

I'm a fairly inexperienced programmer, and i'm currently working on a Console Application project. It's basically a little 'mathematics game'; the application generates two random numbers, that have either been added, subtracted, multiplied or divided against each other randomly. The answer is shown on screen and the user has to pick from the menu which is the right mathematical operator, once the correct answer is picked the application then displays on screen how long it took for the user in milliseconds to input the correct answer.
Now I want to save the times of the players in an array that can be called up later with all the scores. I need to include a method in this programme and I figured a method to save the times into an array would be suitable. I seem to have stumbled across a little problem though.
I'm not quite sure what's wrong:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Mathgame
{
class Program
{
}
class arrayclass
{
public static void saveInArray(int duration)
{
int[] TopTenScores = {000,1000,2000,3000,4000,5000,6000,7000,8000,9000};
if (duration < 1000)
{
duration = TopTenScores[000];
}
else if ((duration >= 1000) && (duration <= 1999))
{
duration = TopTenScores[1000];
}
else if ((duration >= 2000) && (duration <= 2999))
{
duration = TopTenScores[2000];
}
else if ((duration >= 3000) && (duration <= 3999))
{
duration = TopTenScores[3000];
}
else if ((duration >= 4000) && (duration <= 4999))
{
duration = TopTenScores[4000];
}
else if ((duration >= 5000) && (duration <= 5999))
{
duration = TopTenScores[5000];
}
else if ((duration >= 6000) && (duration <= 6999))
{
duration = TopTenScores[6000];
}
else if ((duration >= 7000) && (duration <= 7999))
{
duration = TopTenScores[7000];
}
else if ((duration >= 8000) && (duration <= 8999))
{
duration = TopTenScores[8000];
}
else if ((duration >= 9000) && (duration <= 9999))
{
duration = TopTenScores[9000];
}
Console.WriteLine(TopTenScores);
}
static void Main(string[] args)
{
int intInput, num1, num2, incorrect, array1;
float answer;
string input;
System.Random randNum = new System.Random();
Console.WriteLine("Welcome to the Maths game!");
Console.WriteLine("(Apologies for the glitchiness!)");
Console.WriteLine();
Console.WriteLine("Please choose from the following options:");
Console.WriteLine();
retry:
Console.WriteLine("1 - Test your Maths against the clock!");
Console.WriteLine("2 - Exit the application.");
Console.WriteLine("3 - Top scores");
Console.WriteLine();
input = Console.ReadLine();
intInput = int.Parse(input);
if (intInput == 1)
{
goto start;
}
else if (intInput == 2)
{
goto fin;
}
else if (intInput == 3)
{
array1 = array1.saveInArray;
goto retry;
}
Now, in the last 'else if' statement in the code, you can see my variable array1 trying to call the method, but no matter what I do I keep getting errors.
This is the only error I have at the moment, but I have a feeling soon as I resolve that error, another will come up. For now i'm just determined to get past this error:
'int' does not contain a definition for 'saveInArray' and no extension method 'saveInArray' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?).
Any help would be kindly appreciated, apologies in advanced for my ugly written code! And thank you to any help that I receive!
Regards,
Omar.
Okay,
There's quite a bit in this code that needs fixing TBH.
I'll start with your error first:
You are declaring the variable array1 as an integer. In C# integers are primitive types. This means that they have no methods and no class members. So, when you call array1.saveInArray the compiler is basically saying "the type integer doesn't have any methods... I can't find an appropriate method to match your call".
Instead of calling array1.saveInArray I think what you meant to call was arrayclass.saveInArray(x).
Notice the x in that call above. I'm passing a variable called x which is of type int into the function saveInArray().
This brings us to the second error. If saveInArray was a property, then you could just go arrayclass.saveInArray. However, it is a function which requires an argument... namely an integer.
When you call arrayclass.saveInArray(someInteger) you are passing someInteger as an argument into a method. The method is then free to use this argument to do its calculations.
That should fix your most basic errors and hopefully you can compile.
Moving on to some other errors that will cause you problems at runtime:
In the method saveInArray you are declaring an integer array called TopTenScores.
You are declaring this fine... however later on when you are indexing into TopTenScores, you are using an index that is way out of range of TopTenScores.
Here is your declaration of TopTenScores:
int[] TopTenScores = {000,1000,2000,3000,4000,5000,6000,7000,8000,9000};
Notice that there are 10 numbers in this declaration. This means that the max index you can have is 9. Why? Because arrays start indexing at 0 in C#.
I think you might be thinking that this array is associative... however this is not the case. When you do TopTenScores[1000] you are saying "give me the value at index 1000". This value does not exists and you will get a runtime error.
Instead, you would want to call TopTenScores[1] if you wanted to access the value 1000.
Also, you are not overwriting the default value with the new top score, rather you are overwriting the new top score with the default value. I don't think this is intended. Instead, switch your calls from this: duration = TopTenScores[1000];
to this: TopTenScores[1] = duration;
Edit: Lastly, as the commenter pointed out, using goto is bad practice and greatly discouraged. You will understand why later on as you start to understand program flow and organization better. For now, it is best to try and avoid the habit of using goto. goto maps to a low level system construct, which we should avoid when using a higher level language like C#. Your code can get confusing and error prone quickly with using goto.
Anyways, feel free to ask more questions/comment etc if you have questions or you need to clarify something. Welcome to StackOverflow!
One of your problems is that you're missing the fundamental concept of what an array is. Think of an array as a row of numbered mailboxes. This line of code:
int[] TopTenScores = {000,1000,2000,3000,4000,5000,6000,7000,8000,9000};
is creating an array of 10 integers that look something like this in memory:
Index Value
----- -----
0 0
1 1000
2 2000
3 3000
4 4000
5 5000
6 6000
7 7000
8 8000
9 9000
It is unclear how this is a useful structure to represent your top scores, and I'm not sure what your saveInArray method is trying to do. In that method, here's how one of your lines of code is interpreted:
duration = TopTenScores[1000];
What that means is "take what's at index 1000 of TopTenScores and store it in duration." As you can see from the table above, there is no index 1000, and besides, that code has nothing to do with saving a top score.
Another problem you're having is that you don't seem to have your algorithm in place for accomplishing the task. For the top ten functionality, try breaking down what needs to be done into instructions on how you would do it manually if you were a score keeper. It would be something like this:
I keep track of the top scores by stacking index cards with the scores on them in order of highest to lowest. At first, I have no index cards.
I can do two things: record scores and tell someone the top ten scores.
When someone asks me to record a score, I:
Write the score down on an index card
Look through the stack of previous scores in order until I find a score lower than this new score.
If I find a score that was lower than this new one, I place the card on top of the lower score.
Otherwise, if this score is the lowest one of the bunch, including if this is the first score recorded, I'll place the score at the bottom of the stack.
When someone asks me to tell them the top 10 scores, I:
Go through the first 10 cards or all the cards if I have less than 10.
For each of those scores, write them down in order.
Give the list of scores to the one requesting them.
It may seem silly to do this, but most programs are really only sequences of simple steps, and as a programmer, you need to be able to determine those steps before translating them into a language that the compiler can understand. Once you formulate the problem in simple terms, you can start translating it into code for example:
// You can think of a role a person would do for a manual process as a class
// in a program.
public class ScoreKeeper
{
// Our high score list (stack of cards) is empty to begin with. Unlike
// arrays, lists allow us insert items rather than placing them in
// numbered slots.
private List<int> _scores = new List<int>();
// This is the method for when someone asks us to record a score. The
// "score" parameter is the new score which you can think of as being
// written on a card.
public void RecordScore(int score)
{
// Go through each of the existing scores. "i" is the index in the
// list.
for (int i = 0; i < _scores.Count; i++)
{
// See if the new score is less than the score at index #i
if (_scores[i] < score)
{
// It is lower than this new score. Insert the new score
// above that score.
_scores.Insert(i, score);
// We're done. Stop looping and exit RecordScore.
return;
}
}
// If we get here, we found no scores lower than this new one. Add
// this score to the bottom of the stack.
_scores.Add(score);
}
// This is the method for when someone asks us for the top 10 scores.
// Notice that we return an array of integers, which will represent
// our piece of paper we hand back to the one requesting the scores.
public int[] GetTop10Scores()
{
// We start with a blank piece of paper.
int[] result = new int[10];
// Go through the scores. The first 10 are the top 10 because
// RecordScore puts them in order. We also need to make sure
// we don't try to get more scores than we've recorded.
for (int i = 0; i < 10 && i < _scores.Count; i++)
{
// Write down the score on the paper
result[i] = _scores[i];
}
// Send back the list of scores to the requester
return result;
}
}
Now, inside of your main program, you can create a ScoreKeeper and ask it to do its score keeping:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to the Maths game!");
Console.WriteLine("(Apologies for the glitchiness!)");
Console.WriteLine();
Console.WriteLine("Please choose from the following options:");
Console.WriteLine();
// This object keeps track of scores
ScoreKeeper scoreKeeper = new ScoreKeeper();
bool keepRunning = true;
while (keepRunning)
{
Console.WriteLine("1 - Test your Maths against the clock!");
Console.WriteLine("2 - Exit the application.");
Console.WriteLine("3 - Top scores");
Console.WriteLine();
string input = Console.ReadLine();
int intInput = int.Parse(input);
if (intInput == 1)
{
// You should avoid gotos. Try writing a method instead
// Play the game and get the player's score.
int newScore = PlayGame();
// Have the score keeper record the new score.
scoreKeeper.RecordScore(newScore);
}
else if (intInput == 2)
{
keepRunning = false;
}
else if (intInput == 3)
{
// Get the top scores from the score keeper
int[] topScores = scoreKeeper.GetTop10Scores();
// Print each score
for (int i = 0; i < topScores.Length; i++)
{
Console.WriteLine("{0}: {1}", i + 1, topScores[i]);
}
}
}
}
private static int PlayGame()
{
// Put your game logic in here. Return the score.
}
}
Once you become more familiar with the fundamentals of programming, you'll find there are existing classes you can reuse, like SortedList, that can already take care of common tasks like maintaining an ordered list.

Categories

Resources