Empty Sudoku Filler C++ - c++

I'm working on a program that fills in an empty 9x9 array with the proper values for a sudoku board. My validation method works as I've tested it out in a simple iterative backtracking approach.
My current approach is to randomly choose a row and a column and place an appropriate value, I am also implementing backtracking through the use of recursion. Here is my solver function:
void solve (int board[9][9]) {
static int counter = 0;
int val = 0;
int row = 0;
int col = 0;
if (counter == 81) {
print (board, counter);
exit(1);
}
while (1) {
row = rand() % 9;
col = rand() % 9;
if (board[row][col] == 0)
break;
}
++counter;
for (int i = 1; i < 10; i++) {
val = i;
if (ok (board, row, col, val)) {
board[row][col] = val;
solve (board);
}
}
--counter;
}
Now the issue I am having is that I never reach 81, my function terminates before that, I am assuming the stack gets empty and returns to main. Can you help me understand what mistake I am making? Thank you.

When you try to fill in a Sudoku grid with appropriate values, you eventually end up in deadlocks : situations where the cell you are trying to find a value for cannot be filled in without breaking Sudoku rules. As a simple example, consider a grid where the first row is [x, 2, 3, 4, 5, 6, 7, 8, 9] and the first column is [x, 1, 8, 2, 3, 4, 5, 6, 7]. x cannot be filled in, but all of the other values follow the rules.
In your case, when a deadlock happens, the ok condition isn't fulfilled by any of the values from 1 to 9 and the execution goes back one layer of recursion, to the previous cell, where a value has already been chosen. There, the function tries the next possible value.
In the case of a deadlock on a cell that has had a value (that is, a multiple-level deadlock), the execution goes back one layer of recursion again, but the value is still there. That causes subsequent ok conditions to fail when they should succeed, because of these "ghost" values. The problem doesn't occur for a simple deadlock because the value stays 0.
After the for loop, you need to set the value of board[row][col] back to 0.

Related

Implementing a crossover function for multiple "Salesmen" TSP in a genetic algorithm

