for loop with counter not working after adding input - c#

I have this counter programm based on object oriented programming in C# and
the counter has an Increment Method which counts up so like it goes from 0..1...2.. to 30.
The for loop was working perfectly fine but then I decided to add a class with two Methods that either count up in odd or even steps which also works fine. The only problem is that after changing the main class now it doesn't work in a loop anymore until its on 30, so I have to enter every step individually.
This is my main code (I'm pretty sure the problem is due to the Console.ReadLine and input in general but I don't know what exactly is the issue)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
class Program
{
static void Main(string[] args)
{
char confirm;
int input;
do
{
//int inNum;
Console.Clear();
ModusCounter b = new ModusCounter(0, 30);
for (; ; )
{
b.Display(19, 7);
Console.Write("do you want (1)odd // (2) even // (0)standard ? ");
input = Convert.ToInt32(Console.ReadLine());
if (input == 1)
{
b.OddCount();
}
else if (input == 2)
{
b.EvenCount();
}
else
b.Increment();
System.Threading.Thread.Sleep(300);
if (Console.KeyAvailable) break;
}
//b.Increment();
b.Display(19, 7);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("do you want to restart? (J // N) ");
confirm = Convert.ToChar(Console.ReadLine());
}
while (confirm == 'J');
Console.ReadLine();
}
}
}
ModusCounter:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
public class ModusCounter:CCounter
{
private int wholenum;
public int Wholenum
{
get => wholenum;
set
{
wholenum = value;
}
}
public ModusCounter(int start, int limit) : base(start, limit)
{ }
public void EvenCount() //2
{
Wholenum = 2;
Level += Wholenum;
if (Level % 2 == 0)
{
Level += Wholenum - 2;
}
else
{
Level += Wholenum -1;
}
if (Level > Limit)
Level = Start;
}
public void OddCount() //1
{
Wholenum = 1;
Level += Wholenum;
if (Level % 2 == 0)
{
Level += Wholenum;
}
else
{
Level += Wholenum + 1;
}
if (Level > Limit)
Level = Start;
}
}
}
base class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Counter
{
public class CCounter
{
private int start;
private int limit;
private int level;
public int Start
{
get => start;
protected set
{
start = value;
}
}
public int Limit
{
get => limit;
protected set
{
limit = value;
}
}
public int Level
{
get => level;
protected set
{
if (value < Start)
level = Start;
else if (value > Limit)
Level = Limit;
else
level = value;
}
}
public CCounter(int start_, int limit_)
{
Start = start_;
Limit = limit_;
Level = Start;
}
public void Increment()
{
int level = Level + 1;
if (level > Limit9
Level = Start;
else
Level = level;
}
public void Display(int x_, int y_)
{
Console.SetCursorPosition(x_, y_);
Console.Write(Level.ToString("00"));
}
}
}

First, welcome to S/O. Hope you get good info out here during your obvious learning curve into development. A couple things could get simplified, but that will come with learning, so I wont pounce, but you will see as your skills improve over time.
First, your for(;;) loop. That is in-itself causing an infinite loop. The console read line to get input is always waiting for the next option from your prompt asking for odd, even or standard, so it keeps cycling through.
I dont think your Console.KeyAvailable is ever really getting triggered to break out of the for loop to get you to the next prompt of allowing the user to retry J/N option. You have the console.ReadLine which reads the entire buffer until you hit the enter key. By that time, you are incrementing your cycle, displaying the results and giving a 300 millisecond delay from your Thread.Sleep(300) call, of which you are probably not clicking a key in that short span to break the loop. Now, if you changed the Thread.Sleep(2000) you would be giving the user 2 seconds (1 second = 1000 milliseconds) AFTER the display to press any key to break the loop.
Next item/question I have for you. Your incrementing you appear to be ok with that functionality, but what / why do you want to break. When it gets to the limit? If so, then test for that after the increment process has completed such as (before the Thread.Sleep call)
if (b.Level >= b.Limit)
break;
Getting to your CCounter class and looking at its Increment method. You have a check that if the local "level" variable is greater than the limit to set the level = START value. Was that intended, or not. Also, by using a new int value by the same name as a property on your class (int level vs property level) is not a good practice and can add confusion.
public void Increment()
{
int level = Level + 1;
if (level > Limit)
Level = Start;
else
Level = level;
}
It appears you are trying to use a local temporary variable but is not necessary. It could just as easily be done with slight alteration as I have below.
public void Increment()
{
if (Level +1 > Limit)
Level = Start;
else
Level = Level +1;
}
Because I am not ASSIGNING a value to the "Level" public property, it in essence is doing the +1 before its COMPARISON to the LIMIT property. Only in the ELSE condition do I assign.
Also, a shortcut on adding to a variable or subtracting could be seen as
Level++
or
Level--
Hopefully this helps add SOME clarity to what you are looking to get resolution to and can get you further in your development.

Related

Display "chaging" text on one line even after using more Console.WriteLines [duplicate]

When building a Windows Console App in C#, is it possible to write to the console without having to extend a current line or go to a new line? For example, if I want to show a percentage representing how close a process is to completion, I'd just like to update the value on the same line as the cursor, and not have to put each percentage on a new line.
Can this be done with a "standard" C# console app?
If you print only "\r" to the console the cursor goes back to the beginning of the current line and then you can rewrite it. This should do the trick:
for(int i = 0; i < 100; ++i)
{
Console.Write("\r{0}% ", i);
}
Notice the few spaces after the number to make sure that whatever was there before is erased.
Also notice the use of Write() instead of WriteLine() since you don't want to add an "\n" at the end of the line.
You can use Console.SetCursorPosition to set the position of the cursor and then write at the current position.
Here is an example showing a simple "spinner":
static void Main(string[] args)
{
var spin = new ConsoleSpinner();
Console.Write("Working....");
while (true)
{
spin.Turn();
}
}
public class ConsoleSpinner
{
int counter;
public void Turn()
{
counter++;
switch (counter % 4)
{
case 0: Console.Write("/"); counter = 0; break;
case 1: Console.Write("-"); break;
case 2: Console.Write("\\"); break;
case 3: Console.Write("|"); break;
}
Thread.Sleep(100);
Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
}
}
Note that you will have to make sure to overwrite any existing output with new output or blanks.
Update: As it has been criticized that the example moves the cursor only back by one character, I will add this for clarification: Using SetCursorPosition you may set the cursor to any position in the console window.
Console.SetCursorPosition(0, Console.CursorTop);
will set the cursor to the beginning of the current line (or you can use Console.CursorLeft = 0 directly).
So far we have three competing alternatives for how to do this:
Console.Write("\r{0} ", value); // Option 1: carriage return
Console.Write("\b\b\b\b\b{0}", value); // Option 2: backspace
{ // Option 3 in two parts:
Console.SetCursorPosition(0, Console.CursorTop); // - Move cursor
Console.Write(value); // - Rewrite
}
I've always used Console.CursorLeft = 0, a variation on the third option, so I decided to do some tests. Here's the code I used:
public static void CursorTest()
{
int testsize = 1000000;
Console.WriteLine("Testing cursor position");
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < testsize; i++)
{
Console.Write("\rCounting: {0} ", i);
}
sw.Stop();
Console.WriteLine("\nTime using \\r: {0}", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
int top = Console.CursorTop;
for (int i = 0; i < testsize; i++)
{
Console.SetCursorPosition(0, top);
Console.Write("Counting: {0} ", i);
}
sw.Stop();
Console.WriteLine("\nTime using CursorLeft: {0}", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
Console.Write("Counting: ");
for (int i = 0; i < testsize; i++)
{
Console.Write("\b\b\b\b\b\b\b\b{0,8}", i);
}
sw.Stop();
Console.WriteLine("\nTime using \\b: {0}", sw.ElapsedMilliseconds);
}
On my machine, I get the following results:
Backspaces: 25.0 seconds
Carriage Returns: 28.7 seconds
SetCursorPosition: 49.7 seconds
Additionally, SetCursorPosition caused noticeable flicker that I didn't observe with either of the alternatives. So, the moral is to use backspaces or carriage returns when possible, and thanks for teaching me a faster way to do this, SO!
Update: In the comments, Joel suggests that SetCursorPosition is constant with respect to the distance moved while the other methods are linear. Further testing confirms that this is the case, however constant time and slow is still slow. In my tests, writing a long string of backspaces to the console is faster than SetCursorPosition until somewhere around 60 characters. So backspace is faster for replacing portions of the line shorter than 60 characters (or so), and it doesn't flicker, so I'm going to stand by my initial endorsement of \b over \r and SetCursorPosition.
You can use the \b (backspace) escape sequence to backup a particular number of characters on the current line. This just moves the current location, it does not remove the characters.
For example:
string line="";
for(int i=0; i<100; i++)
{
string backup=new string('\b',line.Length);
Console.Write(backup);
line=string.Format("{0}%",i);
Console.Write(line);
}
Here, line is the percentage line to write to the console. The trick is to generate the correct number of \b characters for the previous output.
The advantage of this over the \r approach is that if works even if your percentage output is not at the beginning of the line.
\r is used for these scenarios.
\r represents a carriage return which means the cursor returns to the start of the line.
That's why Windows uses \n\r as its new line marker.
\n moves you down a line, and \r returns you to the start of the line.
I just had to play with the divo's ConsoleSpinner class. Mine is nowhere near as concise, but it just didn't sit well with me that users of that class have to write their own while(true) loop. I'm shooting for an experience more like this:
static void Main(string[] args)
{
Console.Write("Working....");
ConsoleSpinner spin = new ConsoleSpinner();
spin.Start();
// Do some work...
spin.Stop();
}
And I realized it with the code below. Since I don't want my Start() method to block, I don't want the user to have to worry about writing a while(spinFlag) -like loop, and I want to allow multiple spinners at the same time I had to spawn a separate thread to handle the spinning. And that means the code has to be a lot more complicated.
Also, I haven't done that much multi-threading so it's possible (likely even) that I've left a subtle bug or three in there. But it seems to work pretty well so far:
public class ConsoleSpinner : IDisposable
{
public ConsoleSpinner()
{
CursorLeft = Console.CursorLeft;
CursorTop = Console.CursorTop;
}
public ConsoleSpinner(bool start)
: this()
{
if (start) Start();
}
public void Start()
{
// prevent two conflicting Start() calls ot the same instance
lock (instanceLocker)
{
if (!running )
{
running = true;
turner = new Thread(Turn);
turner.Start();
}
}
}
public void StartHere()
{
SetPosition();
Start();
}
public void Stop()
{
lock (instanceLocker)
{
if (!running) return;
running = false;
if (! turner.Join(250))
turner.Abort();
}
}
public void SetPosition()
{
SetPosition(Console.CursorLeft, Console.CursorTop);
}
public void SetPosition(int left, int top)
{
bool wasRunning;
//prevent other start/stops during move
lock (instanceLocker)
{
wasRunning = running;
Stop();
CursorLeft = left;
CursorTop = top;
if (wasRunning) Start();
}
}
public bool IsSpinning { get { return running;} }
/* --- PRIVATE --- */
private int counter=-1;
private Thread turner;
private bool running = false;
private int rate = 100;
private int CursorLeft;
private int CursorTop;
private Object instanceLocker = new Object();
private static Object console = new Object();
private void Turn()
{
while (running)
{
counter++;
// prevent two instances from overlapping cursor position updates
// weird things can still happen if the main ui thread moves the cursor during an update and context switch
lock (console)
{
int OldLeft = Console.CursorLeft;
int OldTop = Console.CursorTop;
Console.SetCursorPosition(CursorLeft, CursorTop);
switch (counter)
{
case 0: Console.Write("/"); break;
case 1: Console.Write("-"); break;
case 2: Console.Write("\\"); break;
case 3: Console.Write("|"); counter = -1; break;
}
Console.SetCursorPosition(OldLeft, OldTop);
}
Thread.Sleep(rate);
}
lock (console)
{ // clean up
int OldLeft = Console.CursorLeft;
int OldTop = Console.CursorTop;
Console.SetCursorPosition(CursorLeft, CursorTop);
Console.Write(' ');
Console.SetCursorPosition(OldLeft, OldTop);
}
}
public void Dispose()
{
Stop();
}
}
Explicitly using a Carrage Return (\r) at the beginning of the line rather than (implicitly or explicitly) using a New Line (\n) at the end should get what you want. For example:
void demoPercentDone() {
for(int i = 0; i < 100; i++) {
System.Console.Write( "\rProcessing {0}%...", i );
System.Threading.Thread.Sleep( 1000 );
}
System.Console.WriteLine();
}
public void Update(string data)
{
Console.Write(string.Format("\r{0}", "".PadLeft(Console.CursorLeft, ' ')));
Console.Write(string.Format("\r{0}", data));
}
From the Console docs in MSDN:
You can solve this problem by setting
the TextWriter.NewLine property of the
Out or Error property to another line
termination string. For example, the
C# statement, Console.Error.NewLine =
"\r\n\r\n";, sets the line termination
string for the standard error output
stream to two carriage return and line
feed sequences. Then you can
explicitly call the WriteLine method
of the error output stream object, as
in the C# statement,
Console.Error.WriteLine();
So - I did this:
Console.Out.Newline = String.Empty;
Then I am able to control the output myself;
Console.WriteLine("Starting item 1:");
Item1();
Console.WriteLine("OK.\nStarting Item2:");
Another way of getting there.
This works if you want to make generating files look cool .
int num = 1;
var spin = new ConsoleSpinner();
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("");
while (true)
{
spin.Turn();
Console.Write("\r{0} Generating Files ", num);
num++;
}
And this is the method that i got from some answer below and modified it
public class ConsoleSpinner
{
int counter;
public void Turn()
{
counter++;
switch (counter % 4)
{
case 0: Console.Write("."); counter = 0; break;
case 1: Console.Write(".."); break;
case 2: Console.Write("..."); break;
case 3: Console.Write("...."); break;
case 4: Console.Write("\r"); break;
}
Thread.Sleep(100);
Console.SetCursorPosition(23, Console.CursorTop);
}
}
Here's another one :D
class Program
{
static void Main(string[] args)
{
Console.Write("Working... ");
int spinIndex = 0;
while (true)
{
// obfuscate FTW! Let's hope overflow is disabled or testers are impatient
Console.Write("\b" + #"/-\|"[(spinIndex++) & 3]);
}
}
}
If you want update one line, but the information is too long to show on one line, it may need some new lines. I've encountered this problem, and below is one way to solve this.
public class DumpOutPutInforInSameLine
{
//content show in how many lines
int TotalLine = 0;
//start cursor line
int cursorTop = 0;
// use to set character number show in one line
int OneLineCharNum = 75;
public void DumpInformation(string content)
{
OutPutInSameLine(content);
SetBackSpace();
}
static void backspace(int n)
{
for (var i = 0; i < n; ++i)
Console.Write("\b \b");
}
public void SetBackSpace()
{
if (TotalLine == 0)
{
backspace(OneLineCharNum);
}
else
{
TotalLine--;
while (TotalLine >= 0)
{
backspace(OneLineCharNum);
TotalLine--;
if (TotalLine >= 0)
{
Console.SetCursorPosition(OneLineCharNum, cursorTop + TotalLine);
}
}
}
}
private void OutPutInSameLine(string content)
{
//Console.WriteLine(TotalNum);
cursorTop = Console.CursorTop;
TotalLine = content.Length / OneLineCharNum;
if (content.Length % OneLineCharNum > 0)
{
TotalLine++;
}
if (TotalLine == 0)
{
Console.Write("{0}", content);
return;
}
int i = 0;
while (i < TotalLine)
{
int cNum = i * OneLineCharNum;
if (i < TotalLine - 1)
{
Console.WriteLine("{0}", content.Substring(cNum, OneLineCharNum));
}
else
{
Console.Write("{0}", content.Substring(cNum, content.Length - cNum));
}
i++;
}
}
}
class Program
{
static void Main(string[] args)
{
DumpOutPutInforInSameLine outPutInSameLine = new DumpOutPutInforInSameLine();
outPutInSameLine.DumpInformation("");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
//need several lines
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbb");
}
}
i was looking for same solution in vb.net and i found this one and it's great.
however as #JohnOdom suggested a better way to handle the blanks space if previous one is larger than current one..
i make a function in vb.net and thought someone could get helped ..
here is my code:
Private Sub sPrintStatus(strTextToPrint As String, Optional boolIsNewLine As Boolean = False)
REM intLastLength is declared as public variable on global scope like below
REM intLastLength As Integer
If boolIsNewLine = True Then
intLastLength = 0
End If
If intLastLength > strTextToPrint.Length Then
Console.Write(Convert.ToChar(13) & strTextToPrint.PadRight(strTextToPrint.Length + (intLastLength - strTextToPrint.Length), Convert.ToChar(" ")))
Else
Console.Write(Convert.ToChar(13) & strTextToPrint)
End If
intLastLength = strTextToPrint.Length
End Sub
I was doing a search for this to see if the solution I wrote could be optimised for speed. What I wanted was a countdown timer, not just updating the current line.
Here's what I came up with. Might be useful to someone
int sleepTime = 5 * 60; // 5 minutes
for (int secondsRemaining = sleepTime; secondsRemaining > 0; secondsRemaining --)
{
double minutesPrecise = secondsRemaining / 60;
double minutesRounded = Math.Round(minutesPrecise, 0);
int seconds = Convert.ToInt32((minutesRounded * 60) - secondsRemaining);
Console.Write($"\rProcess will resume in {minutesRounded}:{String.Format("{0:D2}", -seconds)} ");
Thread.Sleep(1000);
}
Console.WriteLine("");
Inspired by #E.Lahu Solution, implementation of a bar progress with percentage.
public class ConsoleSpinner
{
private int _counter;
public void Turn(Color color, int max, string prefix = "Completed", string symbol = "■",int position = 0)
{
Console.SetCursorPosition(0, position);
Console.Write($"{prefix} {ComputeSpinner(_counter, max, symbol)}", color);
_counter = _counter == max ? 0 : _counter + 1;
}
public string ComputeSpinner(int nmb, int max, string symbol)
{
var spinner = new StringBuilder();
if (nmb == 0)
return "\r ";
spinner.Append($"[{nmb}%] [");
for (var i = 0; i < max; i++)
{
spinner.Append(i < nmb ? symbol : ".");
}
spinner.Append("]");
return spinner.ToString();
}
}
public static void Main(string[] args)
{
var progressBar= new ConsoleSpinner();
for (int i = 0; i < 1000; i++)
{
progressBar.Turn(Color.Aqua,100);
Thread.Sleep(1000);
}
}
Here is my take on s soosh's and 0xA3's answers.
It can update the console with user messages while updating the spinner and has an elapsed time indicator aswell.
public class ConsoleSpiner : IDisposable
{
private static readonly string INDICATOR = "/-\\|";
private static readonly string MASK = "\r{0} {1:c} {2}";
int counter;
Timer timer;
string message;
public ConsoleSpiner() {
counter = 0;
timer = new Timer(200);
timer.Elapsed += TimerTick;
}
public void Start() {
timer.Start();
}
public void Stop() {
timer.Stop();
counter = 0;
}
public string Message {
get { return message; }
set { message = value; }
}
private void TimerTick(object sender, ElapsedEventArgs e) {
Turn();
}
private void Turn() {
counter++;
var elapsed = TimeSpan.FromMilliseconds(counter * 200);
Console.Write(MASK, INDICATOR[counter % 4], elapsed, this.Message);
}
public void Dispose() {
Stop();
timer.Elapsed -= TimerTick;
this.timer.Dispose();
}
}
usage is something like this:
class Program
{
static void Main(string[] args)
{
using (var spinner = new ConsoleSpiner())
{
spinner.Start();
spinner.Message = "About to do some heavy staff :-)"
DoWork();
spinner.Message = "Now processing other staff".
OtherWork();
spinner.Stop();
}
Console.WriteLine("COMPLETED!!!!!\nPress any key to exit.");
}
}
The SetCursorPosition method works in multi-threading scenario, where the other two methods don't

How do i return the value of a integer from a class to my main? C#

So i have trouble with returning the value from an integer, from a class.
So this is my main program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MatchGame
{
class Program
{
static void Main(string[] args)
{
//( Amount of matches, bot argument, player argument, gameover?,)
//AI MatchGame = new AI(0, 0, 0, false, 0, false);
int matchAmount = 0;
int botMove = 0;
int playerMove = 0;
bool gameOver = false;
int playerMoveAttempt = 0;
bool choseRightAmount = false;
void TurnPlayer()
{
PlayersTurn PlayerMoved = new PlayersTurn(); //choseRightAmount, playerMoveAttempt, playerMove, matchAmount);
PlayersTurn.PlayerTurnMove(choseRightAmount, playerMoveAttempt, playerMove, matchAmount);
Console.WriteLine(playerMoveAttempt);
playerMove = playerMoveAttempt;
matchAmount = matchAmount - playerMove;
}
/*
void PlayerTurn()
{
choseRightAmount = false;
while (!choseRightAmount)
{
playerMoveAttempt = Convert.ToInt32(Console.ReadLine());
if (playerMoveAttempt < 1 || playerMoveAttempt > 3)
{
Console.WriteLine("Please take between 1 and 3 matches");
}
else
{
playerMove = playerMoveAttempt;
matchAmount = matchAmount - playerMove;
choseRightAmount = true;
}
}
} */
void BotTurn()
{
botMove = matchAmount % 4;
matchAmount = matchAmount - botMove;
}
void Status()
{
Console.WriteLine("Bot took " + botMove + " matches from the board.");
Console.WriteLine("There are " + matchAmount + " matches left.");
}
void Game()
{
Console.WriteLine("Welcome to the game!");
Console.WriteLine("To win you need to take the last match!");
Console.WriteLine("You can only take between 1 and 3 matches per turn.");
Console.WriteLine("Please choose the amount of matches you want.");
matchAmount = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("You chose " + matchAmount + " It is your turn, please take between 1 and 3 matches");
while (!gameOver)
{
TurnPlayer();
if (matchAmount <= 0)
{
Console.WriteLine("You Won.");
break;
}
BotTurn();
if (matchAmount <= 0)
{
Console.WriteLine("You lost! The bot won the match!");
gameOver = true;
break;
}
Status();
}
Console.ReadKey();
}
Game();
}
}
}
So i need to get the value of playerMove attempt from the class. I know i can easely do this inside the main program, but my teacher wants us to use classes. I need to use it in TurnPlayer() so i can calculate the amount of matches that are left. This is being used in the while loop in the buttom.
Here is the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MatchGame
{
public class PlayersTurn
{
public static int PlayerTurnMove(bool choseRightAmount, int playerMoveAttempt, int playerMove, int matchAmount)
{
choseRightAmount = false;
while (!choseRightAmount)
{
playerMoveAttempt = Convert.ToInt32(Console.ReadLine());
if (playerMoveAttempt < 1 || playerMoveAttempt > 3)
{
Console.WriteLine("Please take between 1 and 3 matches");
}
else
{
choseRightAmount = true;
return playerMoveAttempt;
}
}
return playerMoveAttempt;
}
}
}
So yea, as you can see i am trying to return playerMoveAttempt. I already know the Class is working, it is just not returning the new values.
Hope some of you can help! Thanks in advance.
You need to assign the result of your method call to the variable like this:
playerMoveAttempt = PlayersTurn.PlayerTurnMove(choseRightAmount, playerMoveAttempt, playerMove, matchAmount);
Console.WriteLine(playerMoveAttempt);
Bear in mind everything you do inside PlayerTurnMove method won't change the values of playerMoveAttempt, playerMove and matchAmount outside of it, although it's possible to accomplish this behavior. You should read about variable scopes.
Since your method is returning only the value of playerMoveAttempt, it's possible to assign this result of your method to a variable, like my code sample above.
I realize this is a homework and you're learning the basics, just wanted to point out you should consider learning about static classes/methods, when to use them and when not to use. Although my code sample above should work, a more elegant solution to your problem would be to use your class like this:
public class PlayersTurn
{
public int PlayerMoveAttempt { get; set; }
public int PlayerMove{ get; set; }
public int MatchAmount{ get; set; }
public PlayersTurn(int playerMoveAttempt, int playerMove, int matchAmount)
{
this.PlayerMoveAttempt = playerMoveAttempt;
this.PlayerMove = playerMove;
this.MatchAmount = matchAmount;
}
public void PlayerTurnMove()
{
while (this.playerMoveAttempt < 1 || this.playerMoveAttempt > 3)
{
Console.WriteLine("Please take between 1 and 3 matches");
this.playerMoveAttempt = Convert.ToInt32(Console.ReadLine());
}
}
}
...then change your method from the console application:
void TurnPlayer()
{
PlayersTurn playerMoved = new PlayersTurn(playerMoveAttempt, playerMove, matchAmount);
playerMoved.PlayerTurnMove();
Console.WriteLine(playerMoved.PlayerMoveAttempt);
playerMove = playerMoved.PlayerMoveAttempt;
matchAmount = playerMoved.MatchAmount - playerMoved.PlayerMove;
}
Still not the best design, because using Console.ReadLine() inside a class is not generally a good idea, as this method is highly coupled with Console Applications, and it's working just because we are using this class inside it.
If you ever wanted to reuse this class and its logic in another type of aplication (e.g a Windows Form, an Web Application), this would not work properly. Your class shouldn't be aware of the mechanism used to get an input from the user.
I'd guess it's ok for now since you're just learning, maybe the next step of your teacher would be to refactor exactly this, but it'd be nice if you started trying to understand these concepts.

make simple program using 'while' and 'do' [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm trying to print
*
**
***
****
*****
and
*****
****
***
**
*
using 'While' and 'do - while'.
But I have no idea how to approach this problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int a = 0;
int b = 0;
while (a <= 0)
{
while (b <= a)
{
Console.Write("*");
b++;
}
a++;
Console.WriteLine();
}
Console.ReadLine();
}
}
}
I've kept trying to approach like above, but I think It never works ever!
P.S How would I improve my logic about programming? I feel like I'm lack of thinking logically.
I figure this is a homework problem and I usually don't answer them, but I think this may help you understand how to program better, so let me try explain...
Think through what you're trying to do - You want to print 1 star first and then stop at 5 stars and then print the reverse.
So, firstly, name your variables to make sense:
int numStars = 1;
int maxNumStars = 5;
Next, you can loop something along the lines of:
while( numStars <= maxNumStars) { ... }
Firstly, it lets you understand your problem better, secondly, it becomes readable and debug-able.
Your final procedure can look something as follows:
static void Main(string[] args)
{
int numStars = 1;
int maxNumStars = 5;
// Print the ascending number of stars
while(numStars <= maxNumStars)
{
// Write numStars number of stars to the console using the string constructor:
Console.WriteLine(new string('*', numStars));
numStars++;
}
// Print the descending number of stars
while (numStars >= 1)
{
// Write numStars number of stars to the console using the string constructor:
Console.WriteLine(new string('*', numStars));
numStars--;
}
}
Again, not a fan of doing work for a person, but I hope it makes enough sense to actually help you figure out similar problems like this in the future.
Edit:
For completeness sake, to use loops everywhere, your code / loop could look something like this:
// Declare a variable for writing the stars to the console:
int numWritten;
// Print the ascending number of stars
while(numStars <= maxNumStars)
{
// Reset the number of stars written:
numWritten = 0;
// Write the stars with a loop:
while (++numWritten <= numStars)
Console.Write("*");
// End the line and increment the numStars variable:
Console.WriteLine();
numStars++;
}
This is one of many ways to do it:
class Program
{
static void Main(string[] args)
{
int a = 0;
int b = 0;
int c = 4;
while (a <= c)
{
b = 0;
while (b <= a)
{
Console.Write("*");
b++;
}
a++;
Console.WriteLine();
}
Console.WriteLine();
if (a > c)
{
a--;
while (a >= 0)
{
b = a;
while (b >= 0)
{
Console.Write("*");
b--;
}
a--;
Console.WriteLine();
}
}
Console.ReadLine();
}
}
}
Probably work in this direction:
int a = 0;
int b = 0;
string s = string.Empty;
while (a < 5)
{
while (b <= a)
{
s += "*";
b++;
}
Console.Write(s);
s = string.Empty;
a++;
b = 0;
}
Hope it gives you some idea...
using while loops can be confusing so I came up with this recursive solution (for science)
public static void Main()
{
test();
}
public static void test(string lastOutPut = "",int maxBound = 5,bool goingup = true,int cursor = 0,int maxOutputs = 10){
if(cursor>maxOutputs)return;
Console.Write("\n");
if(goingup){
Console.Write(lastOutPut+="*");
cursor++;
test(lastOutPut,maxBound,lastOutPut.Length <= maxBound,cursor,maxOutputs);
}else{
lastOutPut=lastOutPut.Substring(0,lastOutPut.Length-1);
Console.Write(lastOutPut);
cursor++;
test(lastOutPut,maxBound,lastOutPut.Length <= 0,cursor,maxOutputs);
}
}

