Strange behaviour in nested For Loops - c++

First of all, I'm pretty new to C++ so try not to be too harsh on me. I wrote this block of code:
int LargestProduct (string numStr, int groupSize) {
int numOfGroups = numStr.size() / groupSize;
int groupsRemaining = numStr.size() % groupSize;
int largestProduct = 0, thisProduct = 1;
for (int i = 1; i <= numOfGroups; i++) {
for (int j = i; j <= groupSize; j++)
thisProduct *= (numStr[j-1] - '0');
if (thisProduct > largestProduct)
largestProduct = thisProduct;
thisProduct = 1;
}
// .. A bit more irrelevant code here
return largestProduct;
}
The function call LargestProduct ("1234567890", 2) should yield 72, but it wrongly yields 6. So, for some reason, this code will work but not as expected (Note: this code I wrote should compute the largest product of groupsSize-adjacent numbers in a big, given number called numStr).
I did some debugging, and found a strange behaviour in the nested for-loop. I set up a breakpoint inside the second for-loop
thisProduct *= (numStr[j] - '0');
After some iterations (for example, 8 iterations), this is what I would expect i and j to be:
+--------+---------+
| i | j |
+--------+---------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
| 4 | 1 |
| 4 | 2 |
+--------+---------+
This is what really happens:
+--------+---------+
| i | j |
+--------+---------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
+--------+---------+
And suddenly the program spits out a wrong result (6, instead of 72)
But this seems counterintuitive, to say the least. The variable i goes from 0 to numOfGroups, which in the example above equals 5. On the other hand, j goes from i to groupSize, which happens to be 2.
There should be 5*2 = 10 iterations, but there are only 3 of them. Also, in the last iteration, j should be "re-initialized" to 0. This doesn't happen though.
Anyone please help this C++ newbie?
EDIT
The problem was that the j-for-loop ranged from a moving index (i) to a non-moving index(groupSize). This was causing that "shrinking" effect in the second for-loop, which is easily fixed by changing this line:
for (int j = i; j <= groupSize; j++)
To this other one:
for (int j = i; j <= i + groupSize - 1; j++)
And to make the full algorithm to work as expected, one should also replace these lines:
int numOfGroups = numStr.size() / groupSize;
int groupsRemaining = numStr.size() % groupSize;
with this single one:
int numOfGroups = numStr.size() - 1;
EDIT 2
Everything is OK now, thank you for your kindness guys! I appreciate it. The whole code is:
int LargestProduct (string numStr, int groupSize) {
int numOfGroups = numStr.size() - 1;
int largestProduct = 0, thisProduct = 1;
for (int i = 1; i <= numOfGroups; i++) {
for (int j = i; j <= i + groupSize - 1; j++)
thisProduct *= (numStr[j-1] - '0');
if (thisProduct > largestProduct)
largestProduct = thisProduct;
thisProduct = 1;
}
return largestProduct;
}

You said:
On the other hand, j goes from 0 to groupSize
But the code says:
for (int j = i; j <= groupSize; j++)
This means j is going from i to groupSize, not 0 to groupSize

Related

Multidimensional array logic

I'm currently being bamboozled by a multidimensional array.
I know a good deal about programming and I was wondering about the logic pertaining to a question from one of quiz modules from cpp institute.
int* t[2] = { new int[2], new int[2] };
for (int i = 0; i < 4; i++)
t[i % 2][i / 2] = i;
std::cout << t[0][1] + t[1][0] << endl;
delete[] t[0];
delete[] t[1];
When the compiler gets to:
for (int i = 0; i < 4; i++)
t[i % 2][i / 2] = i;
I get a little lost, is t[int][int] manipulated every 'i' loop? I know what the answer is so I'm just looking for logic clarification to understand how multidimensional arrays are calculated in loops.
It's a way of iterating through all the combinations that works because it's only a 2x2 array.
It basically has the same effect as
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
t[i][j] = i + 2*j
}
}
But instead of nesting, it's relying on the fact that you can generate the pairs 0, 0, 0, 1, 1, 0, and 1, 1 by performing arithmetic operations on 0, 1, 2, and 3:
i | i % 2 | i / 2
-----------------
0 | 0 | 0
1 | 1 | 0
2 | 0 | 1
3 | 1 | 1
Yes, you can add a print statement if you like to see it for yourself:
for (int i = 0; i < 4; i++)
{
std::cout << i % 2 << ", " << i /2 << "\n";
t[i % 2][i / 2] = i;
}
which prints:
0, 0
1, 0
0, 1
1, 1
That means that it goes through every single cell of your 2D array, in a zig-zag fashion, starting from the top left, finishing at the bottom left.

