I am trying to make the tic tac toe game in C# Windows Forms using the minimax algorithm as the opponent. So instead of making the best move, like preventing the player from winning or playing a move that allows it to get closer to winning, it moves to the following empty index on the board. So how could I fix the algorithm?
int evaluate(int[] grid)
{
for(int i = 0; i < 9; i += 3)
{
if (grid[i] == 0) continue;
if (grid[i] == grid[i + 1] && grid [i] == grid[i + 2])
return grid[i]==1 ? 10 :-10;
}
for (int i = 0; i < 3; i++)
{
if (grid[i] == 0) continue;
if (grid[i] == grid[i + 3] && grid[i] == grid[i + 6])
return grid[i] == 1 ? 10 : -10;
}
if ((grid[0] == grid[4] && grid[4] == grid[8]) || (grid[2] == grid[4] && grid[4] == grid[6]))
return grid[4] == 1 ? 10 : -10;
return 0;
}
bool isMovesLeft(int[] grid)
{
for(int i = 0; i< grid.Length; i++)
{
if (grid[i] == 0) return true;
}
return false;
}
int miniMax(int[] grid,int depth, bool isMax)
{
int isWon = evaluate(grid);
if (isWon == 10 || isWon == -10)
return isWon;
if(!isMovesLeft(grid))
return 0;
if (isMax)
{
int best = int.MinValue;
for(int i = 0;i< grid.Length;i++)
{
if (grid[i] == 0)
{
grid[i] = 1;
best = Math.Max(best,miniMax(grid, depth+1, !isMax));
grid[i] = 0;
}
}
return best;
}
else
{
int best = int.MaxValue;
for (int i = 0; i < grid.Length; i++)
{
if (grid[i] == 0)
{
grid[i] = 2;
best = Math.Min(best, miniMax(grid, depth+1, !isMax));
grid[i] = 0;
}
}
return best;
}
}
void moveByAI()
{
int best = int.MinValue;
int move = -1;
for(int i =0; i<9;i++)
{
if (grids[i]==0)
{
grids[i] = 2;
int locValue = miniMax(grids, 0, true);
grids[i] = 0;
if(locValue > best)
{
move = i;
best = locValue;
MessageBox.Show(""+i);
}
}
}
buttons[move].PerformClick();
}
I have searched the similar games on forum and google but i could not find exactly.
I am making a puzzle game. and user can get point if the nodes (horizontal sticks) are same color then he can get.
when they are in same direction it says colors matched but in generated node whenever i rotate the sticks it says also same.
Can you take a look? and tell me how to fix. Also if you have better idea about this matching I will be appreciated.
---------
void Update()
{
if (Input.GetMouseButtonDown(0))
{
clickTime = Time.time;
rayhit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, Mathf.Infinity, selectableObjLayerMask);
}
else if (Input.GetMouseButtonUp(0))
{
if (rayhit)
{
if (Time.time - clickTime < .2f)
{
Node node = rayhit.transform.GetComponent<Node>();
if (node != null)
{
for (int i = 0; i < node.sticks.Count; i++)
{
Vector3 newAngles = new Vector3(0, 0, (node.sticks[i].transform.localEulerAngles.z - 45));
newAngles.z = newAngles.z < 0 ? newAngles.z + 180 : newAngles.z;
newAngles.z = newAngles.z >180 ? newAngles.z - 180 : newAngles.z;
node.sticks[i].transform.localEulerAngles = newAngles;
node.sticks[i].degree = (int)newAngles.z;
//******** HERE IS COLOR MATCHING*******
if (node.transform.parent.name=="Node1" && node.sticks[i].degree == 90)
{
colorMatch[1] = node.sticks[i].color;
Debug.Log("COLOR 1___"+ colorMatch[1]);
//Debug.Log(colorMatch1);
}
if (node.transform.parent.name == "Node2" && node.sticks[i].degree == 90)
{
colorMatch[2] = node.sticks[i].color;
Debug.Log("COLOR 2___" + colorMatch[2]);
}
if (node.transform.parent.name == "Node3" && node.sticks[i].degree == 90)
{
colorMatch[3] = node.sticks[i].color;
Debug.Log("COLOR 3___" + colorMatch[3]);
//if (colorMatch[1] == colorMatch[2] && colorMatch[2] == colorMatch[3])
//{
// Debug.Log("COLORS MATCHED : " + colorMatch[1]);
//}
}
if (colorMatch[1]==colorMatch[2] && colorMatch[2]==colorMatch[3])
{
Debug.Log("COLOR MATCHED");
}
}
}
}
else
{
Node currNode = rayhit.transform.GetComponent<Node>();
if(currNode.isMoved == false)
{
smallestId = 0;
smallestDistance = 999;
for (int i = 0; i < nodes.Length; i++)
{
float distance = Vector2.Distance(rayhit.transform.position, nodes[i].transform.position);
if (smallestDistance > distance)
{
smallestDistance = distance;
smallestId = i;
}
}
rayhit.transform.position = nodes[smallestId].transform.position;
if (rayhit.transform.parent != nodes[smallestId].transform)
{
if (nodes[smallestId].transform.childCount > 0 && nodes[smallestId].transform != rayhit.transform.parent)
{
if (currNode != null)
{
for (int i = 0; i < currNode.sticks.Count; i++)
{
nodes[smallestId].transform.GetChild(0).GetComponent<Node>().sticks.Add(currNode.sticks[i]);
currNode.sticks[i].transform.SetParent(nodes[smallestId].transform.GetChild(0));
}
Destroy(rayhit.transform.gameObject);
}
}
else
{
if (currNode != null)
{
currNode.isMoved = true;
}
rayhit.transform.SetParent(nodes[smallestId].transform);
}
}
}
}
}
rayhit = new RaycastHit2D();
}
else if (Input.GetMouseButton(0))
{
if(rayhit.transform != null)
{
Node currNode = rayhit.transform.GetComponent<Node>();
if(currNode != null)
if (currNode.isMoved == false)
{
if (Time.time - clickTime >= 0.2f)
{
Vector2 newPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
rayhit.transform.position = newPos;
}
}
}
}
}
if (node.transform.parent.name=="Node1" && node.sticks[i].degree == 90)
{
colorMatch[1] = node.sticks[i].color;
Debug.Log("COLOR 1___"+ colorMatch[1]);
//Debug.Log(colorMatch1);
}
if (node.transform.parent.name == "Node2" && node.sticks[i].degree == 90)
{
colorMatch[2] = node.sticks[i].color;
Debug.Log("COLOR 2___" + colorMatch[2]);
}
if (node.transform.parent.name == "Node3" && node.sticks[i].degree == 90)
{
colorMatch[3] = node.sticks[i].color;
Debug.Log("COLOR 3___" + colorMatch[3]);
if (colorMatch[1] == colorMatch[2] && colorMatch[2] == colorMatch[3])
{
Debug.Log("COLORS MATCHED : " + colorMatch[1]);
}
}
Here is working code. but how i can destroy the matched sticks?
I have a task called Find and Replace in the DataGridView - It's completed.But i want the replaced count in the message box.
Can anyone help me how to achieve this? Below is my Find and Replace code:
private void btnFindandReplace_Click(object sender, EventArgs e)
{
f.cmbColumnCombo.DataSource = cmbList;
f.ShowDialog();
if (recNo > 0)
recNo = recNo - 30;
LoadPage(MyFOrmat, true);
}
public void LoadPage(string Format, bool isFindAndReplace = false)
{
int startRec;
int endRec;
if (currentPage == PageCount)
{
endRec = (int)maxRec;
}
else
{
endRec = (int)pageSize * currentPage;
}
dataGridView1.Rows.Clear();
if (recNo == 0)
{
dataGridView1.Columns.Clear();
}
int rowindex = 0;
startRec = recNo;
for (int RowCount = startRec; RowCount <= endRec; RowCount++)
{
if (datfile[RowCount].ToString() != "" )
{
if (RowCount == 0)
{
string[] column = datfile[RowCount].Split('þ');
for (int i = 0; i < column.Length - 1; i++)
{
if (column[i].ToString() != "") //if (column[i].ToString() != "" && column[i].ToString() != "\u0014")
{
DataGridViewTextBoxColumn dgvtxtcountry = new DataGridViewTextBoxColumn();
dgvtxtcountry.HeaderText = column[i].ToString();
dgvtxtcountry.Name = column[i].ToString();
dataGridView1.Columns.Add(dgvtxtcountry);
cmbList.Add(column[i]);
// dataGridView1.Columns["Sent Date"].DefaultCellStyle.Format = "dd/MM/yyyy";
i += 1;
}
}
}
if (RowCount != 0)
{
dataGridView1.Rows.Add();
string[] column = datfile[RowCount].Split('þ');
int index = 0;
for (int i = 1; i < column.Length - 1; i++)
{
if (column[i].ToString() != "\u0014")
{
//if (i == 3)
//{
// dataGridView1.Rows[rowindex].Cells[index].Value = Convert.ToDateTime(column[i]).ToString(Format);
//}
//else
//{
dataGridView1.Rows[rowindex].Cells[index].Value = column[i].Trim('þ');
//}
if (StaticVar.FnR == true && index == StaticVar.colindx)
{
if ((column[i]).Contains(StaticVar.Find) != null)
dataGridView1.Rows[rowindex].Cells[index].Value = column[i].Replace(StaticVar.Find, StaticVar.Replace);
}
if (StaticVar.DateFormat != "" && StaticVar.DateFormat != null)
{
if (StaticVar.datecolidx == ((i - 1) / 2))
{
dataGridView1.Rows[rowindex].Cells[index].Value = Convert.ToDateTime(column[i]).ToString(StaticVar.DateFormat);
}
}
index += 1;
i += 1;
}
}
rowindex += 1;
}
}
recNo += 1;
}
}
Declare the replaced variable and increment it every time you replace a value. Show a message box at the end of the method.
public void LoadPage(string Format, bool isFindAndReplace = false) {
int replaced = 0;
....
if ((column[i]).Contains(StaticVar.Find) != null) {
dataGridView1.Rows[rowindex].Cells[index].Value = column[i].Replace(StaticVar.Find, StaticVar.Replace);
replaced++;
}
....
if(isFindAndReplace)
MessageBox.Show(string.Format("{0} occurrence(s) replaced.", replaced));
}
Currently, I am doing a log analyzer for my personal project.
My issue here is that I am new to c# and I have an performance issue with my tool.
Everytime the device(iOS) is interacted, I get an output syslog from a library and it comes in to the output handler.
public void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine, iosSyslogger form, string uuid)
{
string currentPath = System.Environment.CurrentDirectory;
bool exit = false;
if (exit == true) return;
try
{
form.BeginInvoke(new Action(() =>
{
form.insertLogText = outLine.Data;
}));
using (System.IO.StreamWriter file = new System.IO.StreamWriter(currentPath + #"\syslog" + uuid + ".txt", true))
{
file.WriteLine(outLine.Data);
}
}
catch
{
return ;
}
//*Most of the logic for outputing the log should be dealt from this output Handler
}
Then, I write the outline.Data to Data grid view. My concern is that I need to be able to search and filter through data gridview.
Curently I am using visibility = false for search filtering ( if the row does not match the given filter specification I set the row to visibility =false)
This requires the program to traverse the entire datagridview to check whether the condition is met.
Will there be any better way to filter and search within ?
(When I have thousands of lines of row, it takes at least 20 seconds to process it)
Below is the code for filtering, and searching through the results function.
private void searchResult(string term)
{
if (term != null)
{
int i = 0;
while (i < dataGridView1.Rows.Count - 1)
{
if (dataGridView1.Rows[i].Cells[3] == null)
{
i++;
continue;
}
if (dataGridView1.Rows[i].Visible == false)
{
i++;
continue;
}
else if (dataGridView1.Rows[i].Cells[2].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[3].Value.ToString().Contains(term) || dataGridView1.Rows[i].Cells[4].Value.ToString().Contains(term))
{
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0)
{
int z = 0;
for (z = 0; z <= count; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
i = i + z;
}
else
{
dataGridView1.Rows[i].Visible = true;
i++;
}
}
else
{
dataGridView1.Rows[i].Visible = false;
i++;
}
}
}
}
public filteringThelist(){
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
dataGridView1.Rows[i].Visible = false;
int count1,count2,count3=0;
count1 = 1;
count2 = 1;
count3 = 1;
int z = 0;
foreach (KeyValuePair<string, string> entry in totalSelected)
{
if (entry.Value == "devicename" && dataGridView1.Rows[i].Cells[1].Value != null)
{
if (dataGridView1.Rows[i].Cells[1].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (devicename.CheckedItems.Count > 1&&count1!= devicename.CheckedItems.Count)
{
count1++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "process" && dataGridView1.Rows[i].Cells[2].Value != null)
{
if (dataGridView1.Rows[i].Cells[2].Value.ToString().Trim().Equals(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
}
else if (processlistname.CheckedItems.Count > 1 && count2 != processlistname.CheckedItems.Count)
{
count2++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
else if (entry.Value == "loglevel" && dataGridView1.Rows[i].Cells[3].Value != null)
{
if (dataGridView1.Rows[i].Cells[3].Value.ToString().Trim().Contains(entry.Key.Trim()))
{
string multirow1 = dataGridView1.Rows[i].Cells[5].Value.ToString();
int counts = Convert.ToInt32(multirow1);
if (counts > 0)
{
for (z = 0; z < counts; z++)
{
dataGridView1.Rows[i + z].Visible = true;
}
}
else
{
dataGridView1.Rows[i].Visible = true;
}
continue;
}
else if (loglevelCheckBox.CheckedItems.Count > 1 && count3 != loglevelCheckBox.CheckedItems.Count)
{
count3++;
continue;
}
else
{
dataGridView1.Rows[i].Visible = false;
break;
}
}
// do something with entry.Value or entry.Key
}
string multirow = dataGridView1.Rows[i].Cells[5].Value.ToString();
int count = Convert.ToInt32(multirow);
if (count > 0&& dataGridView1.Rows[i].Visible==false)
{
for (int k = 0; k <= count; k++)
{
dataGridView1.Rows[i + k].Visible = false;
}
}
i = i + z;
}
The performance problem is because your DataGridView is redrawing at each modification.
Don't fill the DataGridView directly from your Data. Rather create a DataTable and bind it to DataGridView with a BindingSource.
Then use the "Filter" property of the binding source to view extracts of dataTable in the DataGridView. The "Filter" property is a string whose content is similar to that of a WHERE SQL clause.
I am trying to implement minimax in my C# code for tictactoe. For some reason, when the depth = 1 and I debug it to check to see all of the values returned from different paths; I see crazy values like -1000, -5000, -1000, etc! How is this possible? What is happening? This is my full code,
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Minimax_TicTacToe
{
public partial class Main : Form
{
//Definition constants
private const int EMPTY = 0;
private const int PLAYER = 1;
private const int COMPUTER = 2;
private const int PLAYER_WON = 0;
private const int COMPUTER_WON = 1;
private const int DRAW = 2;
private const int GAME = 3;
private const int OVER = 4;
//Internals
private int turns = 0;
private int turn = PLAYER;
private String player_mark = "X";
private String computer_mark = "O";
//Grid
private byte[] grid = {
0, 0, 0,
0, 0, 0,
0, 0, 0
};
public Main()
{
InitializeComponent();
}
private void Main_Load(object sender, EventArgs e)
{
}
/*
private int Minimax(byte[] ngrid, int depth = 0, int score = 0)
{
if (depth == 0)
{
return Minimax(new byte[] { grid[0], grid[1], grid[2],
grid[3], grid[4], grid[5],
grid[6], grid[7], grid[8] },
depth + 1);
}
else
{
int status = GameStatus(ngrid);
if (status == PLAYER_WON) return -1;
else if (status == COMPUTER_WON) return 1;
else if (status == DRAW) return 0;
int i;
for (i = 0; i < grid.Length; i++)
{
if (ngrid[i] == 0)
{
byte[] board = new byte[] {
ngrid[0], ngrid[1], ngrid[2],
ngrid[3], ngrid[4], ngrid[5],
ngrid[6], ngrid[7], ngrid[8]
};
board[i] = (depth % 2 == 0) ? (byte)PLAYER : (byte)COMPUTER;
score = Minimax(board, depth + 1);
if (score == 1 && depth == 1) return i;
if (score == 1) return 1;
}
}
return 0;
}
}*/
private int Minimax(byte[] ngrid, int depth = 0)
{
if (depth == 0)
{
return Minimax(new byte[] { grid[0], grid[1], grid[2],
grid[3], grid[4], grid[5],
grid[6], grid[7], grid[8] },
depth + 1);
}
else
{
int status = GameStatus(ngrid);
if (status == PLAYER_WON) return -1;
else if (status == COMPUTER_WON) return 1;
else if (status == DRAW) return 0;
int i;
int score = 0;
List<Carrier> carry = new List<Carrier>();
for (i = 0; i < grid.Length; i++)
{
if (ngrid[i] == 0)
{
byte[] board = new byte[] {
ngrid[0], ngrid[1], ngrid[2],
ngrid[3], ngrid[4], ngrid[5],
ngrid[6], ngrid[7], ngrid[8]
};
board[i] = (depth % 2 == 0) ? (byte)PLAYER : (byte)COMPUTER;
score += Minimax(board, depth + 1);
if (depth == 1)
{
Carrier c = new Carrier();
c.offset = i;
c.score = score;
carry.Add(c);
}
}
}
if (depth == 1)
{
MessageBox.Show("");
}
return score;
}
}
private void ComputersTurn()
{
turn = COMPUTER;
turns++;
int status = GameStatus(grid);
switch (status)
{
case GAME:
int offset = Minimax(grid);
grid[offset] = COMPUTER;
turn = PLAYER;
UpdateBoard();
break;
}
switch (GameStatus(grid))
{
case PLAYER_WON:
turn = COMPUTER;
MessageBox.Show("You win!");
break;
case COMPUTER_WON:
turn = COMPUTER;
MessageBox.Show("You lost!");
break;
case DRAW:
turn = COMPUTER;
MessageBox.Show("DRAW!");
break;
}
}
private void UpdateBoard()
{
int n = 0;
grid0.Text = (grid[n] != 0) ? ( (grid[n] == PLAYER ? player_mark : computer_mark) ) : "";
n++;
grid1.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid2.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid3.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid4.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid5.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid6.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid7.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
grid8.Text = (grid[n] != 0) ? ((grid[n] == PLAYER ? player_mark : computer_mark)) : "";
n++;
}
private int GameStatus(byte[] pgrid)
{
for (int i = 0; i < 3; i++)
{
if (pgrid[i * 3] == pgrid[i * 3 + 1] && pgrid[i * 3] == pgrid[i * 3 + 2] && pgrid[i * 3] != 0)
return SelectWinner(pgrid[i * 3]);
if (pgrid[i] == pgrid[i + 3] && pgrid[i] == pgrid[i + 6] && pgrid[i] != 0)
return SelectWinner(pgrid[i]);
}
if (pgrid[0] == pgrid[4] && pgrid[0] == pgrid[8] && pgrid[0] != 0)
return SelectWinner(pgrid[0]);
if (pgrid[2] == pgrid[4] && pgrid[2] == pgrid[6] && pgrid[2] != 0)
return SelectWinner(pgrid[2]);
if (turns == 4)
return DRAW;
return GAME;
}
private int SelectWinner(byte item)
{
if (item == PLAYER)
return PLAYER_WON;
else if (item == COMPUTER)
return COMPUTER_WON;
throw new Exception("SELECTION ERROR");
}
private void grid0_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[0] = PLAYER;
grid0.Text = player_mark;
ComputersTurn();
}
private void grid1_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[1] = PLAYER;
grid1.Text = player_mark;
ComputersTurn();
}
private void grid2_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[2] = PLAYER;
grid2.Text = player_mark;
ComputersTurn();
}
private void grid3_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[3] = PLAYER;
grid3.Text = player_mark;
ComputersTurn();
}
private void grid4_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[4] = PLAYER;
grid4.Text = player_mark;
ComputersTurn();
}
private void grid5_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[5] = PLAYER;
grid5.Text = player_mark;
ComputersTurn();
}
private void grid6_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[6] = PLAYER;
grid6.Text = player_mark;
ComputersTurn();
}
private void grid7_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[7] = PLAYER;
grid7.Text = player_mark;
ComputersTurn();
}
private void grid8_Click(object sender, EventArgs e)
{
if (turn == COMPUTER)
return;
grid[8] = PLAYER;
grid8.Text = player_mark;
ComputersTurn();
}
}
class Carrier
{
public int score;
public int offset;
}
}
The one thing that jumps out at me is this piece:
score += Minimax(...
I think you'll want your minimax to select the move with the best score and return that score, not the sum of the scores for all possible moves from that position.