Enumeration class and array declaration - c++

I'm doing a C++ tutorial that teaches the language through game development.
Within this tutorial there's a piece of code which I do not understand how it works.
First an enum class is declared and an array is initialized:
enum class side {LEFT,RIGHT, NONE};
side branchPositions[NUM_BRANCHES]; / which is a const variable and has the value of 6
Within the main function I have this code:
for (int i = 0; i < NUM_BRANCHES; i++)
{
float height = i * 150;
if (branchPositions[i] == side::LEFT)
{
branches[i].setPosition(610, height);
branches[i].setRotation(180);
}
else if (branchPositions[i] == side::RIGHT)
{
branches[i].setPosition(1330, height);
branches[i].setRotation(0);
}
else
{
branches[i].setPosition(3000, height);
}
}
What it does is, it updates the position of the branch sprites.
When running the code, I get the following result:
After the following function is added and called
void updateBranches(int seed)
{
for (int j = NUM_BRANCHES - 1; j > 0; j--)
{
branchPositions[j] = branchPositions[j - 1];
}
srand((int)time(0) + seed);
int r = (rand() % 2);
switch (r)
{
case 0:
branchPositions[0] = side::LEFT;
break;
case 1:
branchPositions[0] = side::RIGHT;
break;
default:
branchPositions[0] = side::NONE;
break;
}
}
the branches get distributed randomly, like so:
Now, I do not get why this is.
I do understand why the branch at position 0 is either left, right or not visible due to the switch statement. But I don't understand how the for loop in the function interacts with the array and why this leads to the behavior shown in image 2.
I also do not understand what values are stored in the array and what the connection with the enum class is.
Could somebody please clarify ? Thanks

The first for loop in updateBranches will move the branches up the array, so that the branch that was in branch[4] will be stored in branch[5], all the way down to storing branch[0] into branch[1]. Then branch[0] is replaced with a new randomly chosen branch. Except that srand should only be called once, and not every time the function is called. And it should use % 3, not % 2, since % 2 will only give you values of 0 or 1.

Related