Snake game -- tail movement

I'm making a snake game and having trouble with the tail movement. I understand the logic for this part, which is that each segment of the tail follows the previous segment, starting from the end of the tail. I am looking at someone else's code, and it looks like this
#include <iostream>
#include <conio.h>
#include <windows.h>
using namespace std;
bool gameOver;
const int width = 20;
const int height = 20;
int x, y, fruitX, fruitY, score;
int tailx[100], taily[100];
int nTail;
enum eDirecton { Stop, Left, Right, Up, Down } dir;
void Setup()
{
gameOver = false;
dir = Stop;
x = width / 2;
y = height / 2;
fruitX = rand() % width;
fruitY = rand() % height;
score = 0;
}
void Draw()
{
system("cls");
for (int i = 0; i < width + 2; i++)
cout << "#";
cout << endl;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (j == 0)
cout << "#";
if (i == y && j == x)
cout << "O";
else if (i == fruitY && j == fruitX)
cout << "F";
else
{
bool print = false;
for (int k = 0; k < nTail; k++)
{
if (tailx[k] == j && taily[k] == i)
{
cout << "o";
print = true;
}
}
if (!print)
cout << " ";
}
if (j == width - 1)
cout << "#";
}
cout << endl;
}
for (int i = 0; i < width + 2; i++)
cout << "#";
cout << endl;
cout << "Score:" << score << endl;
}
void Input()
{
if (_kbhit())
{
switch (_getch())
{
case 'a':
dir = Left;
break;
case 'd':
dir = Right;
break;
case 'w':
dir = Up;
break;
case 's':
dir = Down;
break;
case 'x':
gameOver = true;
break;
}
}
}
void Logic()
{
for (int i = nTail - 1; i > 0; i--)
{
tailx[i] = tailx[i - 1];
taily[i] = taily[i - 1];
}
tailx[0] = x;
taily[0] = y;
switch (dir)
{
case Left:
x--;
break;
case Right:
x++;
break;
case Up:
y--;
break;
case Down:
y++;
break;
default:
break;
}
if (x >= width) x = 0; else if (x < 0) x = width - 1;
if (y >= height) y = 0; else if (y < 0) y = height - 1;
for (int i = 0; i < nTail; i++)
if (tailx[i] == x && taily[i] == y)
gameOver = true;
if (x == fruitX && y == fruitY)
{
score += 10;
fruitX = rand() % width;
fruitY = rand() % height;
nTail++;
}
}
int main()
{
Setup();
while (!gameOver)
{
Draw();
Input();
Logic();
Sleep(50);
}
return 0;
}
I understand the logic but I don't understand why it works. When we create an array, the value of each element is just a garbage value without initializing each element. So in the code above, when doing
tailx[i] = tailx[i-1];
taily[i] = taily[i-1];
what value is assigned to each element?
When displaying the snake, it has a for loop to go through every coordinate of the screen and inside it has another for loop to compare tailx[i] and taily[i] with each coordinate to find out the right position to print each segment of the tail. Since tailx and tialy are not storing the coordinates of the segments of the tail, how come this code works?
Thank you so much!!
Presumably, you're missing a line at the end that looks something like:
if(nTail < 100) { nTail++; }
Assuming that's the case, nTail is initialized to 0 and that this is all in a loop, the code probably looks something like (I'm using a size of 5 instead of 100 to make visualizing easier)
int tailx[5];
int taily[5];
int nTail = 0; //length
while(true) {
for(int i = nTail -1; i > 0; i--)
{
tailx[i] = tailx[i-1];
taily[i] = taily[i-1];
}
// Let's assume there's some logic here the fetches a new
// x and y. For the sake of debugging, let's assume the
// values will be {(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)}
tailx[0] = x; // x is the x-coordinate of the head
taily[0] = y; //y is the y-coordinate of the head
if(nTail < 5) { nTail++; }
}
Let's step through this!
Before we enter the loop, your tail arrays are going to look like: (I'm using NA here to mean "Garbage")
nTail = 0
+-------------------------+
|Name | 0 | 1 | 2 | 3 | 4 |
|-------------------------|
| X | NA| NA| NA| NA| NA|
+-------------------------+
| Y | NA| NA| NA| NA| NA|
+-------------------------+
We enter the loop, initialize i to nTail - 1 which is -1. This doesn't pass the check of i > 0, so we don't even enter the loop.
We'll now grab new x and y vals and assign them into the tails, along with incrementing nTail. So going into the next loop our variables will look like:
nTail = 1
+-------------------------+
|Name | 0 | 1 | 2 | 3 | 4 |
|-------------------------|
| X | 1 | NA| NA| NA| NA|
+-------------------------+
| Y | 1 | NA| NA| NA| NA|
+-------------------------+
We'll head on in, initialize i to nTail - 1 => 0. This DOESN'T pass the check of i > 0, so again we don't enter the loop (which sounds wrong to me...maybe you're initializing nTail to 1 instead of 0?).
We head on down, grab new x/y vals and increment nTail and restart the loop with:
nTail = 2
+-------------------------+
|Name | 0 | 1 | 2 | 3 | 4 |
|-------------------------|
| X | 2 | NA| NA| NA| NA|
+-------------------------+
| Y | 2 | NA| NA| NA| NA|
+-------------------------+
Initializing i to nTail - 1 => 1 means since i > 0 we'll finally enter the inner loop.
With i = 1, we update our tail arrays:
tailx[1] = tailx[0];
taily[1] = taily[0];
Then head down, grab new values and increment nTail. Our variables now look like:
nTail = 3
+-------------------------+
|Name | 0 | 1 | 2 | 3 | 4 |
|-------------------------|
| X | 3 | 2 | NA| NA| NA|
+-------------------------+
| Y | 3 | 2 | NA| NA| NA|
+-------------------------+
After the next loop, things will look like:
nTail = 4
+-------------------------+
|Name | 0 | 1 | 2 | 3 | 4 |
|-------------------------|
| X | 4 | 3 | 2 | NA| NA|
+-------------------------+
| Y | 4 | 3 | 2 | NA| NA|
+-------------------------+
I'll leave it to you to keep tracing if you so desire.
You're right; this code cannot work, and it has undefined behaviour.
nTail isn't even initialised to anything.
Are you sure it's a full program, and not just snippets glued together? Or a sort of "pseudocode" to show the logic without being actual valid C++? You'd need values for nTail and all the array elements.