I’m trying to solve a variant of the TSP problem with “multiple salesmen". I have a series of n waypoints and m drones and I want to generate a result which sorts of balances the number of waypoints between drones and returns an acceptable shortest travelling time. At the moment, I'm not really too worried about finding an optimal solution, I just want something that works at this point. I've sort of distilled my problem to a traditional TSP run multiple times. My example is for a series of waypoints:
[0,1,2,3,4,5,6,7,8,9,10,11]
where 0 == 11 is the start and end point. Say I have 4 drones, I want to generate something like:
Drone A = [0,1,2,3,11]
Drone B = [0,5,6,7,11]
Drone C = [0,4,8,11]
Drone D = [0,9,10,11]
However, I’m struggling to generate a consistent output in my crossover function. My current function looks like this:
DNA DNA::crossover( DNA &parentB)
{
// sol holds the individual solution for
// each drone
std::vector<std::vector<std::size_t>> sol;
// contains the values in flattened sol
// used to check for duplicates
std::vector<std::size_t> flat_sol;
// returns the number of solutions
// required
int number_of_paths = this→getSolution().size();
// limits the number of waypoints required for each drone
// subtracting 2 to remove “0” and “11”
std::size_t max_wp_per_drone = ((number_of_cities-2)/number_of_drones) + 1;
for(std::size_t i = 0; i < number_of_paths; i++)
{
int start = rand() % (this->getSolution().at(i).size() -2) + 1;
int end = start + 1 + rand() % ((this->getSolution().at(i).size()-2) - start +1);
std::vector<std::size_t>::const_iterator first = this->getSolution().at(i).begin()+start;
std::vector<std::size_t>::const_iterator second = this- >getSolution().at(i).begin()+end;
// First Problem occurs here… Sometimes, newOrder can return nothing based on
//the positions of start and end. Tried to mitigate by putting a while loop
to regenerate the vector
std::vector<std::size_t> newOrder(first, second);
// RETURNS a vector from the vector of vectors sol
flat_sol = flatten(sol);
// compare new Order with solution and remove any duplicates..
for(std::size_t k = 0; k < newOrder.size(); k++ )
{
int duplicate = newOrder.at(k);
if(std::find(flat_sol.begin(), flat_sol.end(), duplicate) != flat_sol.end())
{
// second problem is found here, sometimes,
// new order might only return a vector with a single value
// or values that have already been assigned to another drone.
// In this case, those values are removed and newOrder is now 0
newOrder.erase(newOrder.begin()+k);
}
}
// attempt to create the vectors here.
for(std::size_t j = 1; j <=parentB.getSolution().at(i).size()-2; j++)
{
int city = parentB.getSolution().at(i).at(j);
if(newOrder.empty())
{
if(std::find(flat_sol.begin(), flat_sol.end(), city) == flat_sol.end())
{
newOrder.push_back(city);
}
}
else if((std::find(newOrder.begin(), newOrder.end(), city) == newOrder.end())
&&(std::find(flat_sol.begin(), flat_sol.end(), city) == flat_sol.end())
&& newOrder.size() < max_wp_per_drone )
{
newOrder.push_back(city);
}
}
sol.push_back(newOrder);
}
// waypoints and number_of drones are known,
//0 and 11 are appended to each vector in sol in the constructor.
return DNA(sol, waypoints, number_of_drones);
}
A sample output from my previous runs return the following:
[0,7,9,8, 11]
[0, 1,2,4,11]
[0, 10, 6, 11]
[0,3,11]
// This output is missing one waypoint.
[0,10,7,5, 11]
[0, 8,3,1,11]
[0, 6, 9, 11]
[0,2,4,11]
// This output is correct.
Unfortunately, this means in my subsequent generations of new children. and me getting the correct output seems to be random. For example, for one generation, I had a population size which had 40 correct children and 60 children with missing waypoints while in some cases, I've had more correct children. Any tips or help is appreciated.
Solved this by taking a slightly different approach. Instead of splitting the series of waypoints before perfoming crossover, I simply pass the series of waypoints
[0,1,2,3,4,5,6,7,8,9,10,11]
perform crossover, and when computing fitness of each set, I split the waypoints based on m drones and find the best solution of each generation. New crossover function looks like this:
DNA DNA::crossover( DNA &parentB)
{
int start = rand () % (this->getOrder().size()-1);
int end = getRandomInt<std::size_t>(start +1 , this->getOrder().size()-1);
std::vector<std::size_t>::const_iterator first = this->getOrder().begin() + start;
std::vector<std::size_t>::const_iterator second = this->getOrder().begin() + end;
std::vector<std::size_t> newOrder(first, second);
for(std::size_t i = 0; i < parentB.getOrder().size(); i++)
{
int city = parentB.getOrder().at(i);
if(std::find(newOrder.begin(), newOrder.end(), city) == newOrder.end())
{
newOrder.push_back(city);
}
}
return DNA(newOrder, waypoints, number_of_drones);
}

Difficulty with an accumulator in a nested for loop

I'm pretty new at C++, and I have to write code for a matching game, and I'm having trouble with the function that detects matches.
Below is a simpler, watered down version of the game I made to try to debug the match function.
Basically I have a bunch of numbers stored in a 2D array, and I need to cycle through the grid to see if there are any matches (3 of the same character in a row, vertically or horizontally, constitutes a match). The user gets one point for every match.
Every time there's a match, I need to accumulate a variable that stores the user's score. I think the code is pretty intuitive, the loops and if statements are checking the second and third elements after the ith element, and if they are all the same, a match has been detected.
The problem I'm having is that points are not being added to the count variable when they should. The "things" array is meant to emulate the game board, and I've designed it so it has at least one match, which my if statements don't seem to be detecting. How do I fix it so "count" will store points?
I've never posted anything on here before, so I'm sorry for the slightly screwy formatting, but here's the code:
#include <iostream>
using namespace std;
int main()
{
int things[3][3] = {{3, 3, 3}, {2, 8, 4}, {3, 7, 2}};
int count = 0;
for (int i = 0; i <= 3; i++)
{
for (int j = 0; j <= 3; j++)
{
if (things[i] == things[i+1])
count++;
if (things[i] == things[i+2])
count++;
if (things[i] == things[i+3])
count++;
else
{
if (things[j] == things[j+1])
count++;
if (things[j] == things[j+2])
count++;
if (things[j] == things[j+3])
count++;
}
}
}
return 0;
}
3 of the same character in a row, vertically or horizontally, constitutes a match
Too code this correctly You need to first have the correct algorithm.
So this is how I would write it in pseudo code:
For every row:
- For first n-2 columns in this row
- if current match result and next 2 match results are the same : increment counter
For every column:
- For first n-2 rows in this column
- if current match result and next 2 match results are the same : increment counter