C++ Minesweeper checking adjacent squares and adding hints [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
So, I have a pretty good idea of how to implement the majority of the program. However, I am having a hard time coming up with an algorithm to add the hints of array locations adjacent to mines. The real trouble I am seeing is that the edge cases almost make it like you have two functions to deal with it (I have 20 line max on all functions). I know that from the position of the mine we want a loop to check row - 1 to row +1 and col -1 to col +1, but is it possible to do this in one function with the code I have for the game? If so, some advice would be great!
EDIT!
SO I think I have come up with the algorithm that works for all cases, but it is outputting bad info. I am pretty sure it is due to improper casting, but I am unable to see what's wrong.
Here are the two functions I wrote to add the hints:
void add_hints_chk(char ** game_board, int cur_row, int cur_col, int
rows, int cols)
{
int row_start = 0, row_end = 0, col_start = 0, col_end = 0;
if (cur_row - 1 < 0)
{
//Top edge case
row_start = 0;
}
else
{
row_start = cur_row - 1;
}
if (cur_row + 1 > rows - 1)
{
//bottom edge case
row_end = rows - 1;
}
else
{
row_end = cur_row + 1;
}
if (cur_col - 1 < 0)
{
//Left edge case
col_start = 0;
}
else
{
col_start = cur_col - 1;
}
if (cur_col - 1 > cols - 1)
{
//Right edge case
col_end = cols - 1;
}
else
{
col_end = cur_col + 1;
}
add_hints(game_board, row_start, row_end, col_start, col_end);
}
void add_hints(char **board, int row_start, int row_end, int col_start,
int col_end)
{
int tmp_int = 0;
for (int i = row_start; i <= row_end; i++)
{
for (int j = col_start; j <= col_end; j++)
{
if (board[i][j] != '*')
{
if (board[i][j] == ' ')
{
tmp_int = 1;
board[i][j] = (char)tmp_int;
}
else
{
tmp_int = (int)board[i][j];
tmp_int++;
board[i][j] += (char)tmp_int;
}
}
}
}
}
So, when I print the array, I get the little box with a q-mark in it. Am I converting tmp_int back to a char incorrectly?
There are different strategies to handle this. One simple strategy is creating a larger grid (add one line on each side) that is initialized with no bombs; make the board a view that hides the borders. With this strategy you know that you can step out of the game board without causing issues (since the data structure has an additional row).
Alternatively you can test whether the coordinates are within the valid range before calling the function that tests, or as the first step within that function.
Also you can consider precalculating the values for all of the map, whenever you add a bomb to the board during the pre-game phase, increment the counter of bombs in the vicinity for all of the surrounding positions. You can use either of the above approaches to handle the border conditions.
For any cell, C, there are 8 possible locations to check:
# # #
# C #
# # #
Before extracting data from the array, each outer location must be boundary checked.
You may be able to generalize, for example, if the value (column - 1) is out of bounds, you don't need to check 3 locations.
In your case, I would go with the brute force method and check each outer cell for boundary before accessing it. If profiling identifies this as the primary bottleneck, the come back and optimize it. Otherwise move on.
Edit 1: Being blunt
int C_left = C_column - 1;
int C_right = C_column + 1;
if (C_left >= 0)
{
// The left column can be accessed.
}
if (C_right < MAXIMUM_COLUMNS)
{
// The right columns can be accessed.
}
// Similarly for the rows.

Tallest tower with stacked boxes in the given order

Given N boxes. How can i find the tallest tower made with them in the given order ? (Given order means that the first box must be at the base of the tower and so on). All boxes must be used to make a valid tower.
It is possible to rotate the box on any axis in a way that any of its 6 faces gets parallel to the ground, however the perimeter of such face must be completely restrained inside the perimeter of the superior face of the box below it. In the case of the first box it is possible to choose any face, because the ground is big enough.
To solve this problem i've tried the following:
- Firstly the code generates the rotations for each rectangle (just a permutation of the dimensions)
- secondly constructing a dynamic programming solution for each box and each possible rotation
- finally search for the highest tower made (in the dp table)
But my algorithm is taking wrong answer in unknown test cases. What is wrong with it ? Dynamic programming is the best approach to solve this problem ?
Here is my code:
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstring>
struct rectangle{
int coords[3];
rectangle(){ coords[0] = coords[1] = coords[2] = 0; }
rectangle(int a, int b, int c){coords[0] = a; coords[1] = b; coords[2] = c; }
};
bool canStack(rectangle &current_rectangle, rectangle &last_rectangle){
for (int i = 0; i < 2; ++i)
if(current_rectangle.coords[i] > last_rectangle.coords[i])
return false;
return true;
}
//six is the number of rotations for each rectangle
int dp(std::vector< std::vector<rectangle> > &v){
int memoization[6][v.size()];
memset(memoization, -1, sizeof(memoization));
//all rotations of the first rectangle can be used
for (int i = 0; i < 6; ++i) {
memoization[i][0] = v[0][i].coords[2];
}
//for each rectangle
for (int i = 1; i < v.size(); ++i) {
//for each possible permutation of the current rectangle
for (int j = 0; j < 6; ++j) {
//for each permutation of the previous rectangle
for (int k = 0; k < 6; ++k) {
rectangle &prev = v[i - 1][k];
rectangle &curr = v[i][j];
//is possible to put the current rectangle with the previous rectangle ?
if( canStack(curr, prev) ) {
memoization[j][i] = std::max(memoization[j][i], curr.coords[2] + memoization[k][i-1]);
}
}
}
}
//what is the best solution ?
int ret = -1;
for (int i = 0; i < 6; ++i) {
ret = std::max(memoization[i][v.size()-1], ret);
}
return ret;
}
int main ( void ) {
int n;
scanf("%d", &n);
std::vector< std::vector<rectangle> > v(n);
for (int i = 0; i < n; ++i) {
rectangle r;
scanf("%d %d %d", &r.coords[0], &r.coords[1], &r.coords[2]);
//generate all rotations with the given rectangle (all combinations of the coordinates)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
if(j != k) //micro optimization disease
for (int l = 0; l < 3; ++l)
if(l != j && l != k)
v[i].push_back( rectangle(r.coords[j], r.coords[k], r.coords[l]) );
}
printf("%d\n", dp(v));
}
Input Description
A test case starts with an integer N, representing the number of boxes (1 ≤ N ≤ 10^5).
Following there will be N rows, each containing three integers, A, B and C, representing the dimensions of the boxes (1 ≤ A, B, C ≤ 10^4).
Output Description
Print one row containing one integer, representing the maximum height of the stack if it’s possible to pile all the N boxes, or -1 otherwise.
Sample Input
2
5 2 2
1 3 4
Sample Output
6
Sample image for the given input and output.
Usually you're given the test case that made you fail. Otherwise, finding the problem is a lot harder.
You can always approach it from a different angle! I'm going to leave out the boring parts that are easily replicated.
struct Box { unsigned int dim[3]; };
Box will store the dimensions of each... box. When it comes time to read the dimensions, it needs to be sorted so that dim[0] >= dim[1] >= dim[2].
The idea is to loop and read the next box each iteration. It then compares the second largest dimension of the new box with the second largest dimension of the last box, and same with the third largest. If in either case the newer box is larger, it adjusts the older box to compare the first largest and third largest dimension. If that fails too, then the first and second largest. This way, it always prefers using a larger dimension as the vertical one.
If it had to rotate a box, it goes to the next box down and checks that the rotation doesn't need to be adjusted there too. It continues until there are no more boxes or it didn't need to rotate the next box. If at any time, all three rotations for a box failed to make it large enough, it stops because there is no solution.
Once all the boxes are in place, it just sums up each one's vertical dimension.
int main()
{
unsigned int size; //num boxes
std::cin >> size;
std::vector<Box> boxes(size); //all boxes
std::vector<unsigned char> pos(size, 0); //index of vertical dimension
//gets the index of dimension that isn't vertical
//largest indicates if it should pick the larger or smaller one
auto get = [](unsigned char x, bool largest) { if (largest) return x == 0 ? 1 : 0; return x == 2 ? 1 : 2; };
//check will compare the dimensions of two boxes and return true if the smaller one is under the larger one
auto check = [&boxes, &pos, &get](unsigned int x, bool largest) { return boxes[x - 1].dim[get(pos[x - 1], largest)] < boxes[x].dim[get(pos[x], largest)]; };
unsigned int x = 0, y; //indexing variables
unsigned char change; //detects box rotation change
bool fail = false; //if it cannot be solved
for (x = 0; x < size && !fail; ++x)
{
//read in the next three dimensions
//make sure dim[0] >= dim[1] >= dim[2]
//simple enough to write
//mine was too ugly and I didn't want to be embarrassed
y = x;
while (y && !fail) //when y == 0, no more boxes to check
{
change = pos[y - 1];
while (check(y, true) || check(y, false)) //while invalid rotation
{
if (++pos[y - 1] == 3) //rotate, when pos == 3, no solution
{
fail = true;
break;
}
}
if (change != pos[y - 1]) //if rotated box
--y;
else
break;
}
}
if (fail)
{
std::cout << -1;
}
else
{
unsigned long long max = 0;
for (x = 0; x < size; ++x)
max += boxes[x].dim[pos[x]];
std::cout << max;
}
return 0;
}
It works for the test cases I've written, but given that I don't know what caused yours to fail, I can't tell you what mine does differently (assuming it also doesn't fail your test conditions).
If you are allowed, this problem might benefit from a tree data structure.
First, define the three possible cases of block:
1) Cube - there is only one possible option for orientation, since every orientation results in the same height (applied toward total height) and the same footprint (applied to the restriction that the footprint of each block is completely contained by the block below it).
2) Square Rectangle - there are three possible orientations for this rectangle with two equal dimensions (for examples, a 4x4x1 or a 4x4x7 would both fit this).
3) All Different Dimensions - there are six possible orientations for this shape, where each side is different from the rest.
For the first box, choose how many orientations its shape allows, and create corresponding nodes at the first level (a root node with zero height will allow using simple binary trees, rather than requiring a more complicated type of tree that allows multiple elements within each node). Then, for each orientation, choose how many orientations the next box allows but only create nodes for those that are valid for the given orientation of the current box. If no orientations are possible given the orientation of the current box, remove that entire unique branch of orientations (the first parent node with multiple valid orientations will have one orientation removed by this pruning, but that parent node and all of its ancestors will be preserved otherwise).
By doing this, you can check for sets of boxes that have no solution by checking whether there are any elements below the root node, since an empty tree indicates that all possible orientations have been pruned away by invalid combinations.
If the tree is not empty, then just walk the tree to find the highest sum of heights within each branch of the tree, recursively up the tree to the root - the sum value is your maximum height, such as the following pseudocode:
std::size_t maximum_height() const{
if(leftnode == nullptr || rightnode == nullptr)
return this_node_box_height;
else{
auto leftheight = leftnode->maximum_height() + this_node_box_height;
auto rightheight = rightnode->maximum_height() + this_node_box_height;
if(leftheight >= rightheight)
return leftheight;
else
return rightheight;
}
}
The benefits of using a tree data structure are
1) You will greatly reduce the number of possible combinations you have to store and check, because in a tree, the invalid orientations will be eliminated at the earliest possible point - for example, using your 2x2x5 first box, with three possible orientations (as a Square Rectangle), only two orientations are possible because there is no possible way to orient it on its 2x2 end and still fit the 4x3x1 block on it. If on average only two orientations are possible for each block, you will need a much smaller number of nodes than if you compute every possible orientation and then filter them as a second step.
2) Detecting sets of blocks where there is no solution is much easier, because the data structure will only contain valid combinations.
3) Working with the finished tree will be much easier - for example, to find the sequence of orientations of the highest, rather than just the actual height, you could pass an empty std::vector to a modified highest() implementation, and let it append the actual orientation of each highest node as it walks the tree, in addition to returning the height.

