using methods for program? - c#

So I did this hangman game, and it works perfectly fine, the only problem is that I want to use methods to organize everything.
And yes, it is a school project. I tried my best but whenever I try to put a part of the program in a method it's as if I removed a variable and it underlines it in red.
I removed them for now so it's more clear. also, the file I used contained 19 8 letters max words, one on each line.
Can someone tell me how I can incorporate methods without ruining the whole thing? also English isn't my first language plz excuse any mistakes, the code was in french and I translated it for this question. thank you very much. I appreciate your time and effort :)
using System;
using System.IO;
namespace TP3
{
class Program
{
public const String Dico = "dico.txt";
public static void Welcome()
{
//Mot de bienvenue
Console.WriteLine("Welcome to hangman !");
}
public static void Goodbye()
{
Console.WriteLine("thx for playing, goodbye!");
}
public static void Program()
{
int SolvedWords= 0;
string WordToGuess= "";
int NumberOfLetters ;
int x = 0;
int WordTried = 0;
Console.WriteLine("");
Console.WriteLine("Do you wanna guess a word ? oui or non.");
Console.WriteLine("you have 8 chances per word.");
string Answer= Console.ReadLine();
Answer= Answer.ToLower();
while (Answer== "oui" && WordTried <19)
{
const int Lives= 8;
int LostLives= 0;
int LivesLeft= 8;
int LettersGuesed= 0;
x += 1;
WordTried += 1;
if (WordTried <= 20 && WordTried >1)
{
Console.WriteLine("Do you wanna guess a word ? oui or non.");
Answer= Console.ReadLine();
Answer= Answer.ToLower();
}
//Read a word in the file
int compteur = 0;
string ligne;
// Read file and show on the line
System.IO.StreamReader file = new System.IO.StreamReader(#"dico.txt");
while ((line = file.ReadLine()) != null)
{
compteur++;
if (compteur == x)
{
WordToGuess= line;
}
}
file.Close();
char[] table;
table = new char[WordToGuess.Length];
for (int i = 0; i < table.Length; i++)
{
table[i] = WordToGuess [i];
}
//change each letter into a *
Console.WriteLine("here’s the word to guess : ");
string HiddenWord = "********";
char[] table2;
table2 = new char[WordToGuess.Length];
for (int i = 0; i < table2.Length; i++)
{
table2[i] = HiddenWord[i];
}
for (int i = 0; i < table2.Length; i++)
{
Console.Write(table2[i]);
}
Console.WriteLine("");
//guess the word
while (LettersGuesed< WordToGuess.Length && LivesLeft> 0)
{
Console.WriteLine("");
/* Console.WriteLine("Devinez une seule Letterdu mot. Ne pas écrire une Letter plus d'une fois de suite. Si c'est le cas, recommencez le jeu.");*/
string Letter= Console.ReadLine();
Letter= Letter.ToLower();
NumberOfLetters = Letter.Length;
char[] table3;
table3= new char[NumberOfLetters ];
for (int i = 0; i < table2.Length; i++)
{
if (table[i].Equals(Letter[0]))
{
Table2[i] = Letter[0];
LettersGuesed+= 1;
}
}
for (int i = 0; i < table2.Length; i++)
{
Console.Write(table2[i]);
}
if (WordToGuess.IndexOf(Lettre) < 0)
{
Console.WriteLine("");
Console.WriteLine("wrong letter.");
LostLives+= 1;
LivesLeft= Lives- LostLives;
Console.WriteLine("you have " + LivesLeft+ " lives left.");
}
if (WordToGuess.IndexOf(Lettre) >= 0)
{
Console.WriteLine(" ");
Console.WriteLine("right !");
Console.WriteLine("you have " + LivesLeft+ " lives left.");
}
if (LettersGuesed== WordToGuess.Length && LivesLeft> 0)
{
SolvedWords+= 1;
Console.WriteLine(" ");
Console.WriteLine("you found the word !");
Console.WriteLine("you found " + SolvedWords+ " on" + WordTried + " words so far.");
}
if (LivesLeft== 0)
{
Console.WriteLine("you couldnt guess the word.");
Console.WriteLine("the word was :");
for (int i = 0; i < table.Length; i++)
{
Console.Write(table[i]);
}
Console.WriteLine(" ");
Console.WriteLine("you found " + SolvedWords+ " on" + WordTried + " words so far.");
}
if (WordTried == 19)
{
Console.WriteLine("no more words to guess.");
}
}
}
}
static void Main(string[] args)
{
Welcome();
Programme();
Goodbye();
}
}
}

Im not going to make every method for your project, I'll help kickstart on how to think about it. Look at your current code for reading the file of words. You can move that into a method -
public string[] ReadWordsFromFile()
{
string file = "path to your file here";
return File.ReadAllLines(file);
}
Or pass the file path as parameter -
public string[] ReadWordsFromFile(string filePath)
{
return File.ReadAllLines(filePath);
}
Next you can have a method to get random words -
public string GetRandomWord(string[] wordsArray)
{
Random random = new Random();
int randomIndex = random.Next(0, wordsArray.Length);
return wordsArray[randomIndex];
}
Note - words can be repeated if you do it this way, if you don't want that - then add logic to remove that item from the list once its used in the game. If you remove it within this method, its not actually going to remove it from the game, as you'll still be passing the entire array when getting a new word. Ill leave the implementation of that logic to you, if you want it.
In the "game controller" code -
you can use the above methods like this -
string file = "your path to txt file";
string[] allWords = ReadWordsFromFile(file);
string WordToGuess = GetRandomWord(allWords);
May be your next goal should be something like this -
public void GameControler()
{
// get all words here and other logic before game starts
while (Attempts > 0)
{
string WordToGuess = GetRandomWord(wordsArray);
// get letterGuessed from user
bool letterExists = CheckIfLetterExists(WordToGuess, letterGuessed);
if (!letterExists)
{
Attempts--;
ExecuteWrongGuessMethod(x, y);
}
else
{
ExecuteRightGuessMethod(w);
}
}
}
public bool CheckIfLetterExists(string word, string letter)
{
if (word.Contains(letter)) return true;
else return false;
}
public void ExecuteWrongGuessMethod(string passWhatYouNeedTo, int somethingElse)
{
// what to do when the guess is wrong e.g. Console.Writeline("wrong guess");
}
public void ExecuteRightGuessMethod(string word)
{
// logic when guess is right. e.g. Show the letter guessed within the word on the console etc.
}
All of this isn't the best way to do it. BUT I personally feel this is logically next step a beginner takes after what you've implemented. Seeing a fully well-developed program might be too much without understanding atleast some basic concepts of OOP.
After learning how to create Methods and use them, then comes classes and objects. Which should be implemented in this game, but this is all for now. I recommend you do a short C# course on coursera etc or even youtube. And slowly move towards a better understanding of SOLID principles. And by SOLID I mean an acronym for the 5 principles and not the actual word. All the best.

Related

Searching alorithm that accounts for mistakes

I'm still a noob at working with data so I don't know where to look for more advanced algorithms. Where can I find the info about a string searching algorithm that doesn't require exact input?
I want to make a little programm that works pretty much like this: there are quotes and tags asociated with them, a random tag appears and the user has to input a quote that might be compatible with it, my lil programm searches if it has the quote, returns true or false and shows you the number of mistakes.
Here's what i've done so far
public readonly struct Quote
{
public readonly string[] Tags;
public readonly string TheQuote;
public Quote(string theQuote, params string[] tags)
{
Tags = tags;
TheQuote = theQuote;
}
}
static void MatchTag()
{
Console.WriteLine("Input a quote that might fit the tag");
var input = Console.ReadLine();
var inpL = input.Length;
var allowedMistakes = 5;
var possibleQuotes = quotes.Where(q => q.Tags.Contains(currTag) && inpL.IsInRange(q.TheQuote.Length, q.TheQuote.Length < 10 ? 2 : q.TheQuote.Length / 10));
foreach (var quote in possibleQuotes)
{
var quoteTxt = quote.TheQuote;
int diff = quoteStr.Length - inpL, length, mistakesNum=0;
if (diff < 0)//go through the smallest string to not throw an error
{
length = quoteTxt.Length;
mistakesNum += -diff;
}
else
length = inpL;
bool clear = false;
for (int i = 0; i < length; i++)
{
if (input[i] != quoteTxt[i])
mistakesNum++;
if (mistakesNum > allowedMistakes)
{
clear = true;
break;
}
}
if (clear)
continue;
//show that you are right and return;
Console.WriteLine("The quote fits the tag!");
Console.WriteLine("Mistakes: " + mistakesNum);
return;
}
Console.WriteLine("The quote doesn't fit the tag!");
}

Passing a value to a class keeps returning 0

this might be a simple/dumb question but I'm trying to figure out why my code keeps returning 0. I don't think my syntax for passing the value is correct but I cant figure out the proper way of doing it.
class ICESMARK
{
static int ICECount = 0;
public double average = 0;
public double[] ICES = new double[8];
public ICESMARK(double Mark)
{
Mark = ICES[ICECount];
if (ICECount == (ICES.Length - 1))
{
for (int x = 0; x < ICES.Length; x++)
{
average += ICES[x];
}
average /= ICES.Length;
}
ICECount++;
}
}
class Program
{
static void Main(string[] args)
{
ICESMARK[] ICE = new ICESMARK[8];
//LABSMARK[] LAB = new LABSMARK[6];
double userInput;
for (int counter = 0; counter < ICE.Length ; counter++)
{
Console.Write("Please enter your mark for ICE{0}: ", counter + 1 );
bool ifInt = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = new ICESMARK(userInput);
}
Console.WriteLine(ICE[1].average);
Console.ReadLine();
}
}
ICE[1].average - Displays 0
Also if anyone has a more efficient way of doing this, feel free to let me know. Except for the average, is gotta be a calculation, cant use the built in method.
Simplest code to get your work done:
void Main()
{
double[] ICE = new double[8];
double userInput = 0.0;
for (int counter = 0; counter < ICE.Length; counter++)
{
Console.WriteLine($"Please enter your mark for ICE {counter}: ");
bool isNumerical = false;
while(!isNumerical)
isNumerical = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = userInput;
}
Console.WriteLine("Average : " + ICE.Average());
Console.ReadLine();
}
How it works:
Removed all the frills, you don't need an extra class just for this purpose
Made it mandatory for code to enter valid double value to fill all the slots
Finally used Linq Average to calculate Average value
I want to clarify that yes there are easier ways to solve this, but the entire point of the project was to use a class and it specifically says I cant use built in methods such as "array.average".
Sorry that my code was super messy, I was honestly all over the place and very confused. Having that said I finally arrived to this solution. Thanks to everyone who tried to help! really appreciate it, some tips here were very helpful in solving and cleaning up my code.
class ICESMARK
{
public static int ICECount = 0;
public static double average = 0;
public ICESMARK(double Mark)
{
average += Mark;
if (ICECount < 8) { ICECount++; }
if (ICECount == 8) { average /= ICECount;}
}
}
class Program
{
static void Main(string[] args)
{
ICESMARK[] ICE = new ICESMARK[8];
double userInput;
for (int counter = 0; counter < ICE.Length ; counter++)
{
Console.Write("Please enter your mark for ICE{0}: ", counter + 1 );
bool ifInt = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = new ICESMARK(userInput);
Console.WriteLine(ICESMARK.ICECount);
}
Console.WriteLine(ICESMARK.average);
Console.WriteLine(ICESMARK.ICECount);
Console.ReadLine();
}
}

Noob needing help on breaking out of loop

I'm very sorry this is such an easy question, I'm just starting out. I've created code that allows a user to enter a number of random dice rolls, and outputs the sum of those rolls. I've now been asked to create a loop that repeats these steps, including the prompt, until the user types 'quit'. My issue is that my code converts the string to an integer, so typing anything kills the code. Any tips of how to insert the loop and break? My code is:
static void Main(string[] args)
{
Random random = new Random();
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
int numberDice = Convert.ToInt32(numberDiceString);
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.ReadKey();
}
I wouldn't use a "while(true)" statement. As someone pointed out in the comments i would prefer using the right condition in there.
That being said i would do it this way:
static void Main(string[] args)
{
Random random = new Random();
string numberDiceString;
int numberDice;
Console.WriteLine("Enter a number of dice to roll:");
while ((numberDiceString = Console.ReadLine()) != "quit")
{
bool parsed = int.TryParse(numberDiceString, out numberDice);
if (!parsed)
{
//Handle the error. The user input was not a number or "quit" word
break;
}
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.WriteLine("Enter a number of dice to roll:");
}
}
I have to say that i prefer this way because you can easily see when the loop will stop. Also i added an error handling that you should be doing (What happen if the user enters any words that are not numbers?).
Hope this helps.
This change should be fairly simple. What you need to do is to create a while loop, and then a check before you actually parse for an int. The psuedocode for this would be something like.
while(true) {
//Ask for input
//Check if it equals "quit"
//If so -> break;
//If not convert to int
//For Loop for dice rolls
//Print Total
}
I'm sure it could be a little more elegant than this, and you would want to put some more checks to make sure that invalid input doesn't crash the program, but it should get the job done.
This is a very simple solution that shows how to parse the user input.
using System;
namespace Simpleton
{
class Program
{
static public int GetChoice()
{
int choice = 0;
while (true)
{
Console.Write("Enter number of rolls or \"quit\" to finish: ");
var answer = Console.ReadLine();
if (String.Compare(answer, "quit", true) == 0)
{
return 0; // Done
}
if (Int32.TryParse(answer, out choice))
{
return choice;
}
}
}
static void Main(string[] args)
{
var choice = 0;
while ((choice = GetChoice()) > 0)
{
Console.WriteLine($"You'll be looping {choice} times.");
for (int tries = 0; tries < choice; tries++)
{
// Looping
}
}
}
}
}
Try this code:
static void Main(string[] args)
{
Random random = new Random();
while(true)
{
String numberDiceString = "";
int numberDice = 0;
Console.WriteLine("Enter a number of dice to roll:");
numberDiceString = Console.ReadLine();
if (numberDiceString == "quit") { return; }
int total = 0;
if (Int32.TryParse(numberDiceString, out numberDice))
{
total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
}
Console.WriteLine(total);
}
}
I'm not a C# programmer, but you can test for "quit" explicitly and use a goto
BeginLoop:
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
if (numberDiceString == "quit")
{
goto EndLoop;
}
int numberDice = Convert.ToInt32(numberDiceString);
/* Rest of code you want to do per iteration */
goto BeginLoop;
EndLoop:

Streamreader and Readline

Today I'm having trouble with something basic and just having a complete lapse trying to remember how to do this. What I'm trying to do is simply use a number from a file as the int variable for my whole program. Using C#.
StreamReader read = new StreamReader("../../data.dat");
string input=(Console.ReadLine());
int num = Convert.ToInt32(input);
System.Console.WriteLine("Range of Numbers: 1 - " + num);
for (int i = 1; i <= num; i++)
{
if (DivBySeven(i) == true && DivByEleven(i) == true)
{
int j = i;
while (j > 0)
{
System.Console.Write("# ");
j--;
}
}
else if (DivBySeven(i) == true)
{
System.Console.Write("* ");
}
else if (DivByEleven(i) == true)
{
System.Console.Write(". ");
}
else
{
System.Console.Write(i +" ");
}
}
Console.ReadKey();
Sorry for the lack of comments. Quick overview: I am taking the number from the file and using it to output to the console 1-the file number, and taking multiples of 11 and 7, also just 7 and just 11 and doing a couple different things with them.
You have
string input=(Console.ReadLine()); // read from the keyboard
int num = Convert.ToInt32(input);
which is user keyboard input.
To read from the file you need
string input=(read.ReadLine()); // read from the stream reader
int num = Convert.ToInt32(input);

Inserting disks in a container having different diameters at each level [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to make a program , in which the number of layers for a container and their diameters are taken input from the user. Then the user inserts a disk of certain diameter into the program. Then the disks moves through all possible layers , the process can be repeated until the container is filled or user stops adding more disks to it. Finally the program is supposed to give total number of disks contained in the container and their layer numbers. Iam badly stuck and my mind is blank now. Kindly help!
[updated code] The problem remains that the container is never fills , program keeps on inserting disks. I cant think of a logical way to let it know when container is full.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.Write("Number of Layers ? ");
int layers = int.Parse(Console.ReadLine());
int[] container = new int[layers];
int disk_number = 0;
for (int i = 0; i < layers; i++)
{
Console.Write("\nLayer num {0} : ",1+i);
container[i] = int.Parse(Console.ReadLine());
}
Console.Write("\nPress 1 to Insert disk? ");
int insert = int.Parse(Console.ReadLine());
while (insert == 1)
{
Console.Write("\nDiameter of Disk? ");
int disk_diameter = int.Parse(Console.ReadLine());
if (disk_diameter <= container[0])
{
for (int i = 0; i < layers;) {
if (disk_diameter <= container[i])
{
i++;
}
else { if (i == layers - 1) break; layers = i+1; }
}
disk_number++;
Console.Write("\nPress 1 to Insert more disk(s)? ");
insert = int.Parse(Console.ReadLine());
if (insert != 1) { Console.Write("\nNumber of disks contained in container are : {0}", disk_number); }
}
else
{
Console.Write("\nDisc blocked the surface opening of the container , no further input could be processed! \nNumber of disks contained in container are : {0}",disk_number);
break;
}
}
Console.ReadLine();
}
//static int inserting_disk(int a);
}
}
You haven't explained me what you want exactly, but here goes a much improved (on different fronts) version of your code which, hopefully, you will take as a good learning exercise. The overall structure is pretty bad, but I have intended to emulate the one in your original code such that you can understand perfectly what is going on. The "input flow" is still pretty poor and thus might stop working easily (if the right inputs are not introduced) but, at least, I have replaced your Parse with TryParse accounting for different-type inputs (e.g., a string instead of an integer).
Test the code, see what it does. Get used to the new variables (I have renamed/redefined some of them because were too confusing in its original version) and build a code delivering exactly what you are after (and, ideally, properly written).
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.Write("Number of Layers ? ");
int input0 = 0;
bool right0 = int.TryParse(Console.ReadLine(), out input0);
if (right0 && input0 > 0)
{
int tot_layers = input0;
int[] maxDiamLayer = new int[tot_layers + 1]; //better maintain the indexing as displayed to the user: starting from 1
bool[] layerDone = new bool[tot_layers + 1]; //This boolean array will make sure that you don't use the same layer more than once
int disk_number = 0;
for (int i = 1; i <= tot_layers; i++)
{
Console.Write("\nIntroduce the maximum diameter for the layer num {0} : ", i);
maxDiamLayer[i] = int.Parse(Console.ReadLine());
}
Console.Write("\nPress 1 to Insert disk? ");
input0 = 0;
right0 = int.TryParse(Console.ReadLine(), out input0);
while (right0 && input0 == 1)
{
Console.Write("\nDiameter of Disk? ");
int input = 0;
bool right = int.TryParse(Console.ReadLine(), out input);
if (!right || input <= 0)
{
Console.Write("\nWrong Diameter. ");
continue;
}
int disk_diameter = input;
bool oneInserted = false;
for (int i = 1; i <= tot_layers; i++)
{
if (disk_diameter <= maxDiamLayer[i] && !layerDone[i])
{
layerDone[i] = true;
oneInserted = true;
disk_number++;
Console.Write("\nNumber of disks contained in container are : {0}", disk_number);
Console.Write("\nPress 1 to Insert more disk(s)? ");
int input2 = 0;
bool right2 = int.TryParse(Console.ReadLine(), out input2);
if (!right2 || input2 != 1 || disk_number >= tot_layers) break;
Console.Write("\nDiameter of Disk? ");
input = 0;
right = int.TryParse(Console.ReadLine(), out input);
if (!right || input <= 0)
{
Console.Write("\nWrong Diameter. ");
break;
}
disk_diameter = input;
}
}
if (disk_number >= tot_layers)
{
Console.Write("\nAll the layers are filled");
break;
}
else
{
Console.Write("\nWrong diameter. Try again.");
}
if (!oneInserted)
{
Console.Write("\nThe disk couldn't be inserted");
Console.Write("\nPress 1 to continue ");
int input3 = 0;
bool right3 = int.TryParse(Console.ReadLine(), out input3);
if (!right3 || input3 != 1) break;
}
}
}
Console.ReadLine();
}
}
}

Categories