I am trying to make the game of life in c++ at the moment, this is my first C++ exercise ever. I have one question, we need to make some game modes like one is called "torus" where cells that leave the board should re-enter it on the opposite side.
Now, i am checking the neighbours right now. But i am hardcoding it with hell a lot of if clauses, because i tried some for-loops but it did not work.
But is this really the only option? To hardcode every possibility (cells on the left side, on the right side, upper side, lower side etc?
This is a fragment of the code i have for that:
int countNeighboursTorus(int a, int b) {
int living = 0;
// when the starting cell is the one on the upper left (start of the board)
if (a == 0 && b == 0) {
// cell below
if (board[a - 1][b] != DEAD) {
living++;
}
// cell right below
if (board[a + 1][b + 1] != DEAD) {
living++;
}
// cell right
if (board[a][b + 1] != DEAD) {
living++;
}
// cell above (other side of the board)
if (board[HEIGHT - 1][b] != DEAD) {
living++;
}
// cell above right (other side of the board)
if (board[HEIGHT - 1][b + 1] != DEAD) {
living++;
}
}
// first edge case (height = 0, width != 0):
else if (a == 0 && b != 0) {
// cell below
if (board[a - 1][b] != DEAD) {
living++;
}
// cell right below
if (board[a + 1][b + 1] != DEAD) {
living++;
}
// cell right
if (board[a][b + 1] != DEAD) {
living++;
}
// cell left below
if (board[a + 1][b - 1] != DEAD) {
living++;
}
// cell left
if (board[a][b - 1] != DEAD) {
living++;
}
// cell left above (other side of the board)
if (board[HEIGHT - 1][b - 1] != DEAD) {
living++;
}
// cell above (other side of the board)
if (board[HEIGHT - 1][b] != DEAD) {
living++;
}
// cell above right (other side of the board)
if (board[HEIGHT - 1][b + 1] != DEAD) {
living++;
}
}
return living;
}
One of the for loops i wrote, but did not really work, was the following - the loop counted too many cells all the time. After the loop, all the cells ALWAYS had the dead status because the program always counted more than 3 living cells, even if only 2 cells were living from the start. I hope this explanation is helpful, it is a little bit hard to explain. I made an outprint - "+" - and it usually showed about 5/6 plusses, even if it should only show it twice (two living cells).
// for any other "normal" cases inside of the board:
else if (a != 0 && b != 0 && a < HEIGHT - 1 && b < WIDTH - 1) {
for (int c = -1; c < 2; c++) {
for (int d = -1; d < 2; d++) {
if (!(c == 0 && d == 0)) {
if (board[a + c][b + d] != DEAD) {
living++;
}
}
}
}
}
Is there ANY option to simplify that? For instance with loops, like i tried? Or is that the way it should be done? I am really not seeing the light on the end of the tunnel right now. Just so that i know if i am doing this for nothing. I am really having some problems with the C++ syntax because i only did Java for about a year until now, so i am a beginner when it comes to C++. I am grateful for any tips!
Yes. Use the modulus operator:
Instead of
if (board[a + 1][b + 1] != DEAD) {
use:
if (board[(a + 1) % HEIGHT][(b + 1) % WIDTH] != DEAD) {
There is a slight complexity when you doing subtraction (% isn't actually the modulus operation, it's the remainder operation). You don't want to use it on -1 (it will just return -1), so add an additional HEIGHT/WIDTH:
if (board[(a - 1 + HEIGHT) % HEIGHT][(b - 1 + WIDTH) % WIDTH] != DEAD) {
You can then use the same code for all the cells of the board.
This line tries to access elements of the matrix that are not in matrix range:
if (board[a + c][b + d] != DEAD) {
Before executing this line you have to check if a + c and b + d are in matrix range, and if they are not what should be done instead. For "torus" requirement I guess "left" and "right" out of range should be replaced with wrapped values, and "top" and "bottom" out of range should be just skipped.
In addition to Martin Bonner's answer, prepare the table of offsets to eight neighbors:
static const int NoOfNeighbors = 8;
int dVertNeigh [NoOfNeighbors] = {
HEIGHT-1, HEIGHT-1, HEIGHT-1,
0, 0,
1, 1, 1};
int dHorizNeigh [NoOfNeighbors] = {
WIDTH-1, 0, 1,
WIDTH-1, 1,
WIDTH-1, 0, 1};
then you can count neighbor cells with a simple loop:
for (int ngh = 0; ngh < NoOfNeighbors; ngh++) {
int neighborV = (a + dVertNeigh[ngh]) % HEIGHT;
int neighborH = (b + dHorizNeigh[ngh]) % WIDTH;
if (board[neighborV][neighborH] != DEAD) {
living++;
}
}
Related
I have a matrix which is 3*3 for example, and I have a variable = 10.
This variable represents the first element of the new array. I need to store the last element as well in a new variable.
I need to move the matrix left to right, right to left, up to down, and down to up, by shifting the elements and getting the last element.
For example the default matrix:
[[0,1,2]
[3,4,5]
[6,7,8]]
Shifting the the first row with variable=5
[[5,0,1]
[3,4,5]
[6,7,8]]
and then I get back 2 the second result.
Another example shift from up to down the last column with variable=6:
[[5,0,6]
[3,4,2]
[6,7,5]]
and then I get back 8.
Here is a snippet of my c++ code, but I can accept every language.
#include <iostream>
using namespace std;
int main()
{
int ar[3][3] = {
{0, 1, 2} ,
{3, 4, 5} ,
{6, 7, 8}
};
int x=0;
for (int i = 0; i < 2; i++) {
int temp = x[i];
x[i]=x[i+1];
x[i]=tmp;
}
return 0;
}
We can generalize the directions in such a manner that the same code would handle all of the cases. The example below is a proof-of-concept, yet, it was not actually tested, because I lack a C++ env at the moment. But, if it turns out to be some problem with it, then it should be fairly easy to fix it, so if it does not work yet, then please provide example inputs and outputs.
int index = 0; //It can be something between 0 and 2
int isRow = 1; //It can be 1 if it's a row to be shifted and 0 if it's a column to be shifted
int direction = 1; //It can be -1 if it's to the left/up (depending on the value of isRow) and 1 if it's right/down
int output; //The element we need to store at the end
int input = 10; // The element we need to append
int i;
for (i = 0; i <= 2; i++) {
if (i == 0) output = ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * i)) : index];
else ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * (i - 1))) = ar[isRow ? index : (2 - (direction + 1) + direction * i)][isRow ? (2 - (direction + 1) + (direction * (i - 1)));
}
Required to write a minimax algorithm that returns a value from a array of random numbers, the length of which is 2 ^ depth(the algorithm works on a binary tree).
my code:
int minimax(int* scores, unsigned int left, unsigned int right, int depth, bool search_max_score, bool& move)
{
if (search_max_score)
{
if (depth == 1)
{
int result = std::max(scores[left], scores[right]);
move = (result == scores[right]);
return result;
}
int left_value = minimax(scores, left, right / 2, depth - 1, false, move);
int right_value = minimax(scores, right / 2 + 1, right, depth - 1, false, move);
int result = std::max(left_value, right_value);
move = (result == right_value);
return result;
}
else
{
if (depth == 1)
{
int result = std::min(scores[left], scores[right]);
move = (result == scores[right]);
return result;
}
int left_value = minimax(scores, left, right / 2, depth - 1, true, move);
int right_value = minimax(scores, right / 2 + 1, right, depth - 1, true, move);
int result = std::min(left_value, right_value);
move = (result == right_value);
return result;
}
}
//score_num - array length
//search_max_score - which element to search for (false - minimum, true - maximum)
bool move;
int result = minimax(scores, 0, score_num - 1, depth, search_max_score, move);
std::cout << "result: " << result << '\n';
std::cout << "move: " << move;
But sometimes the program outputs the wrong value:
random values:
___/___ __\____
_/_ _\_ _/_ _\_
/ \ / \ / \ / \
-1 3 -5 1 -8 6 4 -7
result: 1
move: 0
move is the direction of the subsequent action of the AI. 0 - left, 1 - right
You have at least 2 bugs:
Inside if (search_max_score) block you call minmax with false as the 5th argument, which is equivalent to making the search for max element becoming a search for min element, and then max again, etc.
If you have an interval [left, right] and you want to halve it, the midpoint is NOT right/2 (unless left == 0), but rather (left + right)/2 or left + (right-left + 1)/2. You need to work on the exact form of this formula that will fit your needs, taking into account the integer rounding when dividing an odd integer by 2. Or you can calculate the offset from depth, as the interval length will always be a power of two.
The third point is not a bug, but an error it is: please use a debugger.
The statement of the problem follows:
Description:
Write a C++ program that reads the dimensions of a pool table, and prints with 0's the trajectory of a ball after hitting the table in the upper left corner with an angle of 45ยบ.
Input:
Input consists of several cases, each with the number of rows and the number of columns. Both numbers are, at least, 2.
Output:
Print every pool table as shown in the examples.
Observation:
The expected solution doesn't use vectors or alike. This includes vectors, strings, arrays, etc. Mathematically speaking, the expected solution uses O(1) memory in the worst case.
Example:
Sample input:
7 4
10 16
Sample output:
######
#0 #
# 0 #
# 0 #
# 0#
# 0 #
# 0 #
#0 #
######
##################
#0 0 0 #
# 0 0 0 0 0 #
# 0 0 0 0 0 #
# 0 0 0#
# 0 0 0 0 0 #
# 0 0 0 0 0 #
#0 0 0 #
# 0 0 0 0 0 #
# 0 0 0 0 0 #
# 0 0 0#
##################
The solution to this problem would be fairly easy if you could use for instance a matrix to keep marking the position of the ball after each movement, and following its trajectory until it hits a corner. But they expect you to not use such data structures (it's an introductory programming course, just to practise), so it's a little bit more difficult.
I've thought of a solution which prints the output pool table line per line, keeping track of the ball position, but the main problem I encountered was being able to predict the position of the ball in cases like the 2nd one (10, 16) where when you print the first line you already need to know that the ball will eventually reach it again twice after some collisions with the table.
Any idea on how to solve it?
int positiveMod(int x, int y)
{
return ((x % y) + y) % y;
}
int main()
{
int x,y,sx,sy;
int startX;
int minStartX = 0;
cin >> sy >> sx;
startX = 0;
// compute the various start points on x with y=0, keep the smallest to identify the repeating stride
do
{
startX = (startX + 2 * (sy - 1)) % (2 * (sx - 1));
if ((minStartX == 0) || (startX < minStartX) && (startX != 0))
{
minStartX = startX;
}
}
while (startX != 0);
for(y=0; y < sy; y++)
{
for(x=0; x < sx; x++)
{
if (
(minStartX == 0) && (x == y) || //identity line
(minStartX != 0) && positiveMod(x - y, minStartX) == 0 || // top-left quadrant
(minStartX != 0) && positiveMod( (2 * (sx - 1) - x) - y, minStartX) == 0 || // mirror against y axis
(minStartX != 0) && positiveMod( x - (2 * (sy - 1)) - y, minStartX) == 0 // mirror against x axis
)
{
cout << '0';
}
else
{
cout << ' ';
}
}
cout << endl;
}
}
It still needs the border, and needs fixing for cases where y>x. You can just flip the x/y logic in that case. Hints taken from comments.
The simplest would be to pre-allocate the buffer of the strings to display. Either:
an array of std::strings, string[y + some].
a two dimensional array, char[y + some][x + some].
or a simple char array, char[(x + some)*(y + some)].
+some is there for the borders, the '\0' terminals, etc...
You probably want it dynamically allocated with new so you can resize your buffer for each table. Or just allocate something larger that covers the largest table.
Then, fill the buffer with spaces, and draw the border in the array. Start the ball at (0,0), iterate while your not done, putting the '0's in the buffer. Once done, print the whole buffer, line by line.
Silly implementation of Jeffreys suggestion. Computationally silly, probably easier to do this mathematically but it answers the question...
bool SimulateBallUntil(int width, int height, int x, int y)
{
// start off heading down right
int xInc = 1;
int yInc = 1;
// Start off at pos 0,0
int curX = 0;
int curY = 0;
// Run the path...
for(int iter=0;;++iter)
{
// Check if hit point
if(curX == x && curY == y)
{
return true;
}
// Check if hit corner (ignoring the first iteration which is the left corner)
if(iter && ((curY == 0) || (curY == height-1)) && ((curX == 0) || (curX == width-1)))
{
return false;
}
// Bounce off walls
if(curX + xInc == width || ((curX + xInc)==-1))
{
xInc *= -1;
}
if(curY + yInc == height || (curY + yInc==-1))
{
yInc *= -1;
}
// Move it
curX += xInc;
curY += yInc;
}
}
I am trying to split a Matrix into segments, perform some manipulation of the segments and then merge the segments into a complete matrix again.
To split, I'm doing:
for(int j = 0; j < segments; ++j)
{
Rect r;
if(j == lastSegment)
{
r = Rect(j * segmentWidth, 0, lastWidth, origHei);
}
else
{
r = Rect(j * segmentWidth, 0, segmentWidth - 1, origHei);
}
tmpFrame(r).copyTo(segmentMats[j]);
}
Then to merge them I try:
Mat fullFrame;
for(int i = 0; i < maxSegments; ++i)
{
int segNum = i % segments;
Rect r;
if( segNum == 0) // 1st segment of frame
{
fullFrame.create(origWid, origHei, segmentMats[i].type());
r = Rect(0, 0, segmentWidth - 1, origHei);
}
else if (segNum == lastSegment)
{
r = Rect((i * segmentWidth), 0, lastWidth, origHei);
}
else
{
r = Rect((i * segmentWidth), 0, segmentWidth - 1, origHei);
}
segmentMats[i].copyTo(fullFrame(r));
}
But I keep getting a failed assertion,
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x
+ roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat
I don't see how this code could set borders outside the assertion values. Can someone see my error?
Thanks.
Edit:
Thanks for the replies. To clarify my variables, I've listed how they are computed below.
origWid and origHei are the height and width of the entire frame
segments = the number of vertical segments a frame is divided into. So segments = 2 means the frame is divided in half vertically.
lastSegment = segments - 1; since they are 0-inclusive indexed, that last segment has this index
segmentWidth = origWid / segments; this floors in case origWid is not evenly divisible by segments
lastWidth = origWid - (lastSegment * segmentWidth); this takes care of the case that origWid is not evenly divisible by segments and captures the number of columns left over in the last segment
segmentMats is an array of segments Mats
segNum = the order of the segment. So if segments == 2, segNum == 0 is the left half of the frame and segNum == 1 is the right half of the frame
Here's the code:
while((fingerYLast - fingerAt.y) > fingerMoveThresh)
{
if( (activeCard) < (allCardList.count - 2))
{
[self sayOut:#"TRUE"];
activeCard = activeCard + 1;
}
else
{
//WTF????
[self sayOut:[NSString stringWithFormat:#"FALSE %i %i",
activeCard, (allCardList.count - 2)]];
}
fingerYLast -= fingerMoveThresh;
}
I've checked the test values, and activeCard is -1, and allCardList has 10 members.
activeCard = -1;
(activeCard) < (allCardList.count - 2) //evaluates as false
(activeCard+1) < (allCardList.count - 1) //evaluates as true
Any ideas?
I don't code in that language but my bet is that allCardList.count returns an unsigned quantity and -2, in an attempt to push it below zero, will return you a very large unsigned number.