Number of Rs in a string

I have an assignment where I'm given a string S containing the letters 'R' and 'K', for example "RRRRKKKKRK".
I need to obtain the maximum number of 'R's that string could possibly hold by flipping characters i through j to their opposite. So:
for(int x = i; x < j; x++)
{
if S[x] = 'R'
{
S[X] = 'S';
}
else
{
S[X] = 'R';
}
}
However, I can only make the above call once.
So for the above example: "RRRRKKKKRK".
You would have i = 4 and j = 8 which would result in: "RRRRRRRRKR" and you would then output the number of R's in the resulting string: 9.
My code partially works, but there are some cases that it doesn't. Can anyone figure out what is missing?
Sample Input
2
RKKRK
RKKR
Sample Output
4
4
My Solution
My solution which works only for the first case, I don't know what I'm missing to complete the algorithm:
int max_R = INT_MIN;
for (int i = 0; i < s.size(); i++)
{
for (int j = i + 1; j < s.size(); j++)
{
int cnt = 0;
string t = s;
if (t[j] == 'R')
{
t[j] = 'K';
}
else
{
t[j] = 'R';
}
for (int b = 0; b < s.size(); b++)
{
if (t[b] == 'R')
{
cnt++;
if (cnt > max_R)
{
max_R = cnt;
}
}
}
}
}
cout << max_R << endl;
How about turning this into the Maximum subarray problem which has O(n) solution?
Run through the string once, giving 'K' a value of 1, and 'R' a value of -1.
E.g For 'RKRRKKKKRKK' you produce an array -> [-1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1] -> [-1, 1, -2, 4, -1, 2] (I grouped consecutive -1s and 1s to be more clear)
Apply Kadane's algorithm on the generated array. What you get from doing this is the maximum number of 'R's you can obtain from flipping 'K's.
Continuing with the example, you find that the maximum subarray is [4, -1, 2] with a sum of 5.
Now add the absolute value of the negative values outside this subarray with the sum of your maximum subarray to obtain your answer.
In our case, only -1 and -2 are negative and outside the subarray. We get |-1| + |-2| + 5 = 8
Try to carefully think about your solution. Do you understand, what it does?
First, let’s forget that the input file may contain multiple tests, so let’s get rid of the while loop. Now, we have just two for loops. The second one obviously just counts R’s in the processed string. But what does the first one do?
The answer is that the first loop flips all the letters from the second one (i.e. which has index 1) till the end of the string. We can see that in the first testcase:
RKKRK
it is indeed the optimal solution. The string turns into RRRKR and we get four R’s. But in the second case:
RKKR
the string turns into RRRK and we get three R’s. While if we flipped just the letters from 2 to 3 (i.e. indices 1 to 2) we could get RRRR which has four R’s.
So your algorithm always flips letters from index 1 to the end, but this is not always optimal. What can we do? How do we know which letters to flip? Well, there are some smart solutions, but the easiest is to just try all possible combinations!
You can flip all the letters from 0 to 1, count the number of R’s, remember it. Get back to the original string, flip letters from 0 to 2, count R’s, remember it and so on till you flip from 0 to n-1. Then you flip letters from 1 to 2, from 1 to 3, etc. And the answer is the largest value you remembered.
This is horribly inefficient, but this works. After you get more practice in solving algorithmic problems, get back to this task and try to figure out more efficient solutions. (Hint: if you consider building the optimal answer incrementally, that is by going through the string char by char and transforming the optimal solution for the substring s[0..i] into the optimal solution for s[0..i+1] you can arrive to a pretty straightforward O(n^2) algorithm. This can be enhanced to O(n), but this step is slightly more involved.)
Here is the sketch of this solution:
def solve(s):
answer = 0
for i in 0..(n-1)
for j in i..(n-1)
t = copy(s) # we will need the original string later
flip(t, i, j) # flip letters from i to j in t
c = count_R(t) # count R's in t
answer = max(answer, c)
return answer

Why Bubble Sort needs nested loops?

