using System; using System.Collections.Generic; namespace TicTacToeAI { class Program { static void Main(string[] args) { Console.WriteLine("Vil du starte? (Y/N)"); string input = Console.ReadLine(); TicTacToe game = new TicTacToe(input); game.startGame(); } } class Grid { //public string[,] grid; public string[,] grid { get; } public int row; public int col; public Grid(string[,] gridIn, int rowIn, int colIn, bool makeMove,string play = " ") { grid = gridIn; row = rowIn; col = colIn; Console.WriteLine("___________"); Console.WriteLine($"|{grid[0, 0]} | {grid[0, 1]} | {grid[0, 2]}|"); Console.WriteLine("|__|___|__|"); Console.WriteLine($"|{grid[1, 0]} | {grid[1, 1]} | {grid[1, 2]}|"); Console.WriteLine("|__|___|__|"); Console.WriteLine($"|{grid[2, 0]} | {grid[2, 1]} | {grid[2, 2]}|"); Console.WriteLine("|__|___|__|"); if (makeMove) { setMove(row, col, play); } } void setMove(int a, int b, string player) { grid[a, b] = player; } } class TicTacToe { string[,] Board = new string[3, 3] { { " ", " ", " " }, { " ", " ", " " }, { " ", " ", " " } }; bool turn = false; //false = player, true = AI. false = X, true = O // player = X // computer = O public TicTacToe(string start) { if(start.ToUpper() == "N") { switchTurn(); } } void switchTurn() { turn = !turn; } void printBoard() { Console.WriteLine("___________"); Console.WriteLine($"|{Board[0, 0]} | {Board[0, 1]} | {Board[0, 2]}|"); Console.WriteLine("|__|___|__|"); Console.WriteLine($"|{Board[1, 0]} | {Board[1, 1]} | {Board[1, 2]}|"); Console.WriteLine("|__|___|__|"); Console.WriteLine($"|{Board[2, 0]} | {Board[2, 1]} | {Board[2, 2]}|"); Console.WriteLine("|__|___|__|"); } bool validMove(int a, int b) { if(Board[a,b] == " ") { return true; } else { return false; } } void makeMove(string position,string player) { int row = (int)Math.Ceiling(int.Parse(position) / 3f - 1f); int col = (int.Parse(position) - 1) % 3; if (validMove(row, col)) { Board[row, col] = player; } switchTurn(); } void setMove(int a, int b, string player) { if (validMove(a, b)) { Board[a, b] = player; } switchTurn(); } bool gameOver(Grid pos) { // Check if the game is over on the current positions child move. if (checkWin(pos, "X")) { return true; } else if (checkWin(pos, "O")) { return true; } return false; } void makeMoveAI() { // Make new grid object Grid currentGrid = new Grid(Board, 0, 0,false); // Get best evaluation from miniMax algorithm. (Grid,int) bestMove = MiniMax(currentGrid, 100000000, true); Console.WriteLine($"placing: {bestMove.Item1.row}, {bestMove.Item1.col}"); setMove(bestMove.Item1.row, bestMove.Item1.col, "O"); } bool checkWin(Grid pos, string player) { for (int y = 0; y < 3; y++) { if (pos.grid[y, 0] == player && pos.grid[y, 1] == player && pos.grid[y, 2] == player) { return true; } else if (pos.grid[0, y] == player && pos.grid[1, y] == player && pos.grid[2, y] == player) { return true; } } if ((pos.grid[0, 0] == player && pos.grid[1, 1] == player && pos.grid[2, 2] == player) || (pos.grid[0, 2] == player && pos.grid[1, 1] == player && pos.grid[2, 0] == player)) { return true; } return false; } int evalPosition(Grid pos) { int eval = 0; for (int y = 0; y < 3; y++) { if(pos.grid[y,0] == "O" && pos.grid[y,1] == "O" && pos.grid[y,2] == "O") { eval += 10; } else if(pos.grid[0,y] == "O" && pos.grid[1,y] == "O" && pos.grid[2,y] == "O") { eval += 10; } else if (pos.grid[y, 0] == "X" && pos.grid[y, 1] == "X" && pos.grid[y, 2] == "X") { eval += -10; } else if (pos.grid[0, y] == "X" && pos.grid[1, y] == "X" && pos.grid[2, y] == "X") { eval += -10; } } if ((pos.grid[0, 0] == "O" && pos.grid[1, 1] == "O" && pos.grid[2, 2] == "O") || (pos.grid[0, 2] == "O" && pos.grid[1, 1] == "O" && pos.grid[2, 0] == "O")) { eval += 10; } if ((pos.grid[0, 0] == "X" && pos.grid[1, 1] == "X" && pos.grid[2, 2] == "X") || (pos.grid[0, 2] == "X" && pos.grid[1, 1] == "X" && pos.grid[2, 0] == "X")) { eval += -10; } return eval; } bool validMoveGrid(Grid pos, int a, int b) { if(pos.grid[a,b] == "X" || pos.grid[a, b] == "O") { Console.WriteLine("False"); return false; } else { Console.WriteLine("true"); return true; } } List<Grid> getPossibleMoves(Grid pos, string player) { //List<Grid> possiblePositions = new List<Grid>(); //Console.WriteLine("Checking possible positions"); //for (int i = 0; i < 3; i++) //{ // for (int x = 0; x < 3; x++) // { // Console.WriteLine($"{i},{x}"); // if (validMoveGrid(pos, i, x)) // { // Console.WriteLine("Found possible position"); // possiblePositions.Add(new Grid(pos.grid, i, x, true, player)); // } // } //} //possiblePositions.Add(new Grid(pos.grid, 1, 1, true, player)); //return possiblePositions; List<Grid> possibleGrids = new List<Grid>(); if (validMoveGrid(pos,0,0)) { possibleGrids.Add(new Grid(pos.grid, 0, 0, true, player)); } if (validMoveGrid(pos, 0, 1)) { possibleGrids.Add(new Grid(pos.grid, 0, 1, true, player)); } if (validMoveGrid(pos, 0, 2)) { possibleGrids.Add(new Grid(pos.grid, 0, 2, true, player)); } if (validMoveGrid(pos, 1, 0)) { possibleGrids.Add(new Grid(pos.grid, 1, 0, true, player)); } if (validMoveGrid(pos, 1, 1)) { possibleGrids.Add(new Grid(pos.grid, 1, 1, true, player)); } if (validMoveGrid(pos, 1, 2)) { possibleGrids.Add(new Grid(pos.grid, 1, 2, true, player)); } if (validMoveGrid(pos, 2, 0)) { possibleGrids.Add(new Grid(pos.grid, 2, 0, true, player)); } if (validMoveGrid(pos, 2, 1)) { possibleGrids.Add(new Grid(pos.grid, 2, 1, true, player)); } if (validMoveGrid(pos, 2, 2)) { possibleGrids.Add(new Grid(pos.grid, 2, 2, true, player)); } return possibleGrids; } (Grid,int) MiniMax(Grid pos, int depth, bool maximizingPlayer) { Console.WriteLine("Run once"); if(depth == 0 || gameOver(pos)) { Console.WriteLine("gameover"); // Check evaluation of current child position int staticEval = evalPosition(pos); //Return evaluation and the grid return (pos, staticEval); } if (maximizingPlayer) { (Grid, int) maxEval; maxEval.Item1 = null; maxEval.Item2 = -1; List<Grid> possibleMoves = getPossibleMoves(pos,"O"); foreach (Grid position in possibleMoves) { Console.WriteLine("check true"); (Grid, int) eval = MiniMax(position, depth - 1, false); if(maxEval.Item2 > eval.Item2) { maxEval = eval; } } if(maxEval.Item1 == null) { // there wasnt any best possible move. pick the first one if(!(possibleMoves.Count == 0)) { maxEval.Item1 = possibleMoves[0]; } else { //tie } } return maxEval; } else { (Grid, int) minEval; minEval.Item1 = null; minEval.Item2 = 1; List<Grid> possibleMoves = getPossibleMoves(pos, "X"); Console.WriteLine("checkfalse"); foreach (Grid position in possibleMoves) { Console.WriteLine("checkFalse"); (Grid, int) eval = MiniMax(position, depth - 1, true); if (minEval.Item2 > eval.Item2) { minEval = eval; } } if (minEval.Item1 == null) { // there wasnt any best possible move. pick the first one if (!(possibleMoves.Count == 0)) { minEval.Item1 = possibleMoves[0]; } else { //tie } } return minEval; } } public void startGame() { printBoard(); if (turn) { //computer turn Console.WriteLine("Computer is making a move"); makeMoveAI(); Console.WriteLine("ai turn"); } else { Console.WriteLine($"Hvor ville du sætte dit X?"); string input = Console.ReadLine(); makeMove(input, "X"); } startGame(); } } }
Write, Run & Share C# code online using OneCompiler's C# online compiler for free. It's one of the robust, feature-rich online compilers for C# language, running on the latest version 8.0. Getting started with the OneCompiler's C# compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C#
and start coding.
OneCompiler's C# online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.
using System;
namespace Sample
{
class Test
{
public static void Main(string[] args)
{
string name;
name = Console.ReadLine();
Console.WriteLine("Hello {0} ", name);
}
}
}
C# is a general purpose object-oriented programming language by Microsoft. Though initially it was developed as part of .net but later it was approved by ECMA and ISO standards.
You can use C# to create variety of applications, like web, windows, mobile, console applications and much more using Visual studio.
Data Type | Description | Range | size |
---|---|---|---|
int | To store integers | -2,147,483,648 to 2,147,483,647 | 4 bytes |
double | to store large floating point numbers with decimals | can store 15 decimal digits | 8 bytes |
float | to store floating point numbers with decimals | can store upto 7 decimal digits | 4 bytes |
char | to store single characters | - | 2 bytes |
string | to stores text | - | 2 bytes per character |
bool | to stores either true or false | - | 1 bit |
datatype variable-name = value;
When ever you want to perform a set of operations based on a condition or set of few conditions IF-ELSE is used.
if(conditional-expression) {
// code
}
else {
// code
}
You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.
Switch is an alternative to If-Else-If ladder.
switch(conditional-expression) {
case value1:
// code
break; // optional
case value2:
// code
break; // optional
...
default:
// code to be executed when all the above cases are not matched;
}
For loop is used to iterate a set of statements based on a condition.
for(Initialization; Condition; Increment/decrement) {
// code
}
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while(condition) {
// code
}
Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.
do {
// code
} while (condition);
Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.
data-type[] array-name;
Method is a set of statements which gets executed only when they are called. Call the method name in the main function to execute the method.
static void method-name()
{
// code to be executed
}