I am attempting to decipher this code: https://github.com/tangentforks/TwoPlusTwoHandEvaluator/blob/master/generate_table.cpp
The code is used to generate a massive lookup table that is then used to look up hand ranks of 7 card hands. I am having difficulty deciphering exactly why the main method is written the way it is. From what I can make of it, the first for loop bruteforces every single combination of cards, substituting the appropriate suit abstractions when necessary, but I am not sure why that is repeated in the next section, or why it is scaled by a factor of 53 and then added 53 to. Could anyone shed any light on this?
This is the code in question::
printf("\nGetting Card IDs!\n");
// Jmd: Okay, this loop is going to fill up the IDs[] array which has
// 612,967 slots. as this loops through and find new combinations it
// adds them to the end. I need this list to be stable when I set the
// handranks (next set) (I do the insertion sort on new IDs these)
// so I had to get the IDs first and then set the handranks
for (IDnum = 0; IDs[IDnum] || IDnum == 0; IDnum++) {
// start at 1 so I have a zero catching entry (just in case)
for (card = 1; card < 53; card++) {
// the ids above contain cards upto the current card. Now add a new card
ID = MakeID(IDs[IDnum], card); // get the new ID for it
// and save it in the list if I am not on the 7th card
if (numcards < 7) holdid = SaveID(ID);
}
printf("\rID - %d", IDnum); // show progress -- this counts up to 612976
}
// main()
printf("\nSetting HandRanks!\n");
// this is as above, but will not add anything to the ID list, so it is stable
for (IDnum = 0; IDs[IDnum] || IDnum == 0; IDnum++) {
// start at 1 so I have a zero catching entry (just in case)
for (card = 1; card < 53; card++) {
ID = MakeID(IDs[IDnum], card);
if (numcards < 7) {
// when in the index mode (< 7 cards) get the id to save
IDslot = SaveID(ID) * 53 + 53;
} else {
// if I am at the 7th card, get the equivalence class ("hand rank") to save
IDslot = DoEval(ID);
}
maxHR = IDnum * 53 + card + 53; // find where to put it
HR[maxHR] = IDslot; // and save the pointer to the next card or the handrank
}
if (numcards == 6 || numcards == 7) {
// an extra, If you want to know what the handrank when there is 5 or 6 cards
// you can just do HR[u3] or HR[u4] from below code for Handrank of the 5 or
// 6 card hand
// this puts the above handrank into the array
HR[IDnum * 53 + 53] = DoEval(IDs[IDnum]);
}
printf("\rID - %d", IDnum); // show the progress -- counts to 612976 again
}
Doing the same currently. It is shifted by 53 because there are 52 cards. Once you point to an invalid state, you transition to 0. From there, any card that you pick must still result in an invalid state, so the first 53 entries 0 + 52 ranks point to 0. The first meaningful entry comes at 53..(53+53).
Try to understand the concept first. The table is a huge directed graph, where each node has 52 childnodes and one „evaluate-current-handrank-node“ at index 0. poker-ai.org and the original thread provide lots of useful information. Also look at CactusKevs idea to obtain handrank-order on cards by using prime numbers. Genius. It all goes into this.
Related
So, within this particular program , I have nodes stored inside an vector of nodes. These nodes contain a user input int ID, int age, and string Name.
This vector is meant to act as a binary search tree that is organized by ID number, and is not worried about being balanced.
Currently I am attempting to write an insert function in which, after the creation of a new node of user input values, it compares it against the root, which is stored at index 1 of the vector.
If it is smaller than the ID at the root, then it is placed into position (root*2). If it is larger than the root, then it is placed into position (root*2 + 1)
However, I am having an extreme amount of difficulty placing into the vector if these two spots are already being taken up by another node.
Is there any way that I could create a loop that would check against the value in the filled spot, and continue looping until it finds an empty spot?
A current example that I'm working with
ID 50, ID 100, ID 75
ID 50 is in position 1.
ID 100 is inserted in position 3, since it is empty (2*1)
ID 75 is attempted to be inserted, but position 3 is filled, so then I need to check it against ID in position 3 using the same algorithm. In this case, since 75 is lower than 100, it would be placed in position 4.
I'm completely stumped as to how to to implement such an algorithm into a loop
Any help would be much appreciated.
Here is my code.
void BST::insert()
{
int ID;
int AGE;
string NAME;
bool done = false;
int root = 1;
cout << "Please enter the ID number, age and name" << endl;
do
{
cin >> ID >> AGE >> NAME;
} while (ID <= 0);
Node *tree = new Node(ID, AGE, NAME);
if (!binaryTree.empty())
{
do
{
Node &n = binaryTree.at(root);
if (n.ID == 0)
{
n.ID = ID;
n.age = AGE;
n.name = NAME;
done = true;
break;
}
else if (ID < n.ID)
{
root = 2 * root;
}
else
{
root = 2 * root + 1;
}
} while (done = true);
}
if (binaryTree.empty())
{
binaryTree.push_back(*tree);
}
start();
}
I am still very new to this language, so any help would be much appreciated!
EDIT:
I fixed some discrepancies and added the code that was suggested, however, now an out_of_bounds exception is being thrown.
Thanks!
My question is essentially, how would I turn such an alogrithm into a
while loop/do while loop, etc
Here's an answer that uses pseudocode. You should re-write the loop on your own with a different constuct such as a while, do while or for loop.
But first, some problems with your code.
You are comparing Node.ID (an int) to NULL to check if a location in the vector is "empty". NULL has the same semantics as 0 so I am going to assume that no IDs will be 0. Your code doesn't actually check this, so you may want to handle that case and/or address these design issues.
I have no idea why you are dynamically allocating memory with new if you are using a vector to store your nodes. This is likely going to lead to a memory leak.
I am assuming you are handling creating a vector of the appropriate size in code you have not posted. If you don't do this, then your code will crash when at throws an exception when root is outside the bounds of the vector.
If it is smaller than the ID at the root, then it is placed into
position (root*2). If it is larger than the root, then it is placed
into position (root*2 + 1)
What if the ID is equal to the ID at the root?
And finally, the code with the goto loop.
int root = 1;
BEGIN LOOP
Node &n = binaryTree.at(root);
if (n.ID == 0)
{
n.ID = ID;
n.age = AGE;
n.name = NAME;
BREAK OUT OF LOOP
}
else if (ID < n.ID)
{
root = 2*root;
}
else
{
root = 2*root + 1;
}
REPEAT
ArrayBag foundBag;
int z;
z = getCurrentSize(); // tell you have many items exit in the bag
for (int i = 0; i < z; i++ )
{
int cur = items[i]; //cur is use to hold each number in the vector and items is the first list of number.
bool found = false; // start as false so it doesnt trigger the true right away
for (int j = 0; j < foundBag.getCurrentSize(); j++) // this loop check the number currently inside cur agianst everything in the foundbag at the moment
{
if (foundBag.items[i] = cur)
{
found == true; // << it didnt detect that it have found the number. I think the problem is here
}
}
if (found == true)
{
// do nothing if found since number is already in the foundbag
}
else if (found != true)
{
foundBag.add(cur); // if number is not found in the foundBag add it to the found bag.
}
}
So what I m trying to do is comparing value from an existing list to a new empty one that is called foundBag in this case. So basically it suppose to get value from the first bag and then check if that number exit in the first bag or not then it will add that number to the foundBag if it did not find it. If it already found the number it will do nothing and move to the next element in the first bag.
say the first bag have number 3 4 5 7 5 8 it should add everything from 3 4 5 7 then do nothing when it get to the second 5 then add 8 to the foundBag.
at the end foundBag should contain: 3 4 5 7 8
The problem is it doesnt seem to correctly detect that the number is already in the foundBag so it add everything.
I been using the step-over function in visual studio to look at each step but I couldnt figure out why the bool still go to false when it found the identical number.
Im not very strong in english so if this doesnt make sense please ask for more explanation
Thank you
It looks like you have your = and == mixed up.
if (foundBag.items[j] == cur) // Use == here for comparison
{
found = true; // Use = here for assignment
}
By the way, if all you're doing is looking for an element in a collection, prefer an algorithm from the standard library:
auto result = std::count(std::begin(foundBag.items), std::end(foundBag.items), cur);
if (result == std::end(foundBag.items)) {
// Not found; Add it
foundBag.add(cur);
}
Recently, I've began learning C++ in college and was asked to make a looping sequence of "*" with the sequence going like this:
*
***
*****
*******
*********
*********
*******
*****
***
*
[continues indefinitely until it goes x lines, where x is specified at the start]
How I did it if you need a visualisation:
#include<iostream>
#include<windows.h>
using namespace std;
int main() {
int hFar=0; //Variable that will be used to find out how many parts into the sequence the user would like to travel.
unsigned long int fibSequenceA = 0; //Unsigned doesn't overflow as easilly. This is the first value of the fibunacci sequence, it's defined as 0 to start.
unsigned long int fibSequenceB = 1; // Second Value of fibbunacci sequence. Defined at 1 to start.
int sPart = 1;//Used for the * sequence, it is the part of the sequence that the loop is on. It changes dynamically by either +2 or -2 every loop.
int cValue = 0;// also for the * sequence, it is the current number of * typed.
int sDirection = 0; // used to change from subtracting 2, and adding 2.
int redo = 1; // used to ensure that every 9 and every 1 the sequence repeats that number a second time. Starts at one because the sequence starts with only 1 single * rather then 2 *.
cout << "How far into the second sequence would you like to travel?" << endl; //Requests how far into the * sequence you'd like to go.
cin >> hFar; //inputs answer into variable.
for(int i = 0; i < hFar; i++ ) {//begins for statement. Notice there's no hfar/2. There will only be 1 output per line now.
while(cValue < sPart) { //Basic while loop to input the ammount of * on the current line. Works by adding a * depending on what part of the sequence it is.
cout << "*"; //self explainitory.
cValue++; //raises the cValue in order to keep track of the current number of *. Also prevents infinite loop.
}
if(sPart == 9 && redo == 0) { //Checks if the sequence part is 9, meaning that the value begins to reduce to 1 again. But first, it must repeat 9 to keep with the sequence.
sDirection = 3; //sets the direction to 3 to make sure that the value of sPart stays at 9, instead of reducing by 2.
redo = 1; //resets the redo.
cValue = 8; //changes the value of the current number of 8. Not sure if this is important, It gets done again later to make sure anyway.
sPart = 9; //Changes the sPart to 9, the needed number of *. Also redone later, but to make sure, I kept this here.
}
else if(sPart == 9 && redo == 1) { // if the sequence has already redone the 9th *
sDirection = 1; //sets the direction to 1; The sequence will reverse.
redo = 0; //returns redo to 0 to ensure that next time it reaches 1, it repeats the 1 * again.
}
else if(sPart == 1 && redo == 0) { //when the value reaches one for the second time, it needs to repeat that value.
sDirection = 3; //sets the direction to 3 again to stop the change.
redo = 1; //resets the redo.
cValue = 0;//also might be redundant.
}
else if(sPart == 1 && redo == 1) { // stops the duplicate number of *
sDirection = 0; //sets the direction to +2 again.
redo = 0;//resets the redo.
}
Sleep(50);
cout << endl; //adds a new line. This ensures that we get a new line after every part rather then 900 * on one line.
if(sDirection == 0) { //if the direction is positive.
sPart += 2; //adds 2 to the spart to keep with the sequence.
cValue = 0; //resets the cValue to 0 so the while statement works again.
}
else if(sDirection == 1) { //if the direction is negative
sPart -=2; //subtracts 2 from the spart to keep with the sequence.
cValue = 0; //resets the cValue to keep the while statement working.
}
else if(sDirection = 3) { //if the change is
//Could have been done differently. Could have just set the values to themselves, but it wasn't working. not sure why.
if(sPart == 9){ //if the spart is currently 9.
sPart = 9; //keeps it at 9.
cValue = 0; //resets the cValue.
}
else if(sPart == 1){ //if the spart is currently 1
sPart = 1; //keeps it at one.
cValue = 0; //resets the cValue.
}
}
}
return 1;//ends the code.
}
[Sorry about all the comments, I'm trying to make sure I understand what I'm doing, like I said, I'm learning :)]
While fooling around with the loops, I ended up putting the Sleep() function in, so that it produced a wave effect when generating the sequence. This got me thinking, and I wanted to know if it would be possible to make the command prompt act like a makeshift volume visualizer. (The more "*" the higher the volume at that point in time).
So, when playing a song on my computer, the program would find the total output to the speaker, and put a number of "*" that correlate to that volume, and would continue this until the program ends, producing (hopefully) an interesting effect. (if you're confused, play a song on your computer, right click on the speaker icon on the task bar, and click open volume mixer, and look at the volume levels change, this is the type of effect that I'm looking for)
Would this be possible? I've been googling the issue, (found things like This and I've found a number of ways to find out the current MASTER volume, and change that, But I'm looking for more of the actual volume that one hears, not the maximum volume that my speakers can output.
Here's somewhat of what I'm looking to do.
int sPart = x; //x = the current output of the speaker
int cValue = 0 //the current number of "*" output
while([somecondition I'm not sure when i want the sequence to stop yet]) {
while(cValue < sPart) {
cout << "*";
cValue++;
}
cout << endl; //ends the current line, making room for the next value of the volume.
Sleep(50); //waits 50ms before finding the next volume value.
sPart = [current speaker value]; //finds the value of the speaker again.
cValue = 0; //resetting the number of "*" back to zero.
}
//I just reused the variables from my original code.
Would this be possible? If so, would a beginner be capable of this? Again, If so, how would it be done?
I've got code which needs to find at what points in time a laser has been fired. The laser is indicated by a DC of above 500 on the dataset, and comes in bulks of 3 lasers at a time, in rather quick, but not entirely deterministic, time gaps.
The code I am using right now:
//std::vector<short>& laserData; this one comes from the function call, this is the definition
int count = 0;
for(unsigned int index = 0; index < laserData.size(); ++index) {
if(laserData.at(index) > 500) {
times.push_back(index);
count = (count + 1)%3;
if(count == 0) {
int dif1 = times.at(times.size()-1) - times.at(times.size()-2);
int dif2 = times.at(times.size()-1) - times.at(times.size()-3);
if(dif1 > 60000 || dif2 > 60000) {
times.erase(times.begin() + times.size() - 2);
times.erase(times.begin() + times.size() - 2);
count = 1;
}
}
switch(count) {
case 0: index += 90000;
default: index += 2000;
}
}
}
I can't be entirely sure that all 3 laser impulses always happen, and if they don't, the complete set of those 1 or 2 laser impulses needs to be removed.
The dataset is 130,000,000 samples long, and I get about 3300 laser impulses in total, so that works fine, its just darned slow. It takes about 45 seconds to parse that vector, and I wonder if there is a faster way to do that.
First: Unless you intended the switch statement to fall-through, add in a break:
switch(count)
{
case 0:
index += 90000;
break;
default:
index += 2000;
}
Ok. now we have a potential error out of the way, we can look at speeding up your code.
The first thing to do is to eliminate as much of the vector resizing as possible.
you said there were about 3300 laser pulses in total. Lets add ~10% margin of error to that and resize the vector of pulses in advance:
times.reserve(3600);
Now the vector should not need to be resized multiple times. If there are more, we should only have the vector realovating once.
Next, we want to get rid of the times.erase() function calls.
To do this, we cache the three most recent values separately, and only push them into the vector once they have been validified:
const int pulse_interval = 2000;
const int burst_interval = 90000;
int cache[3];
times.reserve(3600);
for(unsigned int index = 0; index < laserData.size(); ++index)
{
if(laserData[index] > 500)
{
//this next if block acts as our guard clause
if (count > 0)
{
diff = index - cache[count-1];
if (diff > 60000)
{
count = 1;
cache[0]=index;
index+= pulse_interval;
continue;
// if gap between pulses is too big reset and start again, setting most recent value to first of next sequence.
}
}
//now we actually store data in the cache and if needed add to the vector. No invalid data (not part of a three burst set) should reach here due to guard
cache[count]=index;
if (count == 2)
{
for (int i=0; i<3; i++)
{times.push_back(cache[i]);}
count = 0;
index += burst_interval;
}
else
{
count++;
index += pulse_interval;
}
//updating count at the end is easier to follow
//goes to 0 after 3rd pulse detected
}
}
This removes vector access with invalid data and should speed up the code as much as a quick answer here can do.
edit: added in your index skipping parameters. If I got the logic wrong, let me know. In this case, the switch isnt needed as the logic could be encapsulated in the existing logic from the algorithm.
If you can't turn optimisation on, then you can try unrolling the push_back loop. Cache array can be reduced to two cells, and storing of the index can be moved to the else (for the third value just push_back(index);
This removes the loop overhead and one assignment for each time you find a full burst. Your compiler would handle this normally.
If still slow. then you need to profile. Make sure that your index skips are of the right size (too small means you search too much, but too large and you risk loosing valid data)
You could also do this in parallel as a commenter suggested. You could do this splitting the search space into a number of sections and spawning a thread for each section.
Im positioning sprites in a sliding puzzle game, but I have trouble to randomise the tile position
How can I check if a random move (arc4random) has already been made, and to ignore previous move in the randomisation process?
the tiles do randomise/reshuffle, but sometimes the repeat the random move made
eg tile 23 slides to tile 24 position and back several times, counting as a random move
(which means the board doesn't shuffle properly)
int count = 0;
int moveArray[5];
int GameTile;
int EmptySq;
//loop through the board and find the empty square
for (GameTile = 0; GameTile <25; ++GameTile) {
if (boardOcc[GameTile]== kEMPTY) {
EmptySq = GameTile;
break;
}
}
int RowEmpty = RowNumber[GameTile];
int colEmpty = ColHeight[GameTile];
if (RowEmpty <4) moveArray[count++] = (GameTile +5);//works out the current possible move
if (RowEmpty >0) moveArray[count++] = (GameTile -5);//to avoid unsolvable puzzles
if (colEmpty <4) moveArray[count++] = (GameTile +1);
if (colEmpty >0) moveArray[count++] = (GameTile -1);
int RandomIndex = arc4random()%count;
int RandomFrom = moveArray[RandomIndex];
boardOcc[EmptySq] = boardOcc[RandomFrom];
boardOcc[RandomFrom] = kEMPTY;
There are few - if not many possibilities.
One possibility would be to create a stack-like buffer array, which would contain, let's say 10 steps. (Stack - goes in from one end, goes out from other end)
For example:
NSMutableArray *_buffer = [NSMutableArray new];
So - game starts, buffer array is empty. You generate first random move, and also insert it into the buffer array:
[_buffer insertObject:[NSNumber numberWithInt:RandomIndex] atIndex:0];
Then run a check if our array contains more that 10 elements and remove last one if so:
if([_buffer count] > 10)
{
[_buffer removeObjectAtIndex:10];
}
We need to remove only one item, as we only add one object each time.
And then we add the checking, so that next 'RandomIndex' would be something else than previous 10 indexes. We set 'RandomIndex' to some neutral value (-1) and then launch a while loop (to set 'RandomIndex' to some random value, and second time check if '_buffer' contains such value. If it contains, it will regenerate 'RandomIndex' and check again.. it could do so indefinitely, but if the 'count' is a much bigger number, then it will take 2-3 while loops, tops. No worries.
int RandomIndex = -1;
while(RandomIndex == -1 || [_buffer containsObject:[NSNumber numberWithInt:RandomIndex]])
{
RandomIndex = arc4random()%count;
}
But You could add some safety, to allow it to break out of the loop if after, say, 5 cycles: (But then it will keep the repeating value..)
int RandomIndex = -1;
int safetyCounter = 0;
while(RandomIndex == -1 || [_buffer containsObject:[NSNumber numberWithInt:RandomIndex]])
{
RandomIndex = arc4random()%count;
if(safetyCounter == 5)
{
break;
}
safetyCounter++;
}
You could also decrease the buffer size to - 3 or five, then it will work perfectly in 99.9999999% cases or even 100%. Just to disable that case, when randomly it picks the same number each second time as You described. Anyways - no worries.
But still. Let's discuss another - a bit more advanced and safer way.
Other possibility would be to create two separate buffers. One - as in previous example - would be used to store last 10 values, and second would have all the other possible unique moves.
So:
NSMutableArray *_buffer = [NSMutableArray new];
NSMutableArray *_allValues = [NSMutableArray new];
At the beginning '_buffer' is empty, but for '_allValues', we add all possible moves:
for(int i = 0; i < count; i++)
{
[_allValues addObject:[NSNumber numberWithInt:i]];
}
and again - when we calculate a random value - we add it to the '_buffer' AND remove from '_allValues'
[_buffer insertObject:[NSNumber numberWithInt:RandomIndex] atIndex:0];
[_allValues removeObject:[NSNumber numberWithInt:RandomIndex]];
after that - we again check if _buffer is not larger than 10. If Yes, we remove last object, and add back to _allValues:
if([_buffer count] > 10)
{
[_allValues addObject:[_buffer objectAtIndex:10]];
[_buffer removeObjectAtIndex:10];
}
And most importantly - we calculate 'RandomIndex from the count of _allValues and take corresponding object's intValue:
RandomIndex = [[_allValues objectAtIndex:(arc4random()%[_allValues count])] intValue];
Thus - we don't need any safety checking, because in this way, each time calculated value will be unique for the last 10 moves.
Hope it helps.. happy coding!