I am going to start the new question. I posed the question yesterday and wanted to know what's the problem in my program. The program is given below and you people pointed out that this following program does only one pass of the sorting and needs an outer loop as well. At that time I was good like OK. But again when I looked the program I got confused and need to ask Why we need Outer loop as well for the sort since only a single loop can do the sorting(In my opinion). First see program below then I present my logic at the end of the program.
#include <iostream.h>
#include <conio.h>
using namespace std;
main()
{
int number[10];
int temp = 0;
int i = 0;
cout << "Please enter any ten numbers to sort one by one: "
<< "\n";
for (i = 0; i < 10; i++)
{
cin >> number[i];
}
i = 0;
for (i = 0; i < 9; i++)
{
if (number[i] > number[i + 1])
{
temp = number[i + 1];
number[i + 1] = number[i];
number[i] = temp;
}
}
i = 0;
cout << "The sorted numbers are given below:"
<< "\n";
for (i = 0; i < 10; i++)
{
cout << number[i] << "\n";
}
getch();
}
I think the ONLY loop with the bubble condition should do the sorting. Look at the following loop of the program:
for (i=0;i<9;i++)
if(number[i]>number[i+1])
{
temp=number[i+1];
number[i+1]=number[i];
number[i]=temp;
}
Now I explain what I am thinking what this loop "should" do. It will first compare number[0] with number[1]. If the condition is satisfied it will do what is in IF statement's body. Then i will be incremented by 1(i++). Then on next iteration the values compared will be number[1] with number[2]. Then why it does not happen and the loop exits after only pass? In other words may be I'm trying to ask IF statement does not repeat itself in for loop? In my opinion it does. I'm very thankful for help and views, my question might be of small level but that is how I will progress.
Let me give you an example let's only take 3 numbers. So you input
13, 3 ,1
Now you start sorting how you did it. so it compares 13 and 3
13 > 3 so switch both of them.
now we have.
3, 13, 1
Now it'll compare as you said the next pair = 13 and 1
13 > 1 so the new order would be
3, 1, 13
now your loop is finished and you missed to compare 3 and 1
Actually the first loop only sorts the greatest number!
since only a single loop can do the sorting(In my opinion)
This is not correct. Without getting to details, a constant number of loops is not enough to sort, since sorting is Omega(nlogn) problem. Meaning, an O(1) (constant, including 1) number of loops is not enough for it - for any algorithm1,2.
Consider the input
5, 4, 3, 2, 1
a single loop of bubble sort will do:
4, 5, 3, 2, 1
4, 3, 5, 2, 1
4, 3, 2, 5, 1
4, 3, 2, 1, 5
So the algorithm will end up with the array: [ 4, 3, 2, 1, 5], which is NOT sorted.
After one loop of bubble sort, you are only guaranteed to have the last element in place (which indeed happens in the example). The second iteration will make sure the 2 last elements are in place, and the nth iteration will make sure the array is indeed sorted, resulting in n loops, which is achieved via a nested loop.
(1) The outer loop is sometimes hidden as a recursive call (quick sort is an example where it happens) - but there is still a loop.
(2) Comparisons based algorithms, to be exact.
For bubble sorting a pass simply moves the largest element to the end of array. So you need n-1 passes to get a sorted array, thats why you need other loop. Now for your code 1 pass means
if(number[0]>number[0+1])
{
temp=number[0+1];
number[0+1]=number[0];
number[0]=temp;
}
if(number[1]>number[1+1])
{
temp=number[1+1];
number[1+1]=number[1];
number[1]=temp;
}
.....6 more times
if(number[8]>number[8+1])
{
temp=number[8+1];
number[8+1]=number[8];
number[8]=temp;
}
so as you can see IF statement repeats itself, its just that after all 9 IFs the largets element moves to the end of array
This is not correct because
The algorithm gets its name from the way smaller elements "bubble" to the top of the list. (Bubble sort)
So, at the end of the first loop, we get the smallest element. So, for complete sorting, we have to keep total n loops. (where n = total size of the numbers)

How to produce a random number sequence that doesn't produce more than X consecutive elements