Comparing elapsed time to copy memory buffers: memcpy vs ForLoopIndexCopying

I am trying to understand the difference between "memcpy" and "for-loop-index-copying" of a buffer in the time it takes to copy.
results:
CopyingType | MemoryType | RunMode | Elapsed Time(ms)
-----------------------------------------------------------
memcpy | stack | Debug | x
forLoopIndexing | stack | Debug | 30x
memcpy | stack | Release | 0
forLoopIndexing | stack | Release | 0
memcpy | heap | Release | 0
forLoopIndexing | heap | Release | 2000
Here is my code to run... Maybe I am doing something wrong ???
Seems odd that to copy a 500,000 byte buffer 100,000 times takes no time at all or at least less than the resolution of the machine... in my case 16ms.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
int main()
{
long baseTime;
const long packetLength = 500000;
//char packet1[packetLength];//stack
//char packet2[packetLength];//stack
char *packet1 = (char*)calloc(packetLength, sizeof(char));//heap
char *packet2 = (char*)calloc(packetLength, sizeof(char));//heap
memset(packet1, 0, packetLength);//init
memset(packet2, 0, packetLength);//init
long NumPackets = 100000;
long NumRuns = 10;
for (long k = 0; k < NumRuns; k++)
{
//create packet
printf("\npacket1:\n");
for (long i = 0; i < packetLength; i++) {
packet1[i] = (char)(i % 26 + 65);
}
printf("\nk:%d\n", k);
//index copy
baseTime = GetTickCount();
long ii = 0;
for (long j = 0; j < NumPackets; j++) {
for (long i = 0; i < packetLength; i++) {
packet2[i] = packet1[i];
}
}
printf("Time(IndexCopy): %ld\n", GetTickCount() - baseTime);
//memcpy
memset(packet2, 0, packetLength);//reset
baseTime = GetTickCount();
for (long j = 0; j < NumPackets; j++) {
memcpy(packet2, packet1, packetLength); //Changed via PaulMcKenzie.
}
printf("Time(memcpy): %ld\n", GetTickCount() - baseTime);
//printf("\npacket2\n");
for (long i = 0; i < packetLength; i++) {
//printf("%c", packet2[i]);
}
}
int iHalt;
scanf_s("%d", &iHalt);
return 0;
}
Via the change... the new table
CopyingType | MemoryType | RunMode | Elapsed Time(ms)
-----------------------------------------------------------
memcpy | stack | Debug | x
forLoopIndexing | stack | Debug | 50x
memcpy | stack | Release | 0
forLoopIndexing | stack | Release | 0
memcpy | heap | Release | 2000
forLoopIndexing | heap | Release | 2000
Maybe I am doing something wrong ???
You are doing something wrong, more to the point, in the code that uses memcpy.
const long packetLength = 500000;
char *packet1 = (char*)calloc(packetLength, sizeof(char));
char *packet2 = (char*)calloc(packetLength, sizeof(char));
//...
for (long j = 0; j < NumPackets; j++) {
memcpy(packet2, packet1, sizeof(packet2)); // <-- Incorrect
}
The sizeof(packet2) is the same as sizeof(char *), which more than likely is either 4 or 8.
What you want is not the sizeof(char *), but the actual number of bytes to copy.
for (long j = 0; j < NumPackets; j++) {
memcpy(packet2, packet1, packetLength);
}

