Weird input bug on c# - c#

Errm...Let's see...The bug my project is having is...Weird.
I'm making a Monster Training game,and when it enters on the battle mode,there is a bug that may happen,once you press the key to the left or the right of the controls,before you enter on the battle.
The bug is simple,for example,if you press A(Aka left button),when it lets you choose the action you will take,the game keeps recognizing as if the A button is still pressed,even if it isn't.
This is the code that is causing the bug:
public static int ChooseAction()
{
int choosen = 0;
Battle.CanAct = true;
Battle.ChoosenAction = -1;
while (Battle.ChoosenAction == -1)
{
if (Battle.KeyDelay == 0)
{
if (Procedures.ButtonPressed(Procedures.KeyCodes.KeyRight))
{
Battle.KeyDelay = 64;
int a = Battle.SelectedAction;
a++;
if (a >= BattleActions.Length)
{
a -= BattleActions.Length;
}
Battle.SelectedAction = a;
}
else if (Procedures.ButtonPressed(Procedures.KeyCodes.KeyLeft))
{
Battle.KeyDelay = 64;
int a = Battle.SelectedAction;
a--;
if (a < 0)
{
a += BattleActions.Length;
}
Battle.SelectedAction = a;
}
else if (Procedures.ButtonPressed(Procedures.KeyCodes.Action))
{
Battle.ChoosenAction = Battle.SelectedAction;
}
}
if (KeyDelay != 0 && !Procedures.ButtonPressed(Procedures.KeyCodes.KeyRight) && !Procedures.ButtonPressed(Procedures.KeyCodes.KeyLeft))
{
KeyDelay = 0;
}
if (Battle.KeyDelay > 0)
{
Battle.KeyDelay--;
}
}
choosen = Battle.ChoosenAction;
Battle.CanAct = false;
return choosen;
}
I don't know if this will help,but that script runs on a thread,since it's maden based on the modification of the official script,that were in c# console.
Also,the ButtonPress procedure,returns if the button is pressed,but it ever creates a new boolean everytime it is called.
Any clue of what may be causing the bug?
The Procedures.ButtonPress(KeyCodes) script.
public static bool ButtonPressed(KeyCodes buttonKey)
{
bool pressed = false;
switch (buttonKey)
{
case KeyCodes.MenuKey:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.M) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.Start))
pressed = true;
break;
case KeyCodes.RunKey:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift) || Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.RightShift) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.B))
pressed = true;
break;
case KeyCodes.KeyUp:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.W) || Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Up) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.DPadUp))
pressed = true;
break;
case KeyCodes.KeyDown:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.S) || Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Down) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.DPadDown))
pressed = true;
break;
case KeyCodes.KeyLeft:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.A) || Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Left) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.DPadLeft))
pressed = true;
break;
case KeyCodes.KeyRight:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D) || Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Right) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.DPadRight))
pressed = true;
break;
case KeyCodes.Action:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Enter) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.A))
pressed = true;
break;
case KeyCodes.Return:
if (Keyboard.GetState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.B))
pressed = true;
break;
}
return pressed;
}

After downloading XNA and setting up everything (yes I'm bored at work), I tried the code on a simple menu and it works flawlessly.
The problem is that for some reason XNA's input is not threadable. It doesn't work at all for me when I create another thread with the input. I tried various keys and none of them get a pressed state but the letter "R" which once it's pressed, it stays that way.
I also tried with the R to save the original keyboard state and once the state changes use the original to compare if R was pressed and it worked. However, you will know just ONCE that R was pressed and you won't know if it's being pressed again.
After doing all that I googled and I found recommendations to ALWAYS check your input on your main thread on the update method (as I did at first)
Hope this helps =)

Related

Jump n Rows Up or Down in DataGridView on KeyDown or PreviewKeyDown Events