Ok, I really don't know how to frame the question properly because I barely have any idea how to describe what I want in one sentence and I apologize.
Let me get straight to the point and you can just skip the rest cause I just want to show that I've tried something and not coming here to ask a question on a whim.
I need an algorithm that produces 6 random numbers where it may not produce more than 2 consecutive numbers in that sequence.
example: 3 3 4 4 2 1
^FINE.
example: 3 3 3 4 4 2
^NO! NO! WRONG!
Obviously, I have no idea how to do this without tripping over myself constantly.
Is there a STL or Boost feature that can do this? Or maybe someone here knows how to concoct an algorithm for it. That would be awesome.
What I'm trying to do and what I've tried.(the part you can skip)
This is in C++. I'm trying to make a Panel de Pon/Tetris Attack/Puzzle League whatever clone for practice. The game has a 6 block row and 3 or more matching blocks will destroy the blocks. Here's a video in case you're not familiar.
When a new row comes from the bottom it must not come out with 3 horizontal matching blocks or else it will automatically disappear. Something I do not want for horizontal. Vertical is fine though.
I've tried to accomplish just that and it appears I can't get it right. When I start the game chunks of blocks are missing because it detects a match when it shouldn't. My method is more than likely heavy handed and too convoluted as you'll see.
enum BlockType {EMPTY, STAR, UP_TRIANGLE, DOWN_TRIANGLE, CIRCLE, HEART, DIAMOND};
vector<Block> BlockField::ConstructRow()
{
vector<Block> row;
int type = (rand() % 6)+1;
for (int i=0;i<6;i++)
{
row.push_back(Block(type));
type = (rand() % 6) +1;
}
// must be in order from last to first of the enumeration
RowCheck(row, diamond_match);
RowCheck(row, heart_match);
RowCheck(row, circle_match);
RowCheck(row, downtriangle_match);
RowCheck(row, uptriangle_match);
RowCheck(row, star_match);
return row;
}
void BlockField::RowCheck(vector<Block> &row, Block blockCheckArray[3])
{
vector<Block>::iterator block1 = row.begin();
vector<Block>::iterator block2 = row.begin()+1;
vector<Block>::iterator block3 = row.begin()+2;
vector<Block>::iterator block4 = row.begin()+3;
vector<Block>::iterator block5 = row.begin()+4;
vector<Block>::iterator block6 = row.begin()+5;
int bt1 = (*block1).BlockType();
int bt2 = (*block2).BlockType();
int bt3 = (*block3).BlockType();
int bt4 = (*block4).BlockType();
int type = 0;
if (equal(block1, block4, blockCheckArray))
{
type = bt1 - 1;
if (type <= 0) type = 6;
(*block1).AssignBlockType(type);
}
else if (equal(block2, block5, blockCheckArray))
{
type = bt2 - 1;
if (type <= 0) type = 6;
(*block2).AssignBlockType(type);
}
else if (equal(block3, block6, blockCheckArray))
{
type = bt3 - 1;
if (type == bt3) type--;
if (type <= 0) type = 6;
(*block3).AssignBlockType(type);
}
else if (equal(block4, row.end(), blockCheckArray))
{
type = bt4 - 1;
if (type == bt3) type--;
if (type <= 0) type = 6;
(*block4).AssignBlockType(type);
}
}
Sigh, I'm not sure if it helps to show this...At least it shows that I've tried something.
Basically, I construct the row by assigning random block types, described by the BlockType enum, to a Block object's constructor(a Block object has blockType and a position).
Then I use a RowCheck function to see if there's 3 consecutive blockTypes in one row and I have do this for all block types. The *_match variables are arrays of 3 Block objects with the same block type. If I do find that there are 3 consecutive block types then, I just simply subtract the first value by one. However if I do that I might end up inadvertently producing another 3 match so I just make sure the block types are going in order from greatest to least.
Ok, it's crappy, it's convoluted and it doesn't work! That's why I need your help.
It should suffice to keep record of the previous two values, and loop when the newly generated one matches both of the previous values.
For an arbitrary run length, it would make sense to size a history buffer on the fly and do the comparisons in a loop as well. But this should be close to matching your requirements.
int type, type_old, type_older;
type_older = (rand() % 6)+1;
row.push_back(Block(type_older));
type_old = (rand() % 6)+1;
row.push_back(Block(type_old));
for (int i=2; i<6; i++)
{
type = (rand() % 6) +1;
while ((type == type_old) && (type == type_older)) {
type = (rand() % 6) +1;
}
row.push_back(Block(type));
type_older = type_old;
type_old = type;
}
Idea no 1.
while(sequence doesn't satisfy you)
generate a new sequence
Idea no 2.
Precalculate all allowable sequences (there are about ~250K of them)
randomly choose an index and take that element.
The second idea requires much memory, but is fast. The first one isn't slow either because there is a veeery little probability that your while loop will iterate more than once or twice. HTH
Most solutions seen so far involve a potentially infinite loop. May I suggest a different approch?
// generates a random number between 1 and 6
// but never the same number three times in a row
int dice()
{
static int a = -2;
static int b = -1;
int c;
if (a != b)
{
// last two were different, pick any of the 6 numbers
c = rand() % 6 + 1;
}
else
{
// last two were equal, so we need to choose from 5 numbers only
c = rand() % 5;
// prevent the same number from being generated again
if (c == b) c = 6;
}
a = b;
b = c;
return c;
}
The interesting part is the else block. If the last two numbers were equal, there is only 5 different numbers to choose from, so I use rand() % 5 instead of rand() % 6. This call could still produce the same number, and it also cannot produce the 6, so I simply map that number to 6.
Solution with simple do-while loop (good enough for most cases):
vector<Block> row;
int type = (rand() % 6) + 1, new_type;
int repetition = 0;
for (int i = 0; i < 6; i++)
{
row.push_back(Block(type));
do {
new_type = (rand() % 6) + 1;
} while (repetition == MAX_REPETITION && new_type == type);
repetition = new_type == type ? repetition + 1 : 0;
type = new_type;
}
Solution without loop (for those who dislike non-deterministic nature of previous solution):
vector<Block> row;
int type = (rand() % 6) + 1, new_type;
int repetition = 0;
for (int i = 0; i < 6; i++)
{
row.push_back(Block(type));
if (repetition != MAX_REPETITION)
new_type = (rand() % 6) + 1;
else
{
new_type = (rand() % 5) + 1;
if (new_type >= type)
new_type++;
}
repetition = new_type == type ? repetition + 1 : 0;
type = new_type;
}
In both solutions MAX_REPETITION is equal to 1 for your case.
How about initializing a six element array to [1, 2, 3, 4, 5, 6] and randomly interchanging them for awhile? That is guaranteed to have no duplicates.
Lots of answers say "once you detect Xs in a row, recalculate the last one until you don't get an X".... In practice for a game like this, that approach is millions of times faster than you need for "real-time" human interaction, so just do it!
But, you're obviously uncomfortable with it and looking for something more inherently "bounded" and elegant. So, given you're generating numbers from 1..6, when you detect 2 Xs you already know the next one could be a duplicate, so there are only 5 valid values: generate a random number from 1 to 5, and if it's >= X, increment it by one more.
That works a bit like this:
1..6 -> 3
1..6 -> 3
"oh no, we've got two 3s in a row"
1..5 -> ?
< "X"/3 i.e. 1, 2 use as is
>= "X" 3, 4, 5, add 1 to produce 4, 5 or 6.
Then you know the last two elements differ... the latter would take up the first spot when you resume checking for 2 elements in a row....
vector<BlockType> constructRow()
{
vector<BlockType> row;
row.push_back(STAR); row.push_back(STAR);
row.push_back(UP_TRIANGLE); row.push_back(UP_TRIANGLE);
row.push_back(DOWN_TRIANGLE); row.push_back(DOWN_TRIANGLE);
row.push_back(CIRCLE); row.push_back(CIRCLE);
row.push_back(HEART); row.push_back(HEART);
row.push_back(DIAMOND); row.push_back(DIAMOND);
do
{
random_shuffle(row.begin(), row.end());
}while(rowCheckFails(row));
return row;
}
The idea is to use random_shuffle() here. You need to implement rowCheckFails() that satisfies the requirement.
EDIT
I may not understand your requirement properly. That's why I've put 2 of each block type in the row. You may need to put more.
I think you would be better served to hide your random number generation behind a method or function. It could be a method or function that returns three random numbers at once, making sure that there are at least two distinct numbers in your output. It could also be a stream generator that makes sure that it never outputs three identical numbers in a row.
int[] get_random() {
int[] ret;
ret[0] = rand() % 6 + 1;
ret[1] = rand() % 6 + 1;
ret[2] = rand() % 6 + 1;
if (ret[0] == ret[1] && ret[1] == ret[2]) {
int replacement;
do {
replacement = rand() % 6 + 1;
} while (replacement == ret[0]);
ret[rand() % 3] = replacement;
}
return ret;
}
If you wanted six random numbers (it's a little difficult for me to tell, and the video was just baffling :) then it'll be a little more effort to generate the if condition:
for (int i=0; i<4; i++) {
if (ret[i] == ret[i+1] && ret[i+1] == ret[i+2])
/* three in a row */
If you always change ret[1] (the middle of the three) you'll never have three-in-a-row as a result of the change, but the output won't be random either: X Y X will happen more often than X X Y because it can happen by random chance and by being forced in the event of X X X.
First some comments on the above solutions.
There is nothing wrong with the techniques that involve rejecting a random value if it isn't satisfactory. This is an example of rejection sampling, a widely used technique. For example, several algorithms for generating a random gaussian involve rejection sampling. One, the polar rejection method, involves repeatedly drawing a pair of numbers from U(-1,1) until both are non-zero and do not lie outside the unit circle. This throws out over 21% of the pairs. After finding a satisfactory pair, a simple transformation yields a pair of gaussian deviates. (The polar rejection method is now falling out of favor, being replaced by the ziggurat algorithm. That too uses a rejection sampling.)
There is something very much wrong with rand() % 6. Don't do this. Ever. The low order bits from a random number generator, even a good random number generator, are not quite as "random" as are the high order bits.
There is something very much wrong with rand(), period. Most compiler writers apparently don't know beans about producing random numbers. Don't use rand().
Now a solution that uses the Boost random number library:
vector<Block> BlockField::ConstructRow(
unsigned int max_run) // Maximum number of consecutive duplicates allowed
{
// The Mersenne Twister produces high quality random numbers ...
boost::mt19937 rng;
// ... but we want numbers between 1 and 6 ...
boost::uniform_int<> six(1,6);
// ... so we need to glue the rng to our desired output.
boost::variate_generator<boost::mt19937&, boost::uniform_int<> >
roll_die(rng, six);
vector<Block> row;
int prev = 0;
int run_length = 0;
for (int ii=0; ii<6; ++ii) {
int next;
do {
next = roll_die();
run_length = (next == prev) ? run_length+1 : 0;
} while (run_length > max_run);
row.push_back(Block(next));
prev = next;
}
return row;
}
I know that this already has many answers, but a thought just occurred to me. You could have 7 arrays, one with all 6 digits, and one for each missing a given digit. Like this:
int v[7][6] = {
{1, 2, 3, 4, 5, 6 },
{2, 3, 4, 5, 6, 0 }, // zeros in here to make the code simpler,
{1, 3, 4, 5, 6, 0 }, // they are never used
{1, 2, 4, 5, 6, 0 },
{1, 2, 3, 5, 6, 0 },
{1, 2, 3, 4, 6, 0 },
{1, 2, 3, 4, 5, 0 }
};
Then you can have a 2 level history. Finally to generate a number, if your match history is less than the max, shuffle v[0] and take v[0][0]. Otherwise, shuffle the first 5 values from v[n] and take v[n][0]. Something like this:
#include <algorithm>
int generate() {
static int prev = -1;
static int repeat_count = 1;
static int v[7][6] = {
{1, 2, 3, 4, 5, 6 },
{2, 3, 4, 5, 6, 0 }, // zeros in here to make the code simpler,
{1, 3, 4, 5, 6, 0 }, // they are never used
{1, 2, 4, 5, 6, 0 },
{1, 2, 3, 5, 6, 0 },
{1, 2, 3, 4, 6, 0 },
{1, 2, 3, 4, 5, 0 }
};
int r;
if(repeat_count < 2) {
std::random_shuffle(v[0], v[0] + 6);
r = v[0][0];
} else {
std::random_shuffle(v[prev], v[prev] + 5);
r = v[prev][0];
}
if(r == prev) {
++repeat_count;
} else {
repeat_count = 1;
}
prev = r;
return r;
}
This should result in good randomness (not reliant of rand() % N), no infinite loops, and should be fairly efficient given the small amount of numbers that we are shuffling each time.
Note, due to the use of statics, this is not thread safe, that may be fine for your usages, if it is not, then you probably want to wrap this up in an object, each with its own state.