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();
        }
    }
}
 

C Sharp Online Compiler

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.

Read inputs from stdin

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);
	}
     }
}

About C Sharp

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.

Syntax help

Data types

Data TypeDescriptionRangesize
intTo store integers-2,147,483,648 to 2,147,483,6474 bytes
doubleto store large floating point numbers with decimalscan store 15 decimal digits8 bytes
floatto store floating point numbers with decimalscan store upto 7 decimal digits4 bytes
charto store single characters-2 bytes
stringto stores text-2 bytes per character
boolto stores either true or false-1 bit

Variables

Syntax

datatype variable-name = value;

Loops

1. If-Else:

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.

2. Switch:

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;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement) {
  // code  
} 

4. While:

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 
}

5. Do-While:

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);

Arrays

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.

Syntax

data-type[] array-name;

Methods

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.

Syntax

static void method-name() 
{
  // code to be executed
}