Difference in declaring variable as a array index and "0"?

I'm new to c# so be ready for some dumb questions.
My current task is to find a score from an array where the highest/lowest scores have been taken away, and if the highest/lowest occur more than once (ONLY if they occur more than once), one of them can be added:
eg. int[] scores = [4, 8, 6, 4, 8, 5] therefore the final addition will be 4+8+6+5 = 23.
Another condition of the task is that LINQ cannot be used, as well as any of the System.Array methods. (you can see by my previously ask questions that has been a bit of a pain for me, since I solved this with LINQ in less than 5 minutes).
So here is the problem: I have working code the solves the problem but the task requires multiple methods/functions, so I cannot receive full marks if I have only 3 methods (including main). I have been trying to restructure the program but with all sorts of issues. Here is my code (just so I can explain it better):
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Scoring {
class Program {
static int highOccurrence = 0;
static int lowOccurrence = 0;
//static int high; <------
//static int low; <------
static void Main(string[] args) {
int[] scores = { 4, 8, 6, 4, 8, 5 };
findScore(scores);
ExitProgram();
}
static int findOccurrence(int[] scores, int low, int high) { //find the number of times a high/low occurs
for (int i = 0; i < scores.Length; i++) {
if (low == scores[i]) {
lowOccurrence++;
//record number of time slow occurs
}
if (high == scores[i]) {
highOccurrence++;
//record number of times high occurs }
}
return highOccurrence;
}
static int findScore(int[] scores) { //calculates score, needs to be restructured
int[] arrofNormal = new int[scores.Length];
//int low = scores[0]; <----This is where the issue is
//int high = scores[0]; <----- ^^^^^
int total = 0;
for (int i = 0; i < scores.Length; i++) {
if (low > scores[i]) {
low = scores[i];
} //record lowest value
if (high < scores[i]) {
high = scores[i];
//record highest value
}
}
for (int x = 0; x < scores.Length; x++) {
if (scores[x] != low && scores[x] != high) {
arrofNormal[x] = scores[x];
//provides the total of the scores (not including the high and the low)
}
total += arrofNormal[x];
}
findOccurrence(scores, low, high);
if (highOccurrence > 1) { //if there is more than 1 high (or 1 low) it is added once into the total
total += high;
if (lowOccurrence > 1) {
total += low;
}
}
Console.WriteLine("Sum = " + total);
return total; //remove not all code paths return.. error
}
static void ExitProgram() {
Console.Write("\n\nPress any key to exit program: ");
Console.ReadKey();
}//end ExitProgram
}
}
I have placed arrows in the code above to show where my issue is. If I try to declare "high" and "low" as global variables, my final answer is always a few numbers off, buy if I leave the variables declared as "high = scores[0]" etc, I will get the right answer.
What I want ideally is to have separate methods for each step of the calculation, so right now I have method for finding the number of times a specific value shows up in the array. The next I would like to do is finding the highest/lowest value in the array, one method would do the final calculation, and the final one would write the results into the console window. The last two parts (finding the high/low and final calculation) are currently in the find score method.
Any help would be greatly appreciated. Thanks.

Issues loading different levels randomly in Unity-3D

I need to create a class (or classes, if need be) that loads levels randomly every time the user clicks on the "Next Button" and once all levels have been loaded, we stop loading and close the application. I got the code set up but I am still not getting the result I am looking for which is:
User clicks on a button.
Load a random level
That levels gets stored in an array list
Once the user is done with that level he/she presses the "Load Next Level" button
Load the next random level
But first, we check if the random level is not the same as before.
If it's not, then we repeat steps 2-5, else we go to step 8
If the levels have all been visited then we quit the application
The problem I am having is that my game loads the same level every time I hit play and it doesn't go to the next scene after I am done with the current one. This is what I have so far:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class SceneManager : MonoBehaviour
{
public static bool userClickedNextButton; //This flag is raised by the other classes that have the GUI button logic
protected const int MAX = 2;
private ArrayList scenesWereAlreadyLoaded = new ArrayList();
void Update()
{
if (userClickedNextButton)
{
//by default the game starts at 0 so I want to be able to
//randomly call the next two scenes in my game. There will
//be more levels but for now I am just testing two
int sceneToLoad = Random.Range(1, 2);
if (!scenesWereAlreadyLoaded.Contains(sceneToLoad))
{
scenesWereAlreadyLoaded.Add(sceneToLoad);
Application.LoadLevel(sceneToLoad);
}
userClickedNextButton = false;
}
if (scenesWereAlreadyLoaded.Count > MAX) { Application.Quit(); }
}
}
You create a list with your level numbers, then remove the currently loaded level. You repeat that until the list is empty.
Also don't use ArrayList, it's very old and deprecated type, from the ages before .NET/Mono had Generic support. Better use a Generic List<T>, which is type safe and faster than ArrayList.
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
public class SceneManager : MonoBehaviour
{
// not best idea to have it static
public static bool userClickedNextButton;
protected const int MAX = 50;
private List<int> scenes = new List<int>();
void Start() {
// Initialize the list with levels
scenes = new List<int>(Enumerable.Range(1,MAX)); // This creates a list with values from 1 to 50
}
void Update()
{
if (userClickedNextButton)
{
if(scenes.Count == 0) {
// No scenes left, quit
Application.Quit();
}
// Get a random index from the list of remaining level
int randomIndex = Random.Range(0, scenes.Count);
int level = scenes[randomIndex];
scenes.RemoveAt(randomIndex); // Removes the level from the list
Application.LoadLevel(level);
userClickedNextButton = false;
}
}
}
As per the Unity3D documentation (http://docs.unity3d.com/Documentation/ScriptReference/Random.Range.html), range returns an integer between min (included) and max (excluded), so, in your case, Random.Range(1,2) will always returns 1.
Try with this
int = sceneToLoad = Random.Range(1,3)
There is an easier way to do so. You can prepare an array with random unique numbers. When you want to load a new level just increment the index of the array.
Here's a code that can help:(Attach this script to an empty gameobject in your first scene)
using UnityEngine;
using System.Collections;
public class MoveToRandomScene : MonoBehaviour {
public Texture nextButtonTexture; // set this in the inspector
public static int[] arrScenes;
public static int index;
void Start () {
index = 0;
arrScenes = GenerateUniqueRandom (10, 0, 10); //assuming you have 10 levels starting from 0.
}
void OnGUI {
// Load the first element of the array
if (GUI.Button(new Rect (0,0,Screen.width/4,Screen.height/4),nextButtonTexture))
{
int level = arrScenes [0] ;
Application.LoadLevel (level);
}
}
//Generate unique numbers (levels) in an array
public int[] GenerateUniqueRandom(int amount, int min, int max)
{
int[] arr = new int[amount];
for (int i = 0; i < amount; i++)
{
bool done = false;
while (!done)
{
int num = Random.Range(min, max);
int j = 0;
for (j = 0; j < i; j++)
{
if (num == arr[j])
{
break;
}
}
if (j == i)
{
arr[i] = num;
done = true;
}
}
}
return arr;
}
}
For the other scenes you just need to create this script and attach it to an empty game object whenever you want to load a new random scene:
void OnGUI {
if (GUI.Button(new Rect (0,0,Screen.width/4,Screen.height/4),nextButtonTexture))
{
if (MoveToRandomScene.index == 9) {
// Load again your first level
Application.LoadLevel(0);
}
// else you continue loading random levels
else {
MoveToRandomScene.index++;
int level = MoveToRandomScene.arrScenes[MoveToRandomScene.index];
Application.LoadLevel(level);
}
}
}

Categories

Resources