I'm doing a tic tac toe game with an AI. The AI plays well, except when it has to win with a vertical. All the other ways (horizontal and diagonal) does work.
I've done a lot of debugging and step by step and haven't found the solution. I thought you guys could help me finding the problem and help me solving it!
int findTwoPions(Boolean?[,] jeu)
{
// La méthode qui selon moi est à modifier car c'est celle ci qui décide la position que doit prendre l'IA quand elle peu gagner
int somme = 0;
int compteurX = 0;
int compteur0 = 0;
//Diagonale descendante
for (int i = 0; i < 3; i++)
{
if ((jeu[0, 0] == false || jeu[1, 1] == false || jeu[2, 2] == false) && (jeu[0, 0] == true || jeu[1, 1] == true || jeu[2, 2] == true))
{
somme += 0;
}
else
{
if (jeu[i, i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, i] == true)
{
compteur0 = 0;
compteurX++;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
compteurX = 0;
compteur0 = 0;
//Diagonale montante
for (int i = 0; i < 3; i++)
{
if ((jeu[0, 2] == false || jeu[1, 1] == false || jeu[2, 0] == false) && (jeu[0, 2] == true || jeu[1, 1] == true || jeu[2, 0] == true))
{
}
else
{
if (jeu[i, 2 - i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, 2 - i] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
//En ligne
for (int i = 0; i < 3; i++)
{
compteurX = 0;
compteur0 = 0;
if ((jeu[0, i] == false || jeu[1, i] == false || jeu[2, i] == false) && (jeu[0, i] == true || jeu[1, i] == true || jeu[2, i] == true))
{
somme += 0;
}
else
{
//Verticale
for (int j = 0; j < 3; j++)
{
if (jeu[j, i] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[j, i] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
compteurX = 0;
compteur0 = 0;
if ((jeu[i, 0] == false || jeu[i, 1] == false || jeu[i, 2] == false) && (jeu[i, 0] == true || jeu[i, 1] == true || jeu[i, 2] == true))
{
return somme += 0;
} // Voir les valeurs i j pcque c'est faux
else
{
//Horizontale
for (int j = 0; j < 3; j++)
{
if (jeu[i, j] == false)
{
compteur0++;
compteurX = 0;
if (compteur0 == 2)
{
somme += 1500;
}
}
else if (jeu[i, j] == true)
{
compteurX++;
compteur0 = 0;
if (compteurX == 2)
{
somme -= 1600;
}
}
}
}
}
return somme;
}
}
}
I think the problem is when I add a value to 'somme' or the way I run trough my tic tac toe.
If you need further code please tell me, thank you !
UPDATE:
MY AIRoutine.cs
public Boolean?[][] IAPlay(Boolean?[][] jeu, int profondeur)
{
int max = -10000;
int tmp, tmp2 = 0, tmpSomme = -10000; // -10000
int tmpBefore = 0;
int maxi = 0, maxj = 0;
int somme = 0;
int biggestSomme = 0;
setTab(jeu); // convertit le tableau[][] en tableau[,]
for (int i = 0; i < 3; i++) // parcours toutes les cases vides du tableau
{
for (int j = 0; j < 3; j++)
{
//Si une case est vide, on joue le coup de l'IA sur cette case et on simule le jeu complet
if (tab[i, j] == null)
{
tab[i, j] = false; // On simule le coup de l'IA
somme = findTwoPions(tab);
tmp = Max(tab, profondeur - 1);
if (tmpBefore < tmp && biggestSomme > somme)
{
tmpSomme = somme + tmpBefore;
}
else if (tmpBefore > tmp && biggestSomme < somme)
{
tmpSomme = somme + tmpBefore;
}
else
{
tmpSomme = tmp + somme;
}
if (somme > biggestSomme)
{
biggestSomme = somme;
tmpBefore = tmp;
}
//|| ((tmp == max) && (r.Next(1, 100) % 2 == 0))
if (tmpSomme >= max)
{
max = tmpSomme;
tmp2 = somme;
maxi = i;
maxj = j;
}
tab[i, j] = null;
}
}
}
tab[maxi, maxj] = false;
return getTab(jeu);
}
Let's put it in readable and maintainabe way: let's extract a method WinningLines where we enumerate all winning combinations (I've assummed that jue is 2d array - bool?[3, 3]):
using System.Linq;
...
private static IEnumerable<bool?[]> WinningLines(bool?[,] field) {
// Verticals
for (int column = 0; column < 3; ++column)
yield return new bool?[] {field[0, column], field[1, column], field[2, column]};
// Horizontals
for (int row = 0; row < 3; ++row)
yield return new bool?[] {field[row, 0], field[row, 1], field[row, 2]};
// Diagonals
yield return new bool?[] {field[0, 0], field[1, 1], field[2, 2]};
yield return new bool?[] {field[0, 2], field[1, 1], field[2, 0]};
}
Now let's query (with a help of Linq):
// Do we have any winning combinations for the 1st Player (all 3 true in WinningLines):
bool hasFirstWon = WinningLines(jeu).Any(line => line.All(cell => cell == true));
// Do we have any winning combinations for the 2nd Player (all 3 false in WinningLines):
bool hasSecondWon = WinningLines(jeu).Any(line => line.All(cell => cell == false));
Or if you operate with somme:
int somme =
WinningLines(jeu).Any(line => line.All(cell => cell == true)) ?
1500 // 1st wins
: WinningLines(jeu).Any(line => line.All(cell => cell == false)) ?
-1600 // 2nd wins
: 0; // no-one wins
Edit: Now let's implement a (simple) version of the int findTwoPions(Boolean?[,] jeu) method. First let's have
private static bool FirstIsOnMove(bool?[,] field) {
int count = 0;
foreach (var item in field)
if (item == true)
count += 1;
else if (item == true)
count -= 1;
return count == 0;
}
and the method itself will be
// This method rates the position in a [-1600..1500] range
// [1st player has lost..1st player has won]
int findTwoPions(Boolean?[,] jeu) {
// Edge cases: win or lose
if (WinningLines(jeu).Any(line => line.All(cell => cell == true)))
return 1500; // 1st has won
else if (WinningLines(jeu).Any(line => line.All(cell => cell == false)))
return -1600; // 1st has lost
//TODO: add more heuristics (depending who is on move)
// Example: if palayer is on move and can win by its next move?
// Say, we have positions like
// X.. XXO
// OX. Or X.O
// .O. ...
if (FirstIsOnMove(jeu)) {
if (WinningLines(jeu)
.Any(line => line.Sum(item => item == true ? 1 : item == false ? -1 : 0) == 2))
return 1200; // 1st is going to win (unless it makes a blind)
}
else {
if (WinningLines(jeu)
.Any(line => line.Sum(item => item == true ? 1 : item == false ? -1 : 0) == -2))
return -1200; // 2st is going to win (unless it makes a blind)
}
// Neutral position - neither 1st not 2nd have any advantages
return 0;
}
Related
I made an expression evaluator but I only included: addition and substraction and multiply and division and a brackets resolver and I want to add exponential "^" and after that trigonometric functions: sine, cosine and tangent but I don't know where to start... this is what I did for now:
public static string RemoveBrackets(string text)
{
while (text.Contains('(') && text.Contains(')'))
{
int openIndex = 0;
int closeIndex = 0;
for(int i = 0; i < text.Length; ++i)
{
if(text[i] == '(')
{
openIndex = i;
}
if(text[i] == ')')
{
closeIndex = i;
text = text.Remove(openIndex, closeIndex - openIndex + 1).Insert(openIndex, ResolveBrackets(openIndex, closeIndex, text));
break;
}
}
}
for(int i = 1; i < text.Length; ++i)
{
if(text[i] == '-' && (text[i - 1] == '*' || text[i - 1] == '/'))
{
for(int j = i - 1; j >= 0; --j)
{
if(text[j] == '+')
{
StringBuilder text1 = new StringBuilder(text);
text1[j] = '-';
text = text1.ToString();
text = text.Remove(i, 1);
break;
}
else if(text[j] == '-')
{
StringBuilder text1 = new StringBuilder(text);
text1[j] = '+';
text = text1.ToString();
text = text.Remove(i, 1);
break;
}
}
}
}
for (int i = 0; i < text.Length; ++i)
{
if (text[i] == '-' && (text[i - 1] == '-' || text[i - 1] == '+'))
{
if(text[i - 1] == '-')
{
StringBuilder text1 = new StringBuilder(text);
text1[i] = '+';
text = text1.ToString();
text = text.Remove(i - 1, 1);
}
else
{
StringBuilder text1 = new StringBuilder(text);
text1[i] = '-';
text = text1.ToString();
text = text.Remove(i - 1, 1);
}
}
else if (text[i] == '+' && (text[i - 1] == '-' || text[i - 1] == '+'))
{
if (text[i - 1] == '-')
{
StringBuilder text1 = new StringBuilder(text);
text1[i] = '-';
text = text1.ToString();
text = text.Remove(i - 1, 1);
}
else
{
StringBuilder text1 = new StringBuilder(text);
text1[i] = '+';
text = text1.ToString();
text = text.Remove(i - 1, 1);
}
}
}
if (text[0] == '-')
{
text = '0' + text;
}
return Calculate(text);
}
public static string ResolveBrackets(int openindex, int closeindex, string text)
{
string BracketAnswer = evaluate(text.Substring(openindex + 1, closeindex - openindex - 1));
return BracketAnswer;
}
public static double DivideAndMultiply(string text)
{
string[] expr = text.Split('*');
List<string> textList = new List<string>();
for (int i = 0; i < expr.Length; ++i)
{
textList.Add(expr[i]);
if (i != expr.Length - 1)
{
textList.Add("*");
}
}
for (int i = 0; i < textList.Count; ++i)
{
if (textList[i].Contains('/') && textList[i].Length > 1)
{
string[] textPart = textList[i].Split('/');
textList.RemoveAt(i);
for (int j = textPart.Length - 1; j >= 0; --j)
{
textList.Insert(i, textPart[j]);
if (j != 0)
{
textList.Insert(i, "/");
}
}
}
}
double total;
if (textList[0].Contains('*') || textList[0].Contains('/'))
{
total = textList[0] == "" ? 0 : DivideAndMultiply(textList[0]);
}
else
{
total = Convert.ToDouble(textList[0]);
}
/// 7:30 min tutorial
for (int i = 2; i < textList.Count; i += 2)
{
if (textList[i - 1] == "/")
{
total /= Convert.ToDouble(textList[i]);
}
else if (textList[i - 1] == "*")
{
total *= Convert.ToDouble(textList[i]);
}
}
return total;
}
public static double AddAndSubstract(string text)
{
string[] expr = text.Split('-');
List<string> textList = new List<string>();
for(int i = 0; i < expr.Length; ++i)
{
textList.Add(expr[i]);
if(i != expr.Length - 1)
{
textList.Add("-");
}
}
for(int i = 0; i < textList.Count; ++i)
{
if (textList[i].Contains('+') && textList[i].Length > 1)
{
string[] textPart = textList[i].Split('+');
textList.RemoveAt(i);
for (int j = textPart.Length - 1; j >= 0; --j)
{
textList.Insert(i, textPart[j]);
if (j != 0)
{
textList.Insert(i, "+");
}
}
}
}
//double total = Add(expr[0]);
double total = expr[0] == "" ? 0 : DivideAndMultiply(textList[0]);
for (int i = 2; i < textList.Count; i += 2)
{
if(textList[i - 1] == "-")
{
total -= DivideAndMultiply(textList[i]);
}
else if(textList[i - 1] == "+")
{
total += DivideAndMultiply(textList[i]);
}
}
return total;
}
Any suggestions on what should I read?
Use system.math to do this, it is easier
read about programmatic part - of math class
https://msdn.microsoft.com/en-us/library/system.math(v=vs.110).aspx
And find some tuturial about scientific calculator. That should give a insights.
I have a grid of buttons that should reveal some info when they are clicked (within the button itself) For a knowledge assignment I'm trying to program minesweeper.
The grid method:
public void createGrid()
{
for (int i = 0; i < 8; i++)
{
grid[i] = new Cell[8];
for (int j = 0; j < 8; j++)
{
chance = rand1.Next(0, 6);
if (chance == 0 && bombAmount < 10)
{
grid[i][j] = new Cell(true);
bombAmount++;
}
else
{
grid[i][j] = new Cell();
}
grid[i][j].Name = "grid" + i.ToString() + j.ToString();
grid[i][j].Location = new System.Drawing.Point(i * 49, j * 49);
grid[i][j].Size = new System.Drawing.Size(50, 50);
grid[i][j].TabIndex = 0;
grid[i][j].Font = new System.Drawing.Font("Microsoft Sans Serif", 26.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
}
}
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <8; j++)
{
this.Controls.Add(grid[i][j]);
}
}
}
The Reveal method:
public void RevealCell(int n, int m)
{
if (grid[n][m].HasBomb == true)
{
grid[n][m].Text = "B";
}
else if (grid[n][m].NeighbourBombCount > 0)
{
grid[n][m].Text = grid[n][m].NeighbourBombCount.ToString();
}
else
{
grid[n][m].Text = "NB";
}
grid[n][m].IsRevealed = true;
}
and then there's the checking if neighbours have bombs or not method:
public void CheckNeighbours(int cswitch)
{
switch (cswitch)
{
// Left upper corner (i = 0, j = 0)
case 1:
for (int i = 0; i <= 1; i++)
{
for (int j = 0; j < 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Upper edge (i = 0, 0 < j < 7)
case 2:
for (int i = 0; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Right upper corner (i = 0, j = 7)
case 3:
for (int i = 0; i <= 1; i++)
{
for (int j = -1; j <= 0; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Right edge (0 < i < 7, j = 7)
case 4:
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 0; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Right down corner (i = 7, j = 7)
case 5:
for (int i = -1; i <= 0; i++)
{
for (int j = -1; j <= 0; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Bottom edge (i = 7, 0 < j < 7)
case 6:
for (int i = -1; i <= 0; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Left down corner (i = 7, j = 0)
case 7:
for (int i = -1; i <= 0; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
// Left edge (i = 0, 0 < j < 7)
case 8:
for (int i = 0; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
default:
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0) { }
else
{
if (grid[i][j].HasBomb == true)
{
grid[0][0].NeighbourBombCount++;
}
}
}
}
break;
}
}
As my buttons are laid out in grid fashion the Top left button is button 1 and right bottom button is button 64 (hence the switch statements).
Edit: Didn't add the Click method to the grid[i][j].Click += handler...
Update:
private void Cell_click(object sender, EventArgs e)
{
e.
if(i == 0 && j == 0)
{
CheckNeighbours(1);
}
if (i == 0 && j > 0 && j < 7)
{
CheckNeighbours(2);
}
if (i == 0 && j == 7)
{
CheckNeighbours(3);
}
if (i > 0 && i < 7 && j == 7)
{
CheckNeighbours(4);
}
if (i == 7 && j == 7)
{
CheckNeighbours(5);
}
if (i == 7 && j > 0 && j < 7)
{
CheckNeighbours(6);
}
if (i == 7 && j == 0)
{
CheckNeighbours(7);
}
if(i > 0 && i < 7 && j == 0)
{
CheckNeighbours(8);
}
RevealCell(i, j);
}
Now I just need to know how to grab the i and j indeces from the sender object and I'm golden!
you need
cell[i][j].Click += new System.EventHandler(this.CellClick);
and create a single CellClick event handler method
I'm trying to implement the MinMax algorithm for four in a row (or connect4 or connect four) game.
I think I got the idea of it, it should build a tree of possible boards up to a certain depth, evaluate them and return their score, then we just take the max of those scores.
So, aiChooseCol() checks the score of every possible column by calling MinMax() and returns the column with the max score.
Now I wasn't sure, is this the right way to call MinMax()?
Is it right to check temp = Math.Max(temp, 1000);?
I still haven't made the heuristic function but this should at least recognize a winning column and choose it, but currently it just choose the first free column from the left... I can't figure out what am I doing wrong.
private int AiChooseCol()
{
int best = -1000;
int col=0;
for (int i = 0; i < m_Board.Cols; i++)
{
if (m_Board.CheckIfColHasRoom(i))
{
m_Board.FillSignInBoardAccordingToCol(i, m_Sign);
int t = MinMax(5, m_Board, board.GetOtherPlayerSign(m_Sign));
if (t > best)
{
best = t;
col = i;
}
m_Board.RemoveTopCoinFromCol(i);
}
}
return col;
}
private int MinMax(int Depth, board Board, char PlayerSign)
{
int temp=0;
if (Depth <= 0)
{
// return from heurisitic function
return temp;
}
char otherPlayerSign = board.GetOtherPlayerSign(PlayerSign);
char checkBoard = Board.CheckBoardForWin();
if (checkBoard == PlayerSign)
{
return 1000;
}
else if (checkBoard == otherPlayerSign)
{
return -1000;
}
else if (!Board.CheckIfBoardIsNotFull())
{
return 0; // tie
}
if (PlayerSign == m_Sign) // maximizing Player is myself
{
temp = -1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Max(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
else
{
temp = 1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Min(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
return temp;
}
Some notes:
FillSignInBoardAccordingToCol() returns a boolean if it was successful.
The board type has a char[,] array with the actual board and signs of the players.
This code is in the AI Player class.
So I decided to write my own MinMax Connect 4. I used the depth to determine the value of a win or loss so that a move that gets you closer to winning or blocking a loss will take precedence. I also decide that I will randomly pick the move if more than one has the same heuristic. Finally I stretched out the depth to 6 as that's how many moves are required to find possible win paths from the start.
private static void Main(string[] args)
{
var board = new Board(8,7);
var random = new Random();
while (true)
{
Console.WriteLine("Pick a column 1 -8");
int move;
if (!int.TryParse(Console.ReadLine(), out move) || move < 1 || move > 8)
{
Console.WriteLine("Must enter a number 1-8.");
continue;
}
if (!board.DropCoin(1, move-1))
{
Console.WriteLine("That column is full, pick another one");
continue;
}
if (board.Winner == 1)
{
Console.WriteLine(board);
Console.WriteLine("You win!");
break;
}
if (board.IsFull)
{
Console.WriteLine(board);
Console.WriteLine("Tie!");
break;
}
var moves = new List<Tuple<int, int>>();
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(2, i))
continue;
moves.Add(Tuple.Create(i, MinMax(6, board, false)));
board.RemoveTopCoin(i);
}
int maxMoveScore = moves.Max(t => t.Item2);
var bestMoves = moves.Where(t => t.Item2 == maxMoveScore).ToList();
board.DropCoin(2, bestMoves[random.Next(0,bestMoves.Count)].Item1);
Console.WriteLine(board);
if (board.Winner == 2)
{
Console.WriteLine("You lost!");
break;
}
if (board.IsFull)
{
Console.WriteLine("Tie!");
break;
}
}
Console.WriteLine("DONE");
Console.ReadKey();
}
private static int MinMax(int depth, Board board, bool maximizingPlayer)
{
if (depth <= 0)
return 0;
var winner = board.Winner;
if (winner == 2)
return depth;
if (winner == 1)
return -depth;
if (board.IsFull)
return 0;
int bestValue = maximizingPlayer ? -1 : 1;
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(maximizingPlayer ? 2 : 1, i))
continue;
int v = MinMax(depth - 1, board, !maximizingPlayer);
bestValue = maximizingPlayer ? Math.Max(bestValue, v) : Math.Min(bestValue, v);
board.RemoveTopCoin(i);
}
return bestValue;
}
public class Board
{
private readonly int?[,] _board;
private int? _winner;
private bool _changed;
public Board(int cols, int rows)
{
Columns = cols;
Rows = rows;
_board = new int?[cols, rows];
}
public int Columns { get; }
public int Rows { get; }
public bool ColumnFree(int column)
{
return !_board[column, 0].HasValue;
}
public bool DropCoin(int playerId, int column)
{
int row = 0;
while (row < Rows && !_board[column,row].HasValue)
{
row++;
}
if (row == 0)
return false;
_board[column, row - 1] = playerId;
_changed = true;
return true;
}
public bool RemoveTopCoin(int column)
{
int row = 0;
while (row < Rows && !_board[column, row].HasValue)
{
row++;
}
if (row == Rows)
return false;
_board[column, row] = null;
_changed = true;
return true;
}
public int? Winner
{
get
{
if (!_changed)
return _winner;
_changed = false;
for (int i = 0; i < Columns; i++)
{
for (int j = 0; j < Rows; j++)
{
if (!_board[i, j].HasValue)
continue;
bool horizontal = i + 3 < Columns;
bool vertical = j + 3 < Rows;
if (!horizontal && !vertical)
continue;
bool forwardDiagonal = horizontal && vertical;
bool backwardDiagonal = vertical && i - 3 >= 0;
for (int k = 1; k < 4; k++)
{
horizontal = horizontal && _board[i, j] == _board[i + k, j];
vertical = vertical && _board[i, j] == _board[i, j + k];
forwardDiagonal = forwardDiagonal && _board[i, j] == _board[i + k, j + k];
backwardDiagonal = backwardDiagonal && _board[i, j] == _board[i - k, j + k];
if (!horizontal && !vertical && !forwardDiagonal && !backwardDiagonal)
break;
}
if (horizontal || vertical || forwardDiagonal || backwardDiagonal)
{
_winner = _board[i, j];
return _winner;
}
}
}
_winner = null;
return _winner;
}
}
public bool IsFull
{
get
{
for (int i = 0; i < Columns; i++)
{
if (!_board[i, 0].HasValue)
return false;
}
return true;
}
}
public override string ToString()
{
var builder = new StringBuilder();
for (int j = 0; j < Rows; j++)
{
builder.Append('|');
for (int i = 0; i < Columns; i++)
{
builder.Append(_board[i, j].HasValue ? _board[i,j].Value.ToString() : " ").Append('|');
}
builder.AppendLine();
}
return builder.ToString();
}
}
I'm trying to write a code for a simple game of 2048. I've managed to implement functions for moving the buttons in columns and summing them if they're equal, but somehow, only in X ratio. Why aren't they doing the same thing in Y?
Here's the code:
bool checkIfMoved;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
checkIfMoved = false;
for (int i = 0; i <= 3; i++)
{
for (int j = 0; j <= 3; j++)
{
if ((j != 0) && (board[i, j].Visible == true) && (board[i, j - 1].Visible == false))
{
moveButton(i, j, e);
}
else if ((j != 0) && (board[i, j].Visible == true) && (board[i, j - 1].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
else if (e.KeyCode == Keys.Right)
{
checkIfMoved = false;
for (int i = 3; i >= 0; i--)
{
for (int j = 3; j >= 0; j--)
{
if ((j != 3) && (board[i, j].Visible == true) && (board[i, j + 1].Visible == false))
{
moveButton(i, j, e);
}
else if ((j != 3) && (board[i, j].Visible == true) && (board[i, j + 1].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
else if (e.KeyCode == Keys.Up)
{
checkIfMoved = false;
for (int i = 0; i <= 3; i++)
{
for (int j = 3; j >= 0; j--)
{
if ((i != 0) && (board[i, j].Visible == true) && (board[i - 1, j].Visible == false))
{
moveButton(i, j, e);
}
else if ((i != 0) && (board[i, j].Visible == true) && (board[i - 1, j].Visible == true))
{
sumButtons(i, j, e);
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
}
else if (e.KeyCode == Keys.Down)
{
checkIfMoved = false;
for (int i = 3; i >= 0; i--)
{
for (int j = 0; j <= 3; j++)
{
if ((i != 3) && (board[i, j].Visible == true) && (board[i + 1, j].Visible == false))
{
moveButton(i, j, e);
}
else if ((i != 3) && (board[i, j].Visible == true) && (board[i + 1, j].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
}
}
Now the moving and summing functions:
private void moveButton(int i, int j, KeyEventArgs e)
{
SwitchKey Switch = new SwitchKey(i, j, e);
try
{
while (board[Switch.line, Switch.column].Text == "0")
{
board[Switch.line, Switch.column].Text = board[i, j].Text;
board[Switch.line, Switch.column].Visible = true;
board[i, j].Visible = false;
board[i, j].Text = "0";
sumButtons(Switch.line, Switch.column, e);
checkIfMoved = true;
switch(e.KeyCode)
{
case(Keys.Left):
j--;
break;
case(Keys.Right):
j++;
break;
case(Keys.Up):
i--;
break;
case(Keys.Down):
i++;
break;
}
Switch = new SwitchKey(i, j, e);
}
}
catch { }
}
private void sumButtons(int i, int j, KeyEventArgs e)
{
SwitchKey Switch = new SwitchKey(i, j, e);
while ((board[i, j].Text == board[Switch.line,Switch.column].Text))
{
int x;
int y;
Int32.TryParse(board[i, j].Text, out x);
Int32.TryParse(board[Switch.line, Switch.column].Text, out y);
int z = x + y;
string a = z.ToString();
board[Switch.line, Switch.column].Text = a;
board[Switch.line, Switch.column].Visible = true;
board[i, j].Visible = false;
board[i, j].Text = "0";
}
}
and the SwitchKey class:
class SwitchKey
{
public int line;
public int column;
public SwitchKey(int i, int j, System.Windows.Forms.KeyEventArgs e)
{
#region Keycode switch
switch (e.KeyCode)
{
case (System.Windows.Forms.Keys.Left):
{
column = j-1;
line = i;
break;
}
case (System.Windows.Forms.Keys.Right):
{
column = j + 1;
line = i;
break;
}
case (System.Windows.Forms.Keys.Up):
{
column = j;
line = i-1;
break;
}
case (System.Windows.Forms.Keys.Down):
{
column = j;
line = i+1;
break;
}
}
#endregion
}
}
The game works perfectly when i use left and right keys but doesn't do anything when using up and down. What am I doing wrong?
It seems that you need a close brace here
....
else if (e.KeyCode == Keys.Right)
{
checkIfMoved = false;
.... a lot of code
if (checkIfMoved == true)
{
GenerateField();
}
}// <-- here
else if (e.KeyCode == Keys.Up)
{
...
You have a misplaced }
Your
else if (e.KeyCode == Keys.Up)
{
Is nested inside your
else if (e.KeyCode == Keys.Right)
{
Try this:
bool checkIfMoved;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
checkIfMoved = false;
for (int i = 0; i <= 3; i++)
{
for (int j = 0; j <= 3; j++)
{
if ((j != 0) && (board[i, j].Visible == true) && (board[i, j - 1].Visible == false))
{
moveButton(i, j, e);
}
else if ((j != 0) && (board[i, j].Visible == true) && (board[i, j - 1].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
else if (e.KeyCode == Keys.Right)
{
checkIfMoved = false;
for (int i = 3; i >= 0; i--)
{
for (int j = 3; j >= 0; j--)
{
if ((j != 3) && (board[i, j].Visible == true) && (board[i, j + 1].Visible == false))
{
moveButton(i, j, e);
}
else if ((j != 3) && (board[i, j].Visible == true) && (board[i, j + 1].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
else if (e.KeyCode == Keys.Up)
{
checkIfMoved = false;
for (int i = 0; i <= 3; i++)
{
for (int j = 3; j >= 0; j--)
{
if ((i != 0) && (board[i, j].Visible == true) && (board[i - 1, j].Visible == false))
{
moveButton(i, j, e);
}
else if ((i != 0) && (board[i, j].Visible == true) && (board[i - 1, j].Visible == true))
{
sumButtons(i, j, e);
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
}
else if (e.KeyCode == Keys.Down)
{
checkIfMoved = false;
for (int i = 3; i >= 0; i--)
{
for (int j = 0; j <= 3; j++)
{
if ((i != 3) && (board[i, j].Visible == true) && (board[i + 1, j].Visible == false))
{
moveButton(i, j, e);
}
else if ((i != 3) && (board[i, j].Visible == true) && (board[i + 1, j].Visible == true))
{
sumButtons(i, j, e);
}
}
}
if (checkIfMoved == true)
{
GenerateField();
}
}
}
So I have a combobox and I have it so that based on other criteria the MaxLength is edited. The problem is that the MaxLength property only applies to typed inputs and not items from the combobox. So is there a way to remove items from the combobox based on their length and add them back if the length increases again? here is my code:
private void titleText_TextChanged(object sender, EventArgs e)
{
int colourNum;
int textType = 1;
if (titleTextType.Text == "Material")
textType = 1;
else if (titleTextType.Text == "Material Flipped")
textType = 2;
else if (titleTextType.Text == "Normal")
textType = 3;
else if (titleTextType.Text == "3D")
textType = 4;
else textType = 0;
if (titleTextColour.Text == "Red")
colourNum = 49;
else if (titleTextColour.Text == "Green")
colourNum = 50;
else if (titleTextColour.Text == "Yellow")
colourNum = 51;
else if (titleTextColour.Text == "Blue")
colourNum = 52;
else if (titleTextColour.Text == "Cyan")
colourNum = 53;
else if (titleTextColour.Text == "Pink")
colourNum = 54;
else if (titleTextColour.Text == "White")
colourNum = 55;
else if (titleTextColour.Text == "Black")
colourNum = 48;
else if (titleTextColour.Text == "Yale Blue")
colourNum = 59;
else if (titleTextColour.Text == "Light Yellow")
colourNum = 58;
else colourNum = 0;
byte[] colourArray = new byte[2]
{
(byte) 94,
(byte) colourNum
};
byte[] prefixArray1 = new byte[5]
{
(byte) 94,
(byte) textType,
(byte) 0x3D,//125decmax
(byte) 0x3D,//125decmax
(byte) titleText.Text.Length
};
if (textType == 3 && colourNum == 0)
{
titleText.MaxLength = 23;
}
else if (textType == 3 && colourNum != 0)
{
titleText.MaxLength = 21;
}
else if (textType == 1 && colourNum == 0 || textType == 2 && colourNum == 0)
{
titleText.MaxLength = 18;
}
else if (textType == 1 && colourNum != 0 || textType == 2 && colourNum != 0)
{
titleText.MaxLength = 16;
}
else if (textType == 4)
{
titleText.MaxLength = 3;
}
}
Thanks in advance c:
Here, will be easier to demonstrate code here.
My comboBox is named comboBox1.
This test code adds Test1 - Test20 and then removes them based on their length:
for (int x = comboBox1.Items.Count-1; x >= 0; x--)
if (comboBox1.Items[x].ToString().Length > comboBox1.MaxLength)
comboBox1.Items.RemoveAt(x);
Your code should look like this:
for (int x = titleText.Items.Count-1; x >= 0; x--)
if (titleText.Items[x].ToString().Length > titleText.MaxLength)
titleText.Items.RemoveAt(x);