Reading triple nested for loop

My code is as follows. My confusion occurs during the 2nd and 3rd loop. Why does the result return 1*** then 12** then 123* then 1234.. I get the j loop is reset to 0 but doesn't it reenter the k loop whenever its true that j<=i?
for(int i = 1; i <= 4; i++)
{
for(int j = 1; j <= i; j++)
cout << j;
for(int k = 4 - i; k >= 1; k--)
cout << "*";
cout << endl;
}
Some clarification first:
Firstly: j is never reset to 0, but to 1.
Secondly: This is imho no triple-nested for-loop, which was be (but is not needed to have your code working as you describe it):
for(...) {
for(...) {
for(...) {
}
}
}
To your confusion:
Pretty printing your code:
for(int i=1; i<=4; i++) {
// Write the digits 1..i (1, 12, 123, 1234)
for(int j=1; j<=i; j++) {
std::cout << j;
}
// Write the stars (***, **, *)
for(int k=(4-i); k>=1; k--) {
std::cout << "*";
}
std::cout << std::endl;
}
Imagine the following sequences:
// Iteration | i | j | k | String
// 1 | 1 | 1 | 3 | 1*
// 2 | 1 | 1 | 2 | 1**
// 3 | 1 | 1 | 1 | 1***\n
// 4 | 2 | 1 | - | 1
// 5 | 2 | 2 | - | 12
// 6 | 2 | 2 | 2 | 12*
// 7 | 2 | 2 | 1 | 12**\n
// 8 | 3 | 1 | - | 1
// 9 | 3 | 2 | - | 12
// 10 | 3 | 3 | - | 123
// 11 | 3 | 3 | 1 | 123*\n
// 12 | 4 | 1 | - | 1
// 13 | 4 | 2 | - | 12
// 14 | 4 | 3 | - | 123
// 15 | 4 | 4 | - | 1234\n
The k-loop is reentered, if the initial index:
// k:=(4-i) >= 1
So entering the k-Loop is exclusively dependent on the index i.
Mathematically:
// (4-i) >= 1
// <=> -i >= (1-3)
// <=> -i >= -3
// <=> i <= 3
So the k-loop is reentered, as long as i is <= 3.
In order to get the effect you want your code should be like this:
for(int i = 1; i <= 4; i++)
{
for(int j = 1; j <= i; j++)
{
cout << j;
for(int k = 4 - i; k >= 1; k--)
cout << "*";
}
cout << endl;
}
if you dont have the {} the k loop is executed only after finishing the j loop

Sudoku recursive backtracking, unrecursing too early

