Reputation: 21
I am making a tic tac toe game and I am making it to be unbeatable but first I have to let the computer know the rules.
I'm stuck in a step that is => when it's the computer's turn and we have just started the game so no win case so it's up to the computer to generate a random number that will be the computer's choice ( the block where he mark X or O ) so I need it to generate a number from 1 to 9 but by excluding the already used blocks ( numbers ).
I tried doing that by making a list and adding a number every time the human player used a block but I can't find a way to use those numbers from the list as exclusion for the random choice of the computer.
Here is what I tried and thnx in advance:
//random
List<int> cas = new List<int>();
if (c1 == true)
{
cas.Add(1);
}
if (c2 == true)
{
cas.Add(2);
}
if (c3 == true)
{
cas.Add(3);
}
if (c4 == true)
{
cas.Add(4);
}
if (c5 == true)
{
cas.Add(5);
}
if (c6 == true)
{
cas.Add(6);
}
if (c7 == true)
{
cas.Add(7);
}
if (c8 == true)
{
cas.Add(8);
}
if (c9 == true)
{
cas.Add(9);
}
for (int i = 0; i < cas.Count; i++)
{
random_except_list(cas[]);
}
public static int random_except_list(int[] x)
{
Random r = new Random();
int result = r.Next(1, 9 - );
for (int i = 0; i < x.Length; i++)
{
if (result < x[i])
return result;
result++;
}
return result;
}
Upvotes: 1
Views: 2733
Reputation: 4313
I believe it is better to work with positions left. So user or computer select from all open positions:
using System;
using System.Collections.Generic;
class app
{
public static int random_except_list(List<int> openPositions)
{
Random r = new Random();
int index = r.Next(openPositions.Count - 1);
int result = openPositions[index];
openPositions.RemoveAt(index);
return result;
}
static void Main()
{
List<int> openPositions = new List<int>();
for (int i = 1; i < 10; i++)
{
openPositions.Add(i);
}
bool turn = false;
while (openPositions.Count > 0)
{
foreach (int value in openPositions)
{
Console.Write(value + " ");
}
Console.WriteLine();
if (!turn)
{
while (true)
{
Console.WriteLine("Choose your Position");
ConsoleKeyInfo key = Console.ReadKey();
int num = (int)key.KeyChar - 48;
if (openPositions.Contains(num))
{
openPositions.Remove(num);
Console.WriteLine();
break;
}
else Console.Write(" is not Valid: ");
}
}
else
{
int compPos = random_except_list(openPositions);
Console.WriteLine("Computer choose: " + compPos);
}
turn = !turn;
}
Console.WriteLine("No positions left");
Console.ReadKey();
}
}
Upvotes: 0
Reputation: 34150
Lets have possible places to use:
List<int> possible = Enumerable.Range(1,9).ToList(); // create a list and add 1-9
and used places:
List<int> used = new List<int>();
Random rnd = new Random();
Now everytime we generate a random number in the range of possible
list count as index and remove it from there and move it to used:
int index = rnd.Next(0, possible.Count);
used.Add(possible[index]);
possible.RemoveAt(index);
for user its just enough to check if it exists in the used so the acceptable number should be:
!used.Any(x=> x== NumberUserHaveChosen)
So the first time the random number can be 0-8 (as possible.Count==9) and take from it at random index.
the second time the random number can be 0-7 (as possible.Count==8) and take from it at random index.
and so on... while the possible.Count != 0
in this case there is no need to generate random numbers several times that finally it won't exist in our used List.
Several years ago I was working on a Sudoku algorithm, and what I was trying to achieve was to generate a valid solved sudoku table in minimum time possible, i get to the conclusion that I should replace the algorithm that each time I generate a number I have to check some lists to make sure the number was not generated before, as count of numbers were increasing these comparisons would become more and more. for example when only the number 4 is remaining, I should generate random numbers till I get 4. so I used this approach and the result was amazing.
Upvotes: 1
Reputation: 26917
Just trying to use what you have written (more or less), but changing the method to take a List<int>
which is what you are building, I would write the method using LINQ like this (except I would create a static Random
variable and keep it between calls):
public static int random_except_list(List<int> x) => Enumerable.Range(1, 9).Where(n => !x.Contains(n)).ToList()[new Random().Next(0, 9 - x.Count)];
However, you can implement the same idea in a more explicit way using procedural code:
public static int random_except_list_explicit(List<int> x) {
// First, generate a list of possible answers by skipping the except positions in x
var possibles = new List<int>();
for (int i = 1; i <= 9; i++)
if (!x.Contains(i))
possibles.Add(i);
// now pick a random member of the possible answers and return it
return possibles[new Random().Next(0, possibles.Count)];
}
Upvotes: 0
Reputation: 53
I think you should do something like this:
public static int random_except_list(List<int> x)
{
Random r = new Random();
int result = 0;
while (true)
{
result = r.Next(1, 10);
if (!x.Contains(result))
return result;
}
}
Upvotes: 0