Algorithm Trax Winning Condition

I tried to implement the game Trax in C++.
For those who do not know: http://www.traxgame.com/about_rules.php
I have built the board so far and created the rules where I can put my next Tile and which one I am allowed to set.
But now, I am struggling with the winning conditions.
As you can see, I need a line of at least 8 tiles..
My first solution attempt had included way to many if-conditions. That is simply not possible.
So i need to implement a proper algorithm..
My secong attempt using a bitboard is getting atm quite complicated, so my question would be if there is an easier way, I am simply missing at the moment.
Greets, MC
I can propose you to use recursion. I can misunderstand your, but anyway:
bool isWin(int i, int j, int length) {
if (length >= 8)
return true;
if (canMoveTo(i + 1, j)) {
if (isWin(i + 1, j, length + 1))
return true;
}
if (canMoveTo(i - 1, j)) {
if (isWin(i - 1, j, length + 1))
return true;
}
if (canMoveTo(i, j + 1)) {
if (isWin(i, j + 1, length + 1))
return true;
}
if (canMoveTo(i, j - 1)) {
if (isWin(i, j - 1, length + 1))
return true;
}
return false;
}
bool isWin(int i, int j) {
int length = 0;
isWin(i, j, length);
}
..
main() {
for (int i = 0; i < HEIGHT; ++i) {
for (int j = 0; j < WIDTH; ++j) {
if (isTilePresent(i, j)) {
if (isWin(i, j)) {
if (isRed(i, j))
std::cout << "Red is won!" << std::endl;
else
std::cout << "White is won!" << std::endl;
}
}
}
}
}
For this kind of game stuff To make things easy I would add a small bitmap to tile representation
create tile maps
smallest resolution able to represent all tiles like this
I think may be also 3x3 resolution will be doable. You need 4 colors:
Gray - wall
Red - path plr1
White - path plr2
Magenta - path plr1,plr2
after each turn
create board bitmap from tiles bitmaps and use A* start with last edited tile (and may be also 4 neighbors) and do path for each player/path start point (Yellow). When A* is done then analyze the map data (orange) so find the biggest number in map (green mid point). It is point where A* filling stops (no need to searching for it). Then reconstruct shortest path back to start point (brown) setting used map points as unusable. Then try to reconstruct path again if you can then closed loop is present
while reconstructing path
compute bounding box of used points so you will need min,max x,y coordinates x0,x1,y0,y1 (in tiles). From this if loop found you know:
columns = x1-x0+1
rows = y1-y0+1
so the win condition is just single if from this
Hope this helps, I developed this technique for closed loop path finding/counting in my Carcassonne game