So I am writing a sudoku solver in C++ and have run into a little snag. Below is my solve board code. It works for the first 3 rows of the puzzle, but unrecurses when hitting the end of the 4th row. Looking at the code on gdb it hits the end of the 4th row, backtracks to 6th column, tries and then unrecurses out to the end.
A couple of other notes about the code is the matrix which holds the sudoku board begins at 1,1 not 0,0. So when solveBoard is initially called the parameters are (1, 1, 0). I have also attached the setCell and checkConflicts functions for more insight on there. I have three vectors rowConf,colConf and squConf to store the values that have already been placed in the respective row, column, or square. I have been at this for hours and cannot get it to go past the 3rd row. Any assistance is greatly appreicated. Thanks!
EDIT: Added clearCell()
bool board::solveBoard(int i, int j, int count)
{
if (j > 9)
{
j = 1;
i++;
printBoard();
if (isSolved())
{
printBoard();
cout <<"The Board has been solved!" <<endl
<<" The number of recursive calls was: " <<count <<endl;
return true;
}
}
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
}
}
}
}
else
{
return (solveBoard(i, j + 1, count + 1));
}
clearCell(i, j);
return false;
}
bool board::setCell(int i, int j, char val)
{
int intVal;
intVal = atoi(&val);
if (i >= 1 && i <= BoardSize && j >= 1 && j <= BoardSize &&
intVal >= 1 && intVal <= BoardSize)
{
if (!(checkConflicts(intVal, i, j, squareNumber(i, j))))
{
return false;
}
value[i][j] = intVal;
// Set flags of the conflicts
rowConf[i][intVal] = true;
colConf[j][intVal] = true;
squConf[squareNumber(i, j)][intVal] = true;
return true;
}
else
{
throw rangeError("bad value in setCell");
}
}
bool board::checkConflicts(int val, int i, int j, int k)
{
if (i < 1 && i > BoardSize && j < 1 && j > BoardSize &&
k < 1 && k > BoardSize && val < 1 && val > BoardSize)
{
throw rangeError("bad value in checkConflicts()");
}
if (rowConf[i][val] || colConf[j][val] || squConf[k][val])
{
return false;
}
else
{
return true;
}
}
Initial Board:
-----------------------------
| 3 | 8 | -----------------------------
| | 7 | 5 -----------------------------
| 1 | | -----------------------------
-----------------------------
| | | 3 6 -----------------------------
| 2 | 4 | -----------------------------
| 7 | | -----------------------------
-----------------------------
| | 6 | 1 3 -----------------------------
| 4 5 | 2 | -----------------------------
| | | 8 -----------------------------
-----------------------------
Final Output:
-----------------------------
| 3 2 4 | 1 8 5 | 6 7 9 -----------------------------
| 6 8 9 | 7 2 3 | 4 1 5 -----------------------------
| 1 5 7 | 4 9 6 | 2 8 3 -----------------------------
-----------------------------
| | | 3 6 -----------------------------
| 2 | 4 | -----------------------------
| 7 | | -----------------------------
-----------------------------
| | 6 | 1 3 -----------------------------
| 4 5 | 2 | -----------------------------
| | | 8 -----------------------------
-----------------------------
void board::clearCell(int i, int j)
{
int intVal;
if (i >= 1 && i <= BoardSize && j >= 1 && j <= BoardSize)
{
if (value[i][j] != -1)
{
intVal = value[i][j];
rowConf[i][intVal] = false;
colConf[j][intVal] = false;
squConf[squareNumber(i, j)][intVal] = false;
value[i][j] = -1;
}
}
else
{
throw rangeError("bad value in setCell");
}
}
Your problem is most likely here:
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
}
}
}
}
Somehow it is going through this section, which is why it isn't going through the else in the end, but since it hasn't returned before, it gets stuck.
This needs more debugging, but here is an idea that could lead to a solution:
if (isBlank(i, j))
{
for (int n = 1; n < 10; n++)
{
if (setCell(i, j, (char)n + '0'))
{
if (solveBoard(i, j + 1, count + 1))
{
return true;
} else {
echo 'Looks like it ended on the farthest-level..';
}
} else {
echo 'Looks like it ended on the second-farthest level.';
}
}
The atoi function expects a string as an argument, that is an array of chars terminated with character '\0', ASCII NUL. You give a parameter being a pointer to a character (equivalent to some arrray of chars) but do not guarantee it is zero-terminated. Please replace intVal = atoi(&val); with intVal = (int)val - '0';
And your checkConflicts should have || operators instead of && in the first if.
These are probably not reasons of the error but certainly need correction.