I have trouble implementing arrow key navigation of a DataGridView (no datasource used).
The DataGridView has 2 different type of items, most of the time every second item is of the first type, vice versa the others are of the second type. Now if someone presses KeyUp / Down I want the DataGridView to jump to a row of a given index, not one up or down.
No matter how I try to solve this it is not clear when the event actually ends. If I try this inside the _previewKeyDown method:
if (DgvCarPosAndTrafficMsg.CurrentRow != null)
{
if (e.KeyCode == Keys.Down)
{
if (DgvCarPosAndTrafficMsg.SortOrder == SortOrder.Ascending)
{
for (int i = DgvCarPosAndTrafficMsg.CurrentRow.Index; i < SessionItems.Count; i++)
{
if (SessionItems[i] is CarPosItem)
{
DgvCarPosAndTrafficMsg.Rows[i].Selected = true;
break;
}
}
}
else
{
for (int i = DgvCarPosAndTrafficMsg.CurrentRow.Index; i > 0; i--)
{
if (SessionItems[i] is CarPosItem)
{
DgvCarPosAndTrafficMsg.Rows[i].Selected = true;
break;
}
}
}
}
else if (e.KeyCode == Keys.Up)
{
if (DgvCarPosAndTrafficMsg.SortOrder == SortOrder.Descending)
{
for (int i = DgvCarPosAndTrafficMsg.CurrentRow.Index; i < SessionItems.Count; i++)
{
if (SessionItems[i] is CarPosItem)
{
DgvCarPosAndTrafficMsg.Rows[i].Selected = true;
break;
}
}
}
else
{
for (int i = DgvCarPosAndTrafficMsg.CurrentRow.Index; i > 0; i--)
{
if (SessionItems[i] is CarPosItem)
{
DgvCarPosAndTrafficMsg.Rows[i].Selected = true;
break;
}
}
}
}
it would still just jump up or down 1 Row.
I have no clue when this event is actually processed automatically and I would like to have my own behaviour of key up down events. Please help me, DataGridViews in C# and their annoying events are very hard for me to track down. It seems as every event of those grids is processed differently, for some events the new state has already been applied, for others (OnSelectionChanged) it gets processed afterwards. It is documented poorly and not intuitive, I want to avoid / override all of this background stuff.
Ok I found a solution, using only one event method:
Here is my code, it is important to set the evenArgs as handled, and then do your own update method of the grid:
private void DgvCarPosAndTrafficMsg_KeyDown(object sender, KeyEventArgs e)
{
int diffDown;
int diffUp;
if (DgvCarPosAndTrafficMsg.SortOrder == SortOrder.Descending)
{
diffDown = 1;
diffUp = -2;
}
else
{
diffDown = 2;
diffUp = -1;
}
if (DgvCarPosAndTrafficMsg.CurrentRow != null)
{
if (e.KeyCode == Keys.Down && DgvCarPosAndTrafficMsg.CurrentRow.Index < DgvCarPosAndTrafficMsg.Rows.Count - diffDown)
{
DgvCarPosAndTrafficMsg.CurrentCell = DgvCarPosAndTrafficMsg.Rows[DgvCarPosAndTrafficMsg.CurrentRow.Index + diffDown].Cells[0];
}
else if (e.KeyCode == Keys.Up && DgvCarPosAndTrafficMsg.CurrentRow.Index + diffUp > 0)
{
DgvCarPosAndTrafficMsg.CurrentCell = DgvCarPosAndTrafficMsg.Rows[DgvCarPosAndTrafficMsg.CurrentRow.Index + diffUp].Cells[0];
}
}
e.Handled = true;
DgvCarPosAndTrafficMsg_UpdateAll();
}
I always jump up/down 2 rows as I expect the item of same type there, but in my UpdateAll() method I check again if it has been correct, and correct it if needed, otherwhise (if already correct) I update the visualisation of the data (and fill other grids with details of the selected entry). I hope this will help others too.
You might have -2 and + 2 for both events, I have some treatment going on afterwards so these values are my indexes I needed, adjust this according to your case or give a specific index (as seen in the question)

Detecting multiple keys in Unity

I'm following along with a tutorial about creating a mini-RTS in Unity, but I've hit something of a roadblock when it comes to the selection feature for assigning selection groups for multiple units.
The pertinent parts are below:
In the Update() method of my UnitsSelection class
//manage selection groups with alphanumeric keys
if (Input.anyKeyDown)
{
int alphaKey = Utils.GetAlphaKeyValue(Input.inputString);
if (alphaKey != -1)
{
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
_CreateSelectionGroup(alphaKey);
}
else
{
_ReselectGroup(alphaKey);
}
}
}
And the GetAlphaKeyValue method from Utils:
public static int GetAlphaKeyValue(string inputString)
{
if (inputString == "0") return 0;
if (inputString == "1") return 1;
if (inputString == "2") return 2;
if (inputString == "3") return 3;
if (inputString == "4") return 4;
if (inputString == "5") return 5;
if (inputString == "6") return 6;
if (inputString == "7") return 7;
if (inputString == "8") return 8;
if (inputString == "9") return 9;
return -1;
}
This is the code that is used in the tutorial, but to my understanding there is no way that _CreateSelectionGroup() would ever be called.
I've seen the tutorial demonstrate this functionality working, but whenever I try to run it GetAlphaKeyValue turns the Left and Right control keys into a -1 value so the if statement that checks for them never runs.
Am I missing something here? How does Unity normally handle things like Ctrl+1?
If you use the inputString I would always rather check for Contains instead of an exact string match. However, I tried to use the inputString in the past and I found it too unpredictable for most usecases ^^
While holding control keys your Keyboard most likely simply won't generate any inputString.
Only ASCII characters are contained in the inputString.
But e.g. CTRL+1 will not generate the ASCII symbol 1 but rather a "non-printing character", a control symbol - or simply none at all.
You should probably rather use e.g.
public static bool GetAlphaKeyValue(out int alphaKey)
{
alphaKey = -1;
if (Input.GetKeyDown(KeyCode.Alpha0) alphaKey = 0;
else if (Input.GetKeyDown(KeyCode.Alpha1) alphaKey = 1;
else if (Input.GetKeyDown(KeyCode.Alpha2) alphaKey = 2;
else if (Input.GetKeyDown(KeyCode.Alpha3) alphaKey = 3;
else if (Input.GetKeyDown(KeyCode.Alpha4) alphaKey = 4;
else if (Input.GetKeyDown(KeyCode.Alpha5) alphaKey = 5;
else if (Input.GetKeyDown(KeyCode.Alpha6) alphaKey = 6;
else if (Input.GetKeyDown(KeyCode.Alpha7) alphaKey = 7;
else if (Input.GetKeyDown(KeyCode.Alpha8) alphaKey = 8;
else if (Input.GetKeyDown(KeyCode.Alpha9) alphaKey = 9;
return alphaKey >= 0;
}
And then use it like
//manage selection groups with alphanumeric keys
if(Utils.GetAlphaKeyValue(out var alphaKey)
{
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
_CreateSelectionGroup(alphaKey);
}
else
{
_ReselectGroup(alphaKey);
}
}
As it turns out it may just be an issue with my keyboard. Different keyboards handle key presses in different ways. Mine just refuses to tell Unity that control + (some other key) are being pressed together. Changed the code to respond to Shift + (some other key) and it works fine.

Can't get method to exit and skip turn properly on keypress

So I'm building this RPG turn based game for a class. I'm not trying to get my homework done for me, but this one problem is REALLY spinning me out, I've been at this for like 3 hours and I can't figure out how to fix this problem.
Essentially, I have an update method that controls whos turn it is (either the player or the computer)
public bool Update()
{
// clears console for a fresh start
Console.Clear();
//branch who's turn it is and add a line indicating so
if (playerTurn)
{
//print that it's the player's turn
Console.WriteLine("It's Your Turn to Attack!");
//run the player turn
PlayerTurn();
}
else
{
//print the rivals turn label
Console.WriteLine("It's the Enemy's Turn to Attack!");
}
//run the rivals turn
RivalsTurn();
{
}
//end game check
return EndTurn();
}
Then, I have the player turn method ---
void PlayerTurn()
{
// print instructions to select an attacker
Console.WriteLine($"Select which character will attack!\n(1) To Select {playerArray[0].Name()}\n(2) To Select {playerArray[1].Name()}\n(3) To Select {playerArray[2].Name()}\n(4) to view your teams current status\n(5) To Heal An Ally");
// Loop until an attacker is chosen
while (Attacker == null)
{
// use num 1-3 to select player party member that is the attacker
ConsoleKeyInfo k = Console.ReadKey();
if (k.KeyChar == '1')
{
Attacker = playerArray[0];
Console.WriteLine($"\nYou've chosen to attack with {Attacker.Name()}");
}
else if (k.KeyChar == '2')
{
Attacker = playerArray[1];
Console.WriteLine($"You've chosen to attack with {Attacker.Name()}");
}
else if (k.KeyChar == '3')
{
Attacker = playerArray[2];
Console.WriteLine($"You've chosen to attack with {Attacker.Name()}");
}
else if(k.KeyChar == '4')
{
PrintParties();
continue;
} else if (k.KeyChar == '5') {
HealAlly();
break;
}
// start a new line after user input
Console.WriteLine();
// Data Validation: make sure the key typed is a valid key
if (k.KeyChar < '1' || k.KeyChar > '5')
{
Console.WriteLine("Please Enter (1), (2), or (3) to select your attacking character. Press (4) to view your stats, and (5) to Heal an Ally");
continue;
}
else // convert from key input (1-3) to array element space (0-2)
curSelection = int.Parse(k.KeyChar.ToString()) - 1;
{
}
if (Attacker.GetHP() <= 0)
{
//check to make sure the selected character is alive HP > 0
//print the attackers name
//character's dead choose again
Console.WriteLine($"{Attacker.Name()} is dead! Choose someone who is alive!");
Console.WriteLine("Please Enter (1), (2), or (3) to select your attacking character. Press (4) to view your stats, and (5) to Heal an Ally");
Attacker = null;
}
else
{
Console.WriteLine($"{Attacker.Name()} will attack!");
Thread.Sleep(1000);
}
}
//print instructions for choosing a rival.
Console.WriteLine($"Select which enemy to attack!\n(1) To Attack {enemyArray[0].Name()}\n(2) To Attack {enemyArray[1].Name()}\n(3) To Attack {enemyArray[2].Name()}\n(4) To see the Enemies Current Stats.");
//loop until a defender is choosen
while (Defender == null)
{
// use 1-3 to select player party member that is the attacker
ConsoleKeyInfo k = Console.ReadKey();
if (k.KeyChar == '1')
{
Defender = enemyArray[0];
Console.WriteLine($"\nYou will attack {Defender.Name()}");
} else if(k.KeyChar == '2') {
Defender = enemyArray[1];
Console.WriteLine($"\nYou will attack {Defender.Name()}");
}
else if (k.KeyChar == '3')
{
Defender = enemyArray[2];
Console.WriteLine($"\nYou will attack {Defender.Name()}");
} else if (k.KeyChar == '4')
{
playerTurn = false;
PrintParties();
playerTurn = true;
}
{ }
//add a new line aft er the user input
Console.WriteLine();
// Data Validation: make sure the key typed is a valid key
if (k.KeyChar < '1' || k.KeyChar > '3')
{
// repeat instructions
Console.WriteLine("Select an enemy to attack by pressing either 1, 2, or 3.\n");
// loop again
continue;
}
else // convert from key input (1-3) to array element space (0-2)
curSelection = int.Parse(k.KeyChar.ToString()) - 1; //minus one to use as index
//check to make sure the selected character is alive HP > 0
//print the defenders name
//assign the selected character as the defender
if (Defender.GetHP() <= 0)
{
//print instructions again
Console.WriteLine($"{Defender.Name()} is already dead! Pick another enemy!");
Console.WriteLine("Select an enemy to attack by pressing either 1, 2, or 3.\n");
Defender = null;
} else
{
Console.WriteLine($"{Attacker.Name()} attacks {Defender.Name()}!");
Thread.Sleep(2000);
}
}
//damage the defender by the attacker's Strength value
Defender.ApplyDamage(Attacker.GetStrength());
//change color for rival team
Console.BackgroundColor = Attacker.GetTeamColor();
//print the new rival's health
Console.WriteLine($"{Defender.Name()} was hit by {Attacker.Name()}! {Defender.Name()} now only has {Defender.GetHP()} HP!");
EndTurn();
//change color back for normal
Console.BackgroundColor = ConsoleColor.Black;
//pause for 2 seconds
Thread.Sleep(2000);
//reset attacker/defender for next attack
Attacker = null;
Defender = null;
}
What I am trying to do is when the player selects "5" and runs the HealAlly() Method, I want the program to Take the users next input (who to heal), tell the player whether or not they can heal (if the character is either dead or full health) and then switch turns.
Instead, the code jumps back to the middle of the PlayerTurn method and tries to execute from there, but since the Attacker was never set (the user hit 5 so they didn't pick an Attacker) the game will crash.
Here is the HealAlly() method:
void HealAlly()
{
float healing = 3;
while (Healee == null)
{
Console.WriteLine("\nWhich Ally Do You Want To Heal?");
Console.WriteLine($"(1) for {playerArray[0].Name()}\n(2) for {playerArray[1].Name()}\n(3) for {playerArray[2].Name()}");
// use 1-3 to select player party member that is being healed
ConsoleKeyInfo k = Console.ReadKey();
if (k.KeyChar == '1')
{
Healee = playerArray[0];
Console.WriteLine($"\nYou will heal {Healee.Name()}");
Console.WriteLine("Healing...");
}
else if (k.KeyChar == '2')
{
Healee = playerArray[1];
Console.WriteLine($"\nYou will heal {Healee.Name()}");
Console.WriteLine("Healing...");
}
else if (k.KeyChar == '3')
{
Healee = playerArray[2];
Console.WriteLine($"\nYou will heal {Healee.Name()}");
Thread.Sleep(1000);
Console.WriteLine("Healing...");
}
else if (k.KeyChar > 3 || k.KeyChar < 1)
{
Console.WriteLine("Choose which character you want to heal!");
continue;
}
if (Healee.GetHP() >= 12)
{
Thread.Sleep(1000);
Console.WriteLine($"{Healee.Name()} has full health! You can't heal them!");
EndTurn();
}
else if (Healee.GetHP() <= 0)
{
Thread.Sleep(1000);
Console.WriteLine($"{Healee.Name()} is dead! You can't heal them!");
EndTurn();
}
else
{
Healee.ApplyHealing(healing);
Thread.Sleep(2000);
Console.WriteLine($"{Healee.Name()} has been healed, and now has {Healee.GetHP()} HP!");
EndTurn();
}
I thought that adding the call to EndTurn() at the end of the HealAlly() method would cause the turn to end, but instead all it does is give me the delay message and then shoot back to the middle of the PlayerTurn() method. I'm sure it's because there was no Attacker set, but that's not what I want, because I don't want the player to be able to attack after healing.
Here is the EndTurn() method if that will help
bool EndTurn()
{
//switch turns for next loop
playerTurn = !playerTurn;
// loop through players to see if they're alive and store in a variable counting if they're alive or not
bool playersAlive = true;
for (int i = 0; i < playerArray.Length; i++)
{
if (playerArray[0].GetHP() <= 0 && playerArray[1].GetHP() <= 0 && playerArray[2].GetHP() <= 0)
{
playersAlive = false;
}
}
// same for rivals
bool rivalsAlive = true;
for (int i = 0; i < enemyArray.Length; i++)
{
if (enemyArray[0].GetHP() <= 0 && enemyArray[1].GetHP() <= 0 && enemyArray[2].GetHP() <= 0)
{
rivalsAlive = false;
}
}
// if both have things alive start the next round, pause the game, and return true to continue playing
if (playersAlive && rivalsAlive)
{
Console.WriteLine("Next Round Starts in 5 seconds");
Thread.Sleep(5000);
return true;
} // if only the players have members alive you win
else if (playersAlive)
{
//clear screen for results
Console.Clear();
//print you've won and parties
Console.WriteLine("Congrats you win! Final Standings:");
playerTurn = false;
PrintParties();
playerTurn = true;
PrintParties();
Thread.Sleep(5000);
Console.WriteLine("Thanks For Playing!");
Console.WriteLine("Press Any Key to Play Again");
Console.ReadKey();
Console.Clear();
Init();
return false;
} // only rival members are alive
else
{
//clear screen for results
Console.Clear();
//Print you've lost and parties
Console.WriteLine("You Lose :( Final Standings:");
playerTurn = false;
PrintParties();
playerTurn = true;
PrintParties();
Thread.Sleep(5000);
Console.WriteLine("Thanks For Playing!");
Console.WriteLine("Press Any Key to Play Again");
Console.ReadKey();
Console.Clear();
Init();
return false;
}
}
This is bugging me, can anyone help?
void PlayerTurn()
{
// ...
while (Attacker == null)
{
// ...
if (k.KeyChar == '5') {
HealAlly();
break;
}
}
// ...code that depends on Attacker...
}
The break statement here only causes the flow to break out of the while loop and continue with the code the depends on Attacker. If you want to leave the PlayerTurn() method altogether, replace the break; with a return;

MessageBox.Show being displayed too fast

I'm trying to create my own version of "Fleet battle", but I'm stuck at 99.9%. And here is why. After a ship was destroyed, its color should change to red and then a MessageBox "You won" or "You lost" should come. So now, if the AI destroys my last ship, everything is going fine, all the ships are becoming red one by one and then comes this "You lost" message. But in the opposite case - if I win, the AI ships are becoming red, but the last cell of the last ship becomes red after I click "OK" at the MessageBox "You won". I'm using the same algorithm in both cases and wondering what I'm doing wrong with it. Here is the AI part:
// AI hits a ship
if ((arrayOccupiedCellsBattlefield1[rowIndex, columnIndex] == "1") || (arrayOccupiedCellsBattlefield1[rowIndex, columnIndex] == "2") ||
(arrayOccupiedCellsBattlefield1[rowIndex, columnIndex] == "3") || (arrayOccupiedCellsBattlefield1[rowIndex, columnIndex] == "4"))
{
AIHuntingAShip = true;
dataGridView1.Rows[rowIndex].Cells[columnIndex].Value = " X";
arrayShipsHitbyAIMap[rowIndex, columnIndex] = " X"; // AI marks the burning enemy ships
dataGridView1.Rows[rowIndex].Cells[columnIndex].Style.BackColor = Color.Red;
arrayAITakenShots[transformCoordinatesToCellNumber(rowIndex, columnIndex)] = transformCoordinatesToCellNumber(rowIndex, columnIndex);
storeRowIndex = rowIndex;
storeColumnIndex = columnIndex;
arrayShipsHitbyAIXY[detectedShipLength] = transformCoordinatesToCellNumber(rowIndex, columnIndex);
detectedShipLength++;
if (detectedShipLength == int.Parse(arrayOccupiedCellsBattlefield1[rowIndex, columnIndex])) // AI destroys a ship (the array stores the length of the ship in each of the ship's cells)
{
for (int i = 0; i < detectedShipLength; i++) // placing " o"s around the destroyed ship
{
restrictArea(int.Parse(tranformCellNumberToCoordinates(arrayShipsHitbyAIXY[i])[0].ToString()),
int.Parse(tranformCellNumberToCoordinates(arrayShipsHitbyAIXY[i])[1].ToString()),
dataGridView1,
arrayShipsHitbyAIMap,
arrayAITakenShots);
}
detectedShipLength = 0;
AIHuntingAShip = false;
playerShips--;
textBox6.Text = playerShips.ToString();
if (playerShips == 0)
{
MessageBox.Show("You lost!", "Try it again!", MessageBoxButtons.OK);
dataGridView2.Enabled = false;
}
}
and here is my part:
// player hits a ship
if ((arrayOccupiedCellsBattlefield2[e.RowIndex, e.ColumnIndex] != null) && (arrayOccupiedCellsBattlefield2[e.RowIndex, e.ColumnIndex] != " ."))
{
dataGridView2.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = " X";
arrayShipsHitbyPlayerMap[e.RowIndex, e.ColumnIndex] = " X";
dataGridView2.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BackColor = Color.Red;
arrayPlayerTakenShots[transformCoordinatesToCellNumber(e.RowIndex, e.ColumnIndex)] = transformCoordinatesToCellNumber(e.RowIndex, e.ColumnIndex);
int shipIdent = int.Parse(arrayOccupiedCellsBattlefield2[e.RowIndex, e.ColumnIndex][0].ToString()); // ship ID
int playersShipLength = int.Parse(arrayOccupiedCellsBattlefield2[e.RowIndex, e.ColumnIndex][1].ToString()); // ship length
arrayForPlayersShipsXY[shipIdent] += e.RowIndex.ToString() + e.ColumnIndex.ToString() + ";"; // save the coordinates of this particular ship
arrayForPlayerCounters[shipIdent]++; // increase this particular cell counter basing on the "shipIdent"
if (arrayForPlayerCounters[shipIdent] == playersShipLength) // ship destroyed, so mark the area with " o"
{
for (int i = 0; i < playersShipLength; i++)
{
string xy = extractXYForPlayersShip(arrayForPlayersShipsXY[shipIdent])[i].ToString();
int x = int.Parse(xy.ToString()[0].ToString());
int y = int.Parse(xy.ToString()[1].ToString());
restrictArea(x, y, dataGridView2, arrayShipsHitbyPlayerMap, arrayPlayerTakenShots);
}
AIShips--;
textBox7.Text = AIShips.ToString();
}
if (AIShips == 0)
{
dataGridView2.Enabled = false;
MessageBox.Show("You won!", "Congrats!", MessageBoxButtons.OK);
}
}
Does anybody have an idea? Thank you for your help.
The algorithms might seem the same, but they are not. There is a lot of repeated code, and it is hard to make sure they both do the "same thing". Try and break out parts of this code into smaller methods so you can reuse them.
Without seeing everything, I think this is the issue:
AI:
if (...) //Ship is destroyed
{
// ...
if (ships == 0)
{
MessageBox.Show(...);
}
}
Player
if (...) //ship is destroyed
{
// ...
}
if (ships == 0)
{
MessageBox.Show(...);
}
MessageBox.Show is called inside vs. outside the "ship destroyed" if block.
This question is not exactly the best for StackOverflow because the code is fairly messy and not simplified. Check out this link for how to ask good questions. But keep at it!
As you said both algorithms are equal but windows refresh your form after you hit the 'OK' button.
So I suggest refresh it yourself before displaying msgbox.
if (AIShips == 0)
{
dataGridView2.Refresh(); // <-------- +
dataGridView2.Enabled = false;
MessageBox.Show("You won!", "Congrats!", MessageBoxButtons.OK);
}
Your code is a bit messy I'm not sure about the grid view name, If your problem is about the first one, try this: dataGridView1.Refresh();

How do I "Pause" a console application when the user presses escape?

I am creating a C# console application that will be performing an infinite process. How can I get the application to "pause" when the user presses the escape key?
Once the user presses the escape key I want the option to either exit the application or continue the loop right where it left off. I don't want any discontinuity in the process. If I press Esc at step 100 I should be able to pick right back up at step 101.
Here is my method so far:
// Runs the infinite loop application
public static void runLoop()
{
int count = 0;
while (Console.ReadKey().Key!= ConsoleKey.Escape)
{
WriteToConsole("Doing stuff.... Loop#" + count.ToString());
for (int step = 0; step <= int.MaxValue; step++ ) {
WriteToConsole("Performing step #" + step.ToString());
if (step == int.MaxValue)
{
step = 0; // Re-set the loop counter
}
}
count++;
}
WriteToConsole("Do you want to exit? y/n");
exitApplication(ReadFromConsole());
}
Is there any way to check for the user input key in a separate thread then pause the infinite loop when the other thread sees an Esc key-press?
To find out if there is a key available in the loop, you can do this:
while (someLoopCondition)
{
//Do lots of work here
if (Console.KeyAvailable)
{
var consoleKey = Console.ReadKey(true); //true keeps the key from
//being displayed in the console
if (consoleKey.Key == ConsoleKey.Escape)
{
//Pause here, ask a question, whatever.
}
}
}
Console.KeyAvailable returns true if there is a key in the input stream ready to read and it is a non-blocking call so it won't pause to wait for input. You can check if the escape key was pressed and pause or do whatever you want if the condition is true.
Ron, big thank you for your answer. Using Console.KeyAvalible was key to finding the exact solution to my issue. Here is what I did to produce the results I was expecting. I needed to add in a few methods to check if the user wants to break the current operation or start a new loop from the beginning.
public static void runUpdater()
{
int count = 0;
while (true)
{
WriteToConsole("Doing stuff.... Loop# " + count.ToString());
for (int step = 0; step <= int.MaxValue; step++)
{
if (!breakCurrentOperation())
{
WriteToConsole("Performing step #" + step.ToString());
if (step == int.MaxValue)
{
step = 0; // Re-set the loop counter
}
}
else
{
break;
}
}
count++;
if (!startNewOperation())
{
// Noop
}
else
{
break;
}
}
WriteToConsole("\nAre you ready to run the database updater again? y/n");
startApplication(ReadFromConsole());
}
public static bool startNewOperation()
{
WriteToConsole("Do you want go back to the main menu or start a new update process? \nType y to start a new update process or n to go to the main menu.");
string input = ReadFromConsole();
if (input == "y" || input == "Y")
{
return false;
}
else if (input == "n" || input == "N")
{
return true; // Noop - Restart the Loop from the begining
}
else
{
WriteToConsole("Error: Input was not recognized. ");
return startNewOperation(); // Recursivly call method untill user enters a logical input
}
}
public static bool breakCurrentOperation()
{
if (Console.KeyAvailable)
{
var consoleKey = Console.ReadKey(true);
if (consoleKey.Key == ConsoleKey.Escape)
{
WriteToConsole("Do you want to stop the current process? \nType s to stop or c to continue.");
string input = Console.ReadLine();
if (input == "c" || input == "C")
{
return false; // Continue
}
else if (input == "s" || input == "S")
{
return true; // Break the loop
}
else
{
WriteToConsole("Error: Input was not recognized, the current process will now continue. Press Esc to stop the operation.");
}
}
}
return false;
}
Here are the results:

Categories