passing values to a boolean array

I'm working on a simple 2d game engine, and am trying to set up a system where the player model can move behind certain objects. Every time an non-player object is blitted to the screen, its X and Y are recorded in an array so they can be used later. As such, I have set up a system where if the player X and player Y are relative to an environmental object's X and Y in a certain way, the environmental object is not immediately blitted (Normally, it would be immediately blitted before the player character so that the player character is above the object). Instead of being blitted, I have a true value be handed to a boolean array. I have an int variable that gets 1 larger every time an object is blitted so that the different X, Y and boolean values are associated with a certain position in the array. Essentially, the system looks like this:
HDcounter += 1;
forbiddenX[HDcounter] = modelX[modelNumber] + modelXChange;
forbiddenY[HDcounter] = modelY[modelNumber] + modelYChange;
forbiddenSpriteWidth[HDcounter] = 100;
forbiddenSpriteHeight[HDcounter] = 200;
forbiddenSpriteDepth[HDcounter] = 25;
if((forbiddenX[HDcounter] <= playerXE + forbiddenSpriteWidth[HDcounter]) && (forbiddenX[HDcounter] + forbiddenSpriteWidth[HDcounter] >= playerXE) && (forbiddenY[HDcounter] <= playerYE + forbiddenSpriteWidth[HDcounter]) && (forbiddenY[HDcounter] + forbiddenSpriteHeight[HDcounter] >= playerYE + 77))
{
pineTreeBlitAP = true;
blitModelAP[HDcounter] = true;
}
else
{
modelIMAGE = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(modelX[modelNumber] + modelXChange, modelY[modelNumber] + modelYChange, windowMODELS, modelIMAGE, 0, 0, 200, 200);
}
The problem is that when I try to use the boolean array to blit the model after the player, it does not seem to work. I can get something to happen when the player X and Y hits the threshold, but I cannot seem to get the true value recorded inside the boolean array and then used by my function.
This is the function where it is used:
void enviroment::blitEnviroModelsAP(SDL_Surface* BAPwindow, int modelAmount)
{
SDL_Surface* modelAPimage;
for(int model = 0; model < modelAmount; model++)
{
if((pineTreeBlitAP == true) && (blitModelAP[model] == true))
{
modelAPimage = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(forbiddenX[model], forbiddenY[model], BAPwindow, modelAPimage, 0, 0, 200, 200);
}
}
}
I get that this is probably a totally noob question, I just want some kind of help with this as I have been stuck for nearly a week.
Edit: Here are how my arrays are declared.
int forbiddenX[2000] = {0};
int forbiddenY[2000] = {0};
int forbiddenSpriteHeight[2000] = {0};
int forbiddenSpriteWidth[2000] = {0};
int forbiddenSpriteDepth[2000] = {0};
int blitModelAP[2000] = {false};

