0

I the following array of all false values

bool[] deniedMoves = new bool[64];

think of a game board with x possible moves. After a move is played, it is recorded, some of the moves become impossible in the next play. A game like Go would fit this description as you cannot play over an intersection that has already been played on.

I want the "AI" to play a random move from a list of possible moves. First move is OK:

Random randMove1 = new Random();
int selectedMove1 = randMove1.Next(1, deniedMoves.Length);

and then that move sets some of the values in my array as true.

For example:

void Reset()
{
    if (mainBoard[0, 0] == 1)
        deniedMoves[0] = true;
    deniedMoves[3] = true;
    deniedMoves[5] = true;
}

The next random move the "AI" will play cannot choose from all 64 possibilities so I don't want it to randomize to 5 for example.

I have tried something like this, but RandomElement doesn't belong...

IEnumerable<bool> queryMoves = deniedMoves.Where(deniedMove => deniedMove !=             
true).RandomElement();

My first question and I am terribly sorry for bad code and general coding ignorance. I have tried.

2
  • If you might have a problem with the if Commented Feb 6, 2018 at 0:09
  • in your initial example int selectedMove1 = randMove1.Next(1, deniedMoves.Length); why do you skip the first item in the array? Commented Feb 6, 2018 at 0:11

3 Answers 3

1

What you are doing is what I call "the Lottery problem": You have a number of options. But as each option is picked, it is removed from teh list of possible options. The same way you literally draw Numbers from a set of lottery balls.

You should store all the options in a List<bool> and remove elements as you draw/use them. Example code done largely in my head:

int[] input = new int[20]();

//Fill array
for(int i = 0; i < numbers.lenght; i++)
  input[i] = i;

//initialise the real work variables
List<int> Drawables = new List<int>(input);
List<int> DrawnNumbers = new List<int>();
Random rng = new Random();

while(Drawables.Count > 0){
  int temp = Random.NextInt(Drawables.Count);
  DrawnNumbers = Drawables[i];
  Drawables.Remove(temp);
}
Sign up to request clarification or add additional context in comments.

4 Comments

How about var Drawables = Enumerable.Range(0, 20).ToList(); ? Your code has a lot of errors (where is i from at the bottom? What is numbers.lenght? Where is numbers from? You don't have a List<bool> any where?)
That works too. In the end whose loop fills the array does not really mater, as there will always be a loop. I would propably use Enumerable.Range just to build the input array as I wanted the explicit array-> List step in there. I think keeping it simple to read and Framework agonostic (Enumerable.Range needs 3.5+) maters more with examples taht I will post a lot.
Except your code won't run. Also, the OP specified a move may disqualify multiple moves, making this more complicated than a simple card deal, though your idea is sound.
That is why I said "largely done in my head". It is an idea done without a compiler at my call. Just something I scribelled up in Notepad++ half from memory. And I have a really poor syntax memory.
1

I'm not certain if this is what you're after, and it's very similar to NetMages' answer, but one thing you could do is write a method that returns all the indexes in your array that contain a false value:

private static IEnumerable<int> GetIndexesOfFalseItems(IEnumerable<bool> allItems)
{
    return allItems
        .Select((value, index) => new { value, index })
        .Where(item => item.value == false)
        .Select(item => item.index);
}

Then, to choose a random item from your array whose value is false, you could just do:

private static readonly Random Rnd = new Random();

private static void Main()
{
    // Initialize all moves to false
    bool[] allMoves = new bool[64];
    for (int i = 0; i < allMoves.Length; i++) allMoves[i] = false;

    // Pretend a move was made and set some to true
    allMoves[0] = true;
    allMoves[3] = true;
    allMoves[5] = true;

    // Get ALL indexes of 'false' items (currently everything except 0, 3, and 5)
    var validIndexes = GetIndexesOfFalseItems(allMoves).ToList();

    // Choose a random item from that list
    var randomValidIndex = validIndexes[Rnd.Next(validIndexes.Count)];

    // Now we get our next move from our main list at that index
    var nextMove = allMoves[randomValidIndex];

    // Rest if game code...
}

Comments

0

I would use some LINQ - this may not be the most efficient answer...

bool[] deniedMoves = new bool[64];

System.Random randMove1 = new System.Random();

First, choose a random move amongst the allowed moves:

int allowedMove = randMove1.Next(0, deniedMoves.Count(d => !d)-1);

Then get the actual move index:

int selectedMove = deniedMoves.Select((d, i) => new { d, i })
                              .Where(di => !di.d)
                              .Skip(allowedMove)
                              .First().i;

I changed the moves to be from 0 - 63 as that matches C# arrays better.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.