Implementing Alpha Beta into Minimax

I'm trying to add Alpha Beta pruning into my minimax, but I can't understand where I'm going wrong.
At the moment I'm going through 5,000 iterations, where I should be going through approximately 16,000 according to a friend. When choosing the first position, it is returning -1 (a loss) whereas it should be able to definitely return a 0 at this point (a draw) as it should be able to draw from an empty board, however I can't see where I'm going wrong as I follow my code it seems to be fine
Strangely if I switch returning Alpha and Beta inside my checks (to achieve returning 0) the computer will attempt to draw but never initiate any winning moves, only blocks
My logical flow
If we are looking for alpha:
If the score > alpha, change alpha. if alpha and beta are overlapping, return alpha
If we are looking for beta:
If the score < beta, change beta. if alpha and beta are overlapping, return beta
Here is my
Recursive call
int MinimaxAB(TGameBoard* GameBoard, int iPlayer, bool _bFindAlpha, int _iAlpha, int _iBeta)
{
//How is the position like for player (their turn) on iGameBoard?
int iWinner = CheckForWin(GameBoard);
bool bFull = CheckForFullBoard(GameBoard);
//If the board is full or there is a winner on this board, return the winner
if(iWinner != NONE || bFull == true)
{
//Will return 1 or -1 depending on winner
return iWinner*iPlayer;
}
//Initial invalid move (just follows i in for loop)
int iMove = -1;
//Set the score to be instantly beaten
int iScore = INVALID_SCORE;
for(int i = 0; i < 9; ++i)
{
//Check if the move is possible
if(GameBoard->iBoard[i] == 0)
{
//Put the move in
GameBoard->iBoard[i] = iPlayer;
//Recall function
int iBestPositionSoFar = -MinimaxAB(GameBoard, Switch(iPlayer), !_bFindAlpha, _iAlpha, _iBeta);
//Replace Alpha and Beta variables if they fit the conditions - stops checking for situations that will never happen
if (_bFindAlpha == false)
{
if (iBestPositionSoFar < _iBeta)
{
//If the beta is larger, make the beta smaller
_iBeta = iBestPositionSoFar;
iMove = i;
if (_iAlpha >= _iBeta)
{
GameBoard->iBoard[i] = EMPTY;
//If alpha and beta are overlapping, exit the loop
++g_iIterations;
return _iBeta;
}
}
}
else
{
if (iBestPositionSoFar > _iAlpha)
{
//If the alpha is smaller, make the alpha bigger
_iAlpha = iBestPositionSoFar;
iMove = i;
if (_iAlpha >= _iBeta)
{
GameBoard->iBoard[i] = EMPTY;
//If alpha and beta are overlapping, exit the loop
++g_iIterations;
return _iAlpha;
}
}
}
//Remove the move you just placed
GameBoard->iBoard[i] = EMPTY;
}
}
++g_iIterations;
if (_bFindAlpha == true)
{
return _iAlpha;
}
else
{
return _iBeta;
}
}
Initial call (when computer should choose a position)
int iMove = -1; //Invalid
int iScore = INVALID_SCORE;
for(int i = 0; i < 9; ++i)
{
if(GameBoard->iBoard[i] == EMPTY)
{
GameBoard->iBoard[i] = CROSS;
int tempScore = -MinimaxAB(GameBoard, NAUGHT, true, -1000000, 1000000);
GameBoard->iBoard[i] = EMPTY;
//Choosing best value here
if (tempScore > iScore)
{
iScore = tempScore;
iMove = i;
}
}
}
//returns a score based on Minimax tree at a given node.
GameBoard->iBoard[iMove] = CROSS;
Any help regarding my logical flow that would make the computer return the correct results and make intelligent moves would be appreciated
Does your algorithm work perfectly without alpha-beta pruning? Your initial call should be given with false for _bFindAlpha as the root node behaves like an alpha node, but it doesn't look like this will make a difference:
int tempScore = -MinimaxAB(GameBoard, NAUGHT, false, -1000000, 1000000);
Thus I will recommend for you to abandon this _bFindAlpha nonsense and convert your algorithm to negamax. It behaves identically to minimax but makes your code shorter and clearer. Instead of checking whether to maximize alpha or minimize beta, you can just swap and negate when recursively invoking (this is the same reason you can return the negated value of the function right now). Here's a slightly edited version of the Wikipedia pseudocode:
function negamax(node, α, β, player)
if node is a terminal node
return color * the heuristic value of node
else
foreach child of node
val := -negamax(child, -β, -α, -player)
if val ≥ β
return val
if val > α
α := val
return α
Unless you love stepping through search trees, I think that you will find it easier to just write a clean, correct version of negamax than debug your current implementation.