When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
1 messages · Page 1 of 1 (latest)
When your question is answered use !solved to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
breakpoint and debug it
wtf bro
well, what do you need to check?
I need to check if the cases around the block that I want to place are the same id as the block I want to place or 0.
If it's the same id it should return true so I can place the block, if not it returns false.
The verification must be like that : it can touch corners but can't touch borders of the blocks. @west dragon
The blocks are on a 2d grid, correct?
Stuff like this is great contextual information to have in the original post
How would you do this check manually?
by checking every borders of the block
How would you do it more specifically
idk that's why I'm asking, bcs I really don't know how to do it
well, do you know how to check what id a given block has?
if it's the actual block it's currentBlock.id but when it's place I don't know
well, there seems to be this grid object
that can probably tell you what's in a given cell?
I can provide the entire file as code it would be more simple
just look at the grid object ^^
yep but how can I check the id of this cell now ?
The grid is like that after some blocks placed
Do you have any advices and help ?
you just have to check the ids at x +1, x - 1, y +1 and y - 1
you have this position : grid.grid[item.row][item.column]
so check
grid.grid[item.row + 1][item.column] == id
grid.grid[item.row - 1][item.column] == id
grid.grid[item.row][item.column + 1] == id
grid.grid[item.row][item.column - 1] == id
make sure you don't go out of bound tho
so I have to do another condition to check if it's out of bound ?
if it's correct I already have a function for it so it'll be easier
Yes, you need a condition check for each of the four neighbors you're checking. So the left is x-1, and needs to check x-1 >= 0, as negative indices are out of bounds.
Okay thanks a lot ! I'll try to do all of that and tell you the result because I tried something in the same style but it didn't work
What helped me when I did this the first time was getting a bit of graph paper and drawing on it till stuff clicked in my head
Going out of bounds is equivalent to lifting your pencil off of the paper and writing on the table, which is bad
Yep I understand, the problem is that I don't have a lot of time left but I still have a lot of things to do on this project, and I think I won't have everything when I will give it so i'm a bit sad
@reef crow Has your question been resolved? If so, type !solved :)
I have a problem, it seems to work but I can't place 2 blocks of the same id one adjacent to the other, each block can't touch any other block, that's a bit problematic
@regal monolith @humble pike
That's what it's supposed to do no?
I have to avoid 2 blocks of different id to be place adjacently but 2 with the same id should work
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0)
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0) {
return false;
}
}
return true;
}
But I don't know why it doesn't work
0 is my grid, so the basic cases
And I can place my blocks on it because it represents empty cases without blocks on it
wait i didn't read the first part sorry
np ^^
grid.grid[item.row][item.column - 1] returns the id ?
I think yes, bcs now I can place 2 blocks adjacently
it works now? what did you change if you don't mind
It doesn't work as I want, because blocks can't touch each other even the blocks with the same id
I didn't change anything since the screen I gave you, it was already working like I just said
oh i thought you resolved it 😅
Oh no sorry if I misspoke
grid.grid[item.row + 1][item.column] != currentBlock.id this is true when the grid id is 0
that's why I added && it must be different of 0
wait gonna send a screen
Each color is a different id and the background is full of 0 id, but as you can see, same color can't touch each other and that's a problem, light green should touch light green etc. for other colors but I can't
ok
I hope this was a better explanation
this
like the problem isn't in an other part
I think because whithout this function I can place block next to each other as I want
ok
I'll try to see if the current block has really the id I think it has but normally it must be good
you can put a break point in the function too if you can debug
But I really can't understand why it doesn't work because I literally said in my function : if it's different of the currentBlock it doesn't work so that means if it's the same id it should work
yes, i'm confused too tbh
bcs colors are = id so if the block I'm holding is green and place it is still green just why
if you can show more of the code i can look more detail
to me it doesn't look like the problem is here
I'll give the entire file but my project has 13 files linked I hope it'll be enough 1 file
The only pb is that I totally forgot to put comments 😓
it's fine np
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
currentBlock.id = currentPlayer;
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = GetRandomBlock();
}
}
what does this do currentBlock.id = currentPlayer;
and shouldn't it be before the checks
@reef crow
oh, currentPlayer change everytime we change block and is just an int so it means that the block id = player id so it's more simple, because they are always the same that the player currently playing
do all the blocks in your game have id = 1 once they are locked then?
because currentPlayer is 1
and you put this value in currentBlock.id
and you put the currentBlock.id which is 1 in the grid
yep and after we lock a block it changes to the next player, so after that the player = 2 so the block placed = 2
each player is a color ?
approximatively, I associated the id with a color
if id = 1, color will be light green, 2 = dark green etc.
try to change
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
currentBlock.id = currentPlayer;
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = GetRandomBlock();
}
}
to
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
currentBlock.id = currentPlayer;
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = GetRandomBlock();
}
}
please
you didn't change the id of the block before the check
so you were checking if id is 2 when, the id of the block you're holding is still 1
@humble pikeYou are a genius bro !
I'm watching your conversation on his computer and your help is very important to us! Now, I think we will be able to continue our project 😮
omg 😭
Good luck!
Thanks a lot ! Now I have to check for borders of the grid because it doesn't work everytime when I try to place my blocks at the border of the grid
it's because you go out of bounds
in your array
grid.grid[item.row - 1][item.column]
if item.row is 0
you will have
grid.grid[- 1][item.column]
which doesn't exist
@reef crow Has your question been resolved? If so, type !solved :)
In my file I have a IsBlockOutside() function do you that if I add it, it will work ?
I'm not sure at all about that bcs it's about the block and not about the verification
you just have to add if (item.row - 1 >= 0)
not dumb xD
bool Game::NearBlockCheck() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
for (Position item : tiles) {
if (item.row + 1 <= grid.grid.length)
if (grid.grid[item.row + 1][item.column] != currentBlock.id &&
grid.grid[item.row + 1][item.column] > 0) {
return false;
}
if (item.row - 1 >= 0)
if (grid.grid[item.row - 1][item.column] != currentBlock.id &&
grid.grid[item.row - 1][item.column] > 0) {
return false;
}
if (item.column + 1 <= grid.grid[item.row].length)
if (grid.grid[item.row][item.column + 1] != currentBlock.id &&
grid.grid[item.row][item.column + 1] > 0) {
return false;
}
if (item.column - 1 >= 0)
if (grid.grid[item.row][item.column - 1] != currentBlock.id &&
grid.grid[item.row][item.column - 1] > 0) {
return false;
}
}
return true;
}
something like that probably
I'm so thankful for your help
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 >= 0)
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0 && item.column + 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0 && item.column - 1 >= 0) {
return false;
}
}
return true;
}
Mine is like that
item.column + 1 >= 0 and item.row + 1 >= 0 are wrong
let's say your grid is 30 by 30 (0 to 29), if you're in position 29 and you add 1, you would be in position 30 which is greater than 0, but is out of bound
when you add you have to check the upper bound of the array
ca se dit pas jcrois
wdy mean
it's grid.grid.size() or something for the length of the row
t'aurais pu me dire que t'étais fr mdr
mdrrrr
and grid.grid[item.row].size() for the length of the column
if you use vectors for the grid it should be size()
if it's an array its sizeof(grid.grid)
you lost me
what the data type of grid.grid
actually the top right and bottom right corners don't work while placing a block
this
I think it's an array
int[] ?
go to position.h
Np I was asking myself why position but you seem very good in C++ so I trust you
you get the length of the row
and if you use sizeof(grid.grid[item.row])
you get the length of the column
you can use those to check if the positions you're trying are out of bound
Top right, bottom right and bottom left are still not working
forgot that
i'm still dumb
and still writing the wrong signs
it was with ... >= sizeof because it's over 30 for a grid of 30
it really changes something ? because it's working with what I have
gimme 2 sec
okay yeah it was fine
bool Game::NearBlockCheck() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
for (Position item : tiles) {
if (grid.grid[item.row + 1][item.column] != currentBlock.id &&
grid.grid[item.row + 1][item.column] > 0 &&
item.row + 1 < sizeof(grid.grid)) {
return false;
} else if (grid.grid[item.row - 1][item.column] != currentBlock.id &&
grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if (grid.grid[item.row][item.column + 1] != currentBlock.id &&
grid.grid[item.row][item.column + 1] > 0 &&
item.column + 1 < sizeof(grid.grid[item.row])) {
return false;
} else if (grid.grid[item.row][item.column - 1] != currentBlock.id &&
grid.grid[item.row][item.column - 1] > 0 &&
item.column - 1 >= 0) {
return false;
}
}
return true;
}
re-posting, it's what you had
can you try to put a block out of the grid?
I can't, I did a function to avoid that, even if we rotate a block it'll never be out of the grid
I used IsCellOutside() function that I wrote in another file
yep i saw that, i meant in this function you must have used something like that sizeof(grid.grid[item.row]
bool Grid::IsCellOutside(int row, int column)
{
if(row >= 0 && row < numRows && column >= 0 && column < numCols)
{
return false;
}
return true;
}
pretty similar
okok, anyway ask if you have more questions
Thanks a lot, I'll try to not bother you too much, you already helped me a lot
luken... I have a problem, I thought that it was working but sometimes it can't be place near block of a different id and sometime it can
On this screen we can't see but the strange red L in bottom left can't be placed, but all other blocks have been placed
it just doesn't work uh
it seems taht I can't place it under and on the right of a block but I can place it on the top and on the left
but it did work before the bound changes
can you send your version of that
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 >= sizeof(grid.grid))
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0 && item.column + 1 >= sizeof(grid.grid[item.row])) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0 && item.column - 1 >= 0) {
return false;
}
}
return true;
}
For the size of I didn't write the same thing as you bcs it was not working with a <, bcs it's over 30, not under
ah yes
wait
no
its <
if the id is different and the id is not 0 and the position is in the grid you return
item.row + 1 >= sizeof(grid.grid)) should be item.row + 1 < sizeof(grid.grid))
same with the other one
If I do this I can't place block on the bottom line
and you can in the right column?
with the code that I have yes but if I put < instead of >= it doesn't work anymore
so you're in row 29, if the id in 30 is different from yours and not 0 it will be true but you don't want to check it so you do 30 < 30 which is false so you don't enter in the if and you don't return
so it is <
but it doesn't work...
< numCols can you use this?
instead of size
Okay I have to include my grid.h file so
the include changes nothing I can't use numCols and numRows
still doesn't work
and the strange thing is that I can place some blocks in the row but not the entire row, like sometimes it works and sometimes not
can you stream it? i can't talk tho
I can't rn sry
okay np
do these changed block you from puting next to another box at least?
< and / sizeof(int)
blocks can only be placed at the top and left of blocks that are not the same id
My conditions should be false
wtf
send again i guess
ill have to go for 30 minutes after i look at it
my guess would be grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 is true but then you do item.row + 1 >= sizeof(grid.grid) which is false and you don't enter
no problem don't worry
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 >= sizeof(grid.grid))
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0 && item.column + 1 >= sizeof(grid.grid[item.row])) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0 && item.column - 1 >= 0) {
return false;
}
}
return true;
}
the borders of the grid work but not left and top of blocks
but right and bottom of blocks work bcs I can't place a block of different color under and on the right
you didn't add the changes
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 < sizeof(grid.grid) / sizeof(int))
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0 && item.column + 1 < sizeof(grid.grid[item.row]) / sizeof(int)) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0 && item.column - 1 >= 0) {
return false;
}
}
return true;
}
retry with this please
with the change I just can't place blocks on the right and bottom border of the grid
but now blocks of different colors can't touch
yep we're soon here !
be back in 30 minutes then
okay !
it was faster than i thought,
can you try to get ride of NearBlockCheck() in your LockBlock() function, restart the game and see if you can put your blocks on the last column/row, to make sure the problem is coming from NearBlockCheck
Sorry didn't tell you that I was going to be afk
So
I'll test
So without it I can put blocks on last row and column
@humble pike
I tried to resolve it but really can't understand why bcs the conditions seems good
You'll want to step through the code using a debugger so you can inspect the variables and see where things are going wrong
Add the compilation flag -g to add debugging information to your executable, and run lldb a.out or gdb a.out to start debugging it. If you named your executable something other than a.out, use that name in the lldb/gdb command
b main to set a breakpoint in your main functionr to run the program until it hits that breakpoints to step a single line, stepping into every function calln to go to the next line, stepping over every function callp foo to print a variable called foohelp to see a list of available commandsI'm running with clion rn so didn't do anything with a terminal
Well use clion's debugger if you prefer that, otherwise use lldb/gdb in the terminal
I know where the problem is, but I just don't know how to fix it
Do you know the exact line and values that cause the issue though? Cause if not a debugger can still be extremely helpful as it provides example values and lines where it goes wrong, rather than having to do this all in your head
I know that it's this function
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 < sizeof(grid.grid) / sizeof(int))
{
return false;
} else if(grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0 && item.row - 1 >= 0) {
return false;
} else if(grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0 && item.column + 1 < sizeof(grid.grid[item.row])) {
return false;
} else if(grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0 && item.column - 1 >= 0) {
return false;
}
}
return true;
}
Before it was working with the last version that I don't have anymore but might be in this channel, but this version is so useful bcs it prevent the player to put 2 blocks of different colors next to each other
Okay, but just knowing which function you suspect is the cause isn't very helpful as I don't have the ability to check which values the grid cells have, and so on. But you do, so please fire up a debugger. If you absolutely don't want to open a terminal you can follow a short online tutorial to learn how to use clion's debugger. But it's really hard for others to help you, you're way more capable to identify the issue than we all are :)
I'll try a debugger for sure
the debugger doesn't seems to change something will putting it on this function
When I try to put a block on the right or bottom of the grid I don't have anythig that is returned
Put int foo = 42; as your main function's first line and put a breakpoint on the line after it. You should be able to at least see the value foo 42 in the debugger if you run it till the breakpoint?
the only function in my main function that can be useful is the handleInput one, should I try with this ?
No, I am saying literally put that int foo = 42; line as the first line in your literal main() function
If I put it on the first line it doesn't seems to work because the main menu stills open and I can do everything as before
I deleted the line but it didn't work
Deleted which line? You should add, not remove, int foo = 42;
Make a screenshot showing you having added that as the first line in your main, and of you having set a breakpoint on the InitWindow line after it.
Wdym by didn't work specifically?
It works like before, not any change even with the breakpoint
Right, but in what manner are you starting your program right now? With a hotkey, or with an on-screen button?
oh I thought the breakpoint would work even with standard mode
yep
Try to step into functions using the debugger's keys that popped up
See if you can see all variables
You can click on vectors in the debugger's window to inspect them closer
Oh, and you can remove int foo = 42; now of course
So in the function should I put a breakpoint on each if ?
Idk where it would be the most useful
You don't necessarily need to put more breakpoints, they just allow you to continue running the program as normal until that breakpoint is hit, where the program will be paused
okay so i'll just try to put blocks on borders and see what is returned
I recommend creating a grid that is as small as possible that still shows of your problem you're having. That way you can step through every single line of executed code really quickly.
No, I recommend for now just stepping into every function call to get a feel for the debugger. There is the step over button to not go into a function call, and the step into button to go into a function call, that's all you need!
good luck ;p
But by stepping over function calls you can skip huge portions you're not interested in
the problem is with the size of the array i think, you hardcoded 30, but the actual size you're using is 20
so when you check if 20 is less than the size of the array it says true
But why did it work with the last code ? I coded 30 to have the max size, but I change it when I initalize the grid
so 2 options,
1 don't hardcode the size,
2 get the size of the grid as a constant which you can use in your function instead of the size
i don't understand the question
when we first started coding this, I could place blocks on the borders of the grid
but after we change some things, we resolved the other problem of blocks next to each other but created the one with borders
yes but now we are checking at +1,
like we have the grid 0 - 19
and we check the value in 20 which is undefined so we don't know what happens,
what i suggested was to omit the check when the box we were checking was out of the grid,
for that we used the size of the array
but the size of the array is actually 30 not 20, so when we check if the box in 20 is in the grid it says it is
but if I put it to 30, when i'll have the 30x30 grid it won't work ?
try it
forgot to tell you that I also have a 30x30 grid for 4-9 players
and it doesn't work in this either?
only on the bottom row
get those 2 numROws and numCols
use them here
instead of sizeof(grid.grid) / sizeof(int)) and sizeof(grid.grid[item.row])
Another thing that is immediately sus is that a line of code you shared here checks whether the index is in bounds last, rather than first. You should switch the order of checks so you first check whether the index is in bounds. :)
if(grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0 && item.row + 1 < sizeof(grid.grid) / sizeof(int))
And yeah, combine it with Luken's suggestion
that's luken's code 😂
You two work on this together as a group project I presume?
nope I work with @sinful anchor
well i did use an other if at first
Ah I see, but anyways Tenebres fix that
Luken's a very kind guy that's helpin me too
yup
im looking his computer when he's talking with you don't worry, he sits near to me
fck I don't have the numRows and numCols variables in this file
Pass it as an argument somehow
I don't understand how to do that to have something that works
create getter functions for them
I think that I did the error to create global variables for some variables in my code
Are the width and height globals?
they are private in grid
I'll say this one more time sorry but I really can't understand why it was working before
You can get unpredictable results when you have undefined behavior, like reading out of bounds, or many other reasons. It may have been because of that, but it doesn't really matter, all that matters is getting the current version working
Like if I don't put the function in the lockBlock, I can put blocks on the borders
If you want to understand why your program behaves the way it does, the best way is to just use the debugger and closely inspect the values. Right now you're kind of flying blind if you don't
I really hope that I will fix this today
Huh?
just do what we told you for now, it should work after that
Creating a getter ?
You told me too much things
guys I just discovered something
It works on some places but not on others, my red and dark green blocks are placed, but I couldn't place them on another place of the border, like I tried to put the red one on the left or right and it wasn't working
wtf is that
my orange block is placed too
Welcome to undefined behavior i guess
It can do strange things at this point ???
@humble pike So I need to do a Getter ?
.
.
okay thanks I'm doing that rn
Is this ok like this ?
I moved the numRows and numCols from private to public so I think it's easier to get them without a getter but with just an include
@reef crow Has your question been resolved? If so, type !solved :)
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(item.row + 1 < grid.numRows && grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0)
{
return false;
} else if(item.row - 1 >= 0 && grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0) {
return false;
} else if(item.column + 1 < grid.numCols && grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0) {
return false;
} else if(item.column - 1 >= 0 && grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0) {
return false;
}
}
return true;
}
Gonna invite you at my wedding
Can I ask you just 1 more thing about another function ?
yep
@reef crow curious, what are you working on?
Just a project like that, I'm bad in C and C++
That's exactly how you learn 🙂
I want to be in cybersecurity but sadly rn I don't have the choice to do some projects in C and C++, I'm autodidact so that helps but I really don't like C and C++, more specifically C.
yep i'll do that
I have this function to get all blocks in my game and I absolutely need to shuffle it and after that take all blocks one by one each turn but I struggle to shuffle it. Actually I have a function in which each turn the current player takes a random block in it, delete it from the vector and if it's empty, it takes back all blocks.
I would like to do the same but just to shuffle it one time before everything and each turn, so when the player change in the 3rd screen, take the next block.
std::vector<Block> Game::GetAllBlocks()
{
return {SmallLBlock(), TBlock(), SmallCrossBlock(), ZBlock(), SmallTBlock(), SquareBlock(), UBlock(), ThreeBlock(), LightningBlock(), SmallCornerBlock(), SmallStairsBlock()}; //Continuer de mettre le reste des blocs dont ceux qui se répètent plusieurs fois
}
Block Game::GetRandomBlock() //A remplacer par GetNextBlock()
{
if(blocks.empty())
{
blocks = GetAllBlocks();
}
int randomIndex = rand() % blocks.size();
Block block = blocks[randomIndex];
blocks.erase(blocks.begin() + randomIndex);
return block;
}
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
currentBlock.id = currentPlayer;
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = GetRandomBlock();
}
}
What version of C++ are you using?
et pourquoi as-tu besoin d'une fonction pour les blocs aléatoires?
Not entirely sure of the use there
i need to shuffle blocks just one time to get them in the order it is after the shuffle because I need to print the 5 next blocks on my screen.
I also need to add 1x1 blocks at the first turn for all the player to place their starting block with a specific condition, but if I take a random block in the vector each turn I won't have these 1x1 blocks at the first turn.
Like if there are 5 players, I'll need to add 5 1x1 blocks at the beginning of the list.
Actually I see the thing like that.
And my version might be 3.11
that's what I found in my cmake
i don't really understand what you're trying to do but you can read this https://stackoverflow.com/questions/6926433/how-to-shuffle-a-stdvector
the problem is that my vector is a function that returns it and I don't know how I can change it
oh okay so I can just shuffle blocks
yep
After the shuffle do you know how I can do to always have the next block in the list ?
I thought about
currrentBlock = blocks[currentBlock +1]
But not totally sure about that
there are some ways,
you can use a counter for the index of the block which you can put in your class,
#include <iostream>
class Yours {
private:
int counter = 0;
public:
void foo() {
std::cout << counter;
counter++;
}
};
int main() {
Yours y;
y.foo();
y.foo();
y.foo();
}
you can use a static int in the function and increment the int every time you enter the function,
like that
#include <iostream>
void foo(){
static int i = 0;
std::cout << i;
i ++;
}
int main(){
foo();
foo();
foo();
}
Okay, i'm actually creating the shuffle function but I don't know if it worked xD
Idk why but it seems that I can't print the vector, like the names in it
if I print names I could see if it really shuffled or not
how are you trying to print it
Trying different methods from chatgpt
you should be able to see the values too
if you expand cells
and expand whatever is inside again and again
you will have the positions of the boxs of that block
then you can interpret which forme it is
ye
you don't have to look at every single block just find the first 3 restart the game and make sure they are different
Nice, I only looked at the first one bcs the next ones are with GetRandomBlock()
so now I have to implement something to change the block
Just fyi, now you know debugger basics you're able to debug significantly harder problems than before in a much shorter time 🥳
It's great to see you able to use it to inspect values
Yeah I can see that I never really used it bcs I had such easy codes but rn it's pretty useful
Hello guys ! Sorry to bother you again but I'm still struggling with the block change after each turn, these are my 2 functions :
Game::Game()
{
grid = Grid();
blocks = GetAllBlocks();
shuffleBlocks();
currentBlock = blocks[0];
nextBlock = GetRandomBlock();
}
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
currentBlock.id = currentPlayer;
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = GetRandomBlock();
}
}
I have to delete the GetRandomBlock function to replace it by the next block in the vector, I have another function that prints the next block and I have to print the 5 next blocks but I don't know how I can always have the next block in the vector.
In the second function I tried with i++ and getting the next block with currentBlock = blocks[i] but it doesn't seems to work.
Actually it always take a random block after I play the first one
you shuffle every time you enter the function
oh nvm
its the constructor lmao
The Game::Game happens just one time I think because it doesn't get all the blocks every time
yep
can you send the code where you tried to use i++
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
currentBlock.id = currentPlayer;
int i = 0;
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
i++;
currentBlock = nextBlock;
nextBlock = blocks[i];
}
}
I might have lost msyelf on this one
in this code the declaration of i is in the function, so every time this function is called a new 'i' is created
-_-
so you will always get blocks[1] into nextblock
you can create an int in your class named nextBlockIndex or some, and use that instead of i
okay that sounds better
what do you do when all the blocks have been used btw?
do you restart at 0, or do you shffle again and restart at 0
Normally I have to implement some bonuses in my game and one is : you have to choose one of the next 5 blocks to replace the one you actually have, you continue at the new block index and previous blocks stays in the list. once all blocks are used, you come back to the beginning of the list and use the blocks you left before your new block
But I won't have time for this I think
int currentPlayer = 1;
int nextBlockIndex;
Game::Game()
{
grid = Grid();
blocks = GetAllBlocks();
shuffleBlocks();
for(int i = 0; i < numberOfPlayers; i++)
{
blocks.insert(blocks.begin(), oneBlock());
}
currentBlock = blocks[0];
nextBlock = getNextBlock();
}
Block Game::getNextBlock() //A remplacer par GetNextBlock()
{
nextBlockIndex ++;
if(blocks.empty())
{
blocks = GetAllBlocks();
}
}
void Game::LockBlock() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
currentBlock.id = currentPlayer;
if (BlockFits() && NearBlockCheck()) {
for (Position item : tiles) {
grid.grid[item.row][item.column] = currentBlock.id;
}
if (currentPlayer < numberOfPlayers) {
currentPlayer += 1;
} else {
currentPlayer = 1;
}
currentBlock = nextBlock;
nextBlock = getNextBlock();
}
}
I did that but it doesn't work
you need to initialise NextBlockIndex
I tried with 0 or 1 but my window close instantly when the game launches
you don't return anything from getNextBlock btw
return blocks[nextBlockIndex];
and int nextBlockIndex = 0;
at the top
If it still doesn't work you can try to debug the constructor
yep it works !
My brain is burning
I have to do the same thing that we did to avoid blocks touching each others while not the same id, but now I have to force the player to touch a block with the same id, conditions are the same but I can't see how I can do that.
It can be place on blocks or touch blocks with id 0, can't touch blocks with different id, but have to touch a block with same id...
I think with XOR conditions
try this
bool Game::isInGrid(int row, int column) {
return (row < 0 || row >= grid.numRows || column < 0 ||
column >= grid.numCols);
}
bool Game::isTouchingSameColor(int row, int column) {
return grid.grid[row][column] == currentBlock.id;
}
bool Game::isTouchingDifferentColor(int row, int column) {
return (grid.grid[row][column] != currentBlock.id &&
grid.grid[row][column] != 0);
}
bool Game::doChecks(int row, int column, bool &isTouching) {
if (isInGrid(row, column)) {
if (isTouchingDifferentColor(row, column)) {
return false;
}
if (isTouchingSameColor(row, column)) {
isTouching = true;
}
}
return true;
}
bool Game::NearBlockCheck() {
std::vector<Position> tiles = currentBlock.GetCellPositions();
bool isTouching = false;
for (Position item : tiles) {
if (doChecks(item.row + 1, item.column, isTouching) == false)
return false;
if (doChecks(item.row - 1, item.column, isTouching) == false)
return false;
if (doChecks(item.row, item.column + 1, isTouching) == false)
return false;
if (doChecks(item.row, item.column - 1, isTouching) == false)
return false;
}
return isTouching;
}
there might be errors correct them, you can change names etc
I'll try, the only problem is that now I have turns, because first turns i have to let what we implemented before with the NearBlockCheck, but since the 2nd round starts I have to implement this new rule
can't I just add something in the NearBlockCheck function to do this ?
Like this :
bool Game::NearBlockCheck()
{
std::vector<Position> tiles = currentBlock.GetCellPositions();
for(Position item: tiles)
{
if(turn == 1)
{
if(item.row + 1 < grid.numRows && grid.grid[item.row + 1][item.column] != currentBlock.id && grid.grid[item.row + 1][item.column] > 0)
{
return false;
} else if(item.row - 1 >= 0 && grid.grid[item.row - 1][item.column] != currentBlock.id && grid.grid[item.row - 1][item.column] > 0) {
return false;
} else if(item.column + 1 < grid.numCols && grid.grid[item.row][item.column + 1] != currentBlock.id && grid.grid[item.row][item.column + 1] > 0) {
return false;
} else if(item.column - 1 >= 0 && grid.grid[item.row][item.column - 1] != currentBlock.id && grid.grid[item.row][item.column - 1] > 0) {
return false;
}
} else {
}
}
return true;
}
So in the else, it's after the turn 1, so when I have to do what I said before
You can just put isTouching to true for the first round and leave it at false for the other rounds
If (turn == 1) isTouching = true;
try to debug it, i don't have much time rn
bool Game::isInGrid(int row, int column) {
return (row >= 0 && row < grid.numRows && column >= 0 &&
column < grid.numCols);
}
actually this was wrong
try with that
I'll try
if it still doesn't work and you're not comfortable with this code try to implement the method you were suggesting
Yep i'll check to do that
clion tells me that the isInGrid fct can be made const, what will it change ?
It should put const after the method, which means the this which is always secretly passed as the first argument to methods becomes const, meaning you can't modify member variables in that method anymore.
In my game.h it made me change it to this :
[[nodiscard]] bool isInGrid(int, int) const;
i've never seen this nodiscard thing
Damn I have one last thing to do, I have to calculate the biggest square/player and when the game is finished I have to print which player have the biggest square
Talk us through your thought process of how you'd do it, I'm sure you can figure it out
I should check all the grid, for that i'll do a for loop that'll check it for each player, if I have a block on the grid with the id of the player I'm checking I'll start checking for a square and this for each block. I'll have to compare all squares of the same player and take the largest, after that we'll switch to another player and compare both largest square.
The player with the largest square will be in a variable and we'll return this player to display it on the screen.
I have to finish it tonight
So I'm pretty nervous about that
I would see something like that :
for(each player)
for(board size)
if(board cell == player)
check square (I don't know how to actually do this)
stock it in a var to compare it with other players square but I have to associate it with the player that I'm checking for
after all of this done compare the squares between each players and take the largest which is associated to a player
return player
@regal monolith
or anyone else
Did you really just try to ping 31,195 people?
Did you figure it out or would you like a hint?
I would really like to have a hint bcs rn... I'm mental boom
Can you explain to me what makes one square "bigger" than another, cause if you can then that helps with writing code
And can each player have multiple, separate squares, or can every player only have one?
We'll check if every single blocks together makes a square, and bigger is like 4x4 bigger than 3x3, even if there is blocks around I only have to check squares
We'll only take the biggest square/player
.
?
Answer that one
Oh okay, they can have multiple squares but we have to compare to only take the biggest one
That's why we have to check square everytime we see a block of a player
Alright, so what if someone has this 2x3 shape:
XXX
XXX
Does this count as a 2x2 square, or does it not count as a square because the thing as a whole is a rectangle, so not a square?
2x2
Programming is not about writing code, but about thinking of all the edge cases
Yep, I thought abt that all the day
Okay, and this?
XX
XXX
Right, so you understand that we'll at the very least need a loop to count how wide it is, right?
Here is the last edge case, what size is this?
XXX
XX
X
Yup
it can be something like that :
XXXXX
X XXX
XXXXX
It will be 3x3
So the naïve and wrong approach would be this:
Yep because if there is a hole in the middle it won't work
Yup, so what we've learnt with this example is that you simply can't figure out what the largest square in it is, if you only check the top-left. Got that?
My naïve algorithm only checked the top-left.
So you'll have to check every block of the diagonal I think ?
Can you elaborate why? It might be right, I just need more
because it will check every block of the square I don't know how to explain it but top-left will be :
XXX
X
X
and diagonal will be :
XXX
XXX
XXX
bcs we check to the right and the bottom of the block we want to scan on
Okay, but if you only check the diagonals, see how in this case it would think the largest square is 2, rather than 3?
XX
XX
XX
XX
XXX
XXX
XXX
XX
XX
XX
XX
but if we check every block of the grid, it will find the 3x3 square after the verification
Yes, nice! "If we check every block of the grid" is the magic phrase I was trying to pull out of you :)
oh xD I had it since the beginning, I was already thinking about that, it's pretty normal for a verification
Yeah, but I didn't know you knew, so ;p
the "for(board size)" was meaning that but yep it wasn't very clear
But just checking the diagonals only still wouldn't be enough, cause what if you have this:
XX
XXX
XXX
If you say you loop over every tile in the grid and then check the diagonals growing down-right, then the tile at (0,0) would check tiles (1,1) and (2,2), and would conclude it's a 3x3 square.
yep you alo have to check the corners and go to right and bottom as you said before
I'm just going to say it more simply: you need to check every single tile, not just the diagonals and the corners.
yep said like that it's pretty simple
So basically, if you have this input:
XX
XXX
XXX
You start with growing a square out of (0,0):
%X
XXX
XXX
This worked, so the square's size is at least 1x1.
And then you have a loop that checks the column to the right of it, and another, separate loop that checks the row under it:
%%
%%X
XXX
This worked, so it's at least 2x2.
And it then tries to check the next column and row:
%%!
%%%
%%%
This fails at the !, as it isn't the player's tile, and so you return that the largest square you could grow from position (0,0) is 2x2.
Got an idea of how to program it now? :)
The important part is that you start from some point, in this case (0,0), but you do this for every other tile as well, and then keep adding another tile and row until you encounter a tile that doesn't belong to the player, or until you reach the edge of the map.
for me it would be :
for(i < board size)
for(j < board size)
for(k < board size && l < board size)
if(grid case != player.id)
return false;
Am I right ?
i think not xD
What does returning false here mean? Don't you want to return an int?
You know how to make a function, yes?
Alright, so do something like this:
def get_largest_player_square(player_id):
largest_size = 0
for y in height:
for x in width:
if grid[y][x] == player_id:
size = grow_tile(x, y, player_id)
if size > largest_size:
largest_size = size
return largest_size
def grow_tile(x, y, player_id):
# You can do this yourself with my earlier description ;)
Again, see this for how to implement that grow_tile function
But how can I create in the function something to say : that square blongs to this player
You're right, I edited it so it's passed in
You'd call get_largest_player_square() for every player ID
so : for(numberOfPlayers)
and you call get_largest_player_square
Assuming their IDs go like 0, 1, 2, ..., then yes
I am presuming you have a 2D grid that has a player ID for every value, where -1 means no player or something
okay, and my final question (maybe not the last we'll see 😅), in the grow_tile, how can you associate the player to its square to compare it to others square.
0 are empty cases, 1 are player 1's cases, etc.
So you're saying that no player can have ID 0, or in other words that player IDs start at 1?
No, that's absolutely fine! Just checking :)
oh okay !
So the goal of get_largest_player_square() is that you give it a player ID, and it returns you what that player ID's largest square is. So if you call this in a loop, you can track which player had the largest one and print that.
get_largest_player_square() doesn't loop over other players
For the player I only have currentPlayer where I can do currentPlayer.id
Should I create another variable or is it correct to use this one ?
get_largest_square_of_player() would be a better name, I'd use that
In which spot/function would you create that variable?
Or are you referring to making player_id a function argument? Cause that's what my Python code recommends
I don't know... If I do it it would be in the second function bcs it's the one in which i'll do a loop changing the player everytime to check squares
Can you give the name of the "second" function, idk what you're referring to
I don't even have currentPlayer.id, just currentPlayer which is equal to the id after all. Like I use it to get currentBlock.id
currentBlock.id = currentPlayer
grow_tile
So notice how get_largest_player_square received player_id as an argument, and it passes it along to grow_tile() so you also have access to player_id in there?
player_id is passed as an argument in both functions, because that's how they work
makes sense?
yep, but like for the player id I'm using currentPlayer, which is the player actually playing
If I do it it would be in the second function bcs it's the one in which i'll do a loop changing the player everytime to check squares
The point is that neither get_largest_player_square() nor grow_tile() loop over the players! The idea is that you do this instead:
largest_player_size = 0
for player_id in player_ids:
size = get_largest_player_square(player_id)
if size > largest_player_size:
largest_player_size = size
print(f"Player {player_id} had the largest square size of {largest_player_size}")
You want to print the largest square size, along with which player id's square that was, right? That's what this does
Yes totally but what I want to say is that we have to increment the id we're checking everytime, so player_id would be a new variable that we increment after every check of the full board
i'll try something
I maybe have a cool idea
Yes, so you mean this, right?
largest_player_size = 0
player_id = 0
while player_id < player_count:
size = get_largest_player_square(player_id)
if size > largest_player_size:
largest_player_size = size
player_id += 1
print(f"Player {player_id} had the largest square size of {largest_player_size}")
Yeah, that's what I meant, I just wasn't sure whether it'd be possible for a player to drop out of the game so wrote for player_id in player_ids: to be sure
i'm tired
no worries
Send the whole function by copying the function's code in a code block like so:
The c makes sure it has nice C colors
The ` key is called the backtick and is to the left of your 1 key
int Game::getLargestSquareOfPlayer(int playerId) {
int largestSize = 0;
for(int i = 0; i < grid.numRows; i++) {
for(int j = 0; j < grid.numCols; j++) {
if(grid.grid[i][j] == playerId) {
int size = getSquare();
if(size > largestSize) {
largestSize = size;
}
}
}
return largestSize;
}
}
int Game::getSquare(){
int largestPlayerSquare = 0;
int playerId = 1;
while(playerId <= numberOfPlayers) {
int size = getLargestSquareOfPlayer(playerId);
if(size > largestPlayerSquare) {
largestPlayerSquare = size;
}
playerId += 1;
}
return largestPlayerSquare;
}
Right, so it's complaining about getLargestSquareOfPlayer()
I have orange warning all over these, I put the functions in public bcs I have to access it on my main file
Take a veeery close look at it
that's strange bcs If I put my fct in private they don't have all of these warnings
only largestPlayerSquare and playerId
in the getSquare one
That's not right though, it should be public if you want to call it outside of the class
Look closely at getLargestSquareOfPlayer()'s return statement, something's wrong with it
yep but when I put them in public them have a lot of warnings
Well that's what you want because the warnings are correct, the function's code isn't correct
the return isn't at the good line I think, it's in a for loop
Yes!
wtf I have an unreachable code on the largestSize = size line in the getLargestSquareOfPlayer
hmm, that's strange, cause the code you sent is fine
can you send a screenshot of the error
same for largestPlayerSquare = size in the other function
Just so you can see all my other warnings
So the first thing you want to do is add the methods to the class its header, cause I am pretty sure that's what might be causing the lines under the method names
So add them as declarations
well then hover over this orange line to get info
it doesn't tell me anything on this one, just a clang-tidy
can you screenshot the clang-tidy? I'm curious
ah
so tell me, what function are you calling inside getSquare()?
And tell me, what function are you calling inside getLargestSquareOfPlayer()?
oh
hehe
nice recursive loop xD
don't just ignore the clang-tidy, it could've saved you a lot of time
yep I always check warnings
How could I break this recursive loop ? I know that it's in the getLargestSquareOfPlayer(), but what should I put to replace getSquare() ?
good question, it'll be this unimplemented function that I tasked you to write :)
oooooh okay
See this for a basic description of how it'll work
Basically I'll need playerId
And an x and y to grow down-right from, hence def grow_tile(x, y, player_id):
Maybe def grow_tile(top_left_x, top_left_y, player_id):
yep, I can just use i and j that I defined before for the loop
yup! exactly
I do recommend replacing the names i and j with x and y, since I have absolutely no clue without carefully inspecting your code whether i means x or y
i is x and j is y
but I have a really hard time remembering that
x and y are more logical like in maths but idk why they always learn this to us in french university or schools when we code
it's natural to start a single loop with i as it just means index, but when you add another dimension it makes more sense to go with x and y, and if you add a third dimension of course x, y, z
yep totally
so minecraft of course lists block positions as x, y, z instead of i, j, k in the F3 debug menu
I recommend applying the same logic in your case, renaming i and j to x and y
yep that's logic af, but I never think about that bcs they always tell us to use i j k l m etc for loops
well I am telling you your teacher sucks xD
you don't have to change it if you don't want to, but people are more likely to ask why you used i and j than asking why you used x and y
"good" code is all about the details
And you're totally right
If we think with x and y, can you explain me what is wrong with it plz ?
I usually initialize i and j in the for loop but they are already initialize that's why Idk how I can do that
wait, but the getSquare() you wrote here already seemed correct?
or did you move the code inside it to a different fn?
I just changed the name don't worry
ah ok, good
this getSquare is the grow_tile you were speaking
so you initialize the squaresize to 0, which is good, as you'll be returning that at the end of the function
after all, you want this function to return an int, right? so do that
so right now you have a for-loop inside of a for-loop, but note how I said separate, so in other words the for-loop for the column shouldn't inside of the one for the row:
And then you have a loop that checks the column to the right of it, and another, separate loop that checks the row under it:
but what can I return in both loops ?
moreover my i and j in my both loops are in grey which means they are not used but why
I can do i = i and it seems to work but it's pretty dumb xD
So the numbers at the top indicate how many rows and column out from the top-left you're checking
The green crosses are done in a single loop, and after that the orange crosses are done in another loop
If the green or orange (column or row, respectively) loop tells you there is a tile in it which doesn't belong to the player, or if the row/column would lie outside the map, you immediately return the squareSize in your function
So you do the green and orange loops in an infinite while(true) to keep growing the square
At the end of every while-loop you increment squareSize by 1. squareSize is that blue number I wrote at the top that indicates how many columns and rows to go out from the top-left
but both for loops are empty now, should I return something in both ?
If the green or orange (column or row, respectively) loop tells you there is a tile in it which doesn't belong to the player, or if the row/column would lie outside the map, you immediately return the squareSize in your function
i don't really understand how it is possible bcs both for loops are independant
You can have multiple places where you return from a function inside of a single function!
It is often very useful to not only return at the end
though you can also probably figure out a way to only return at the end if you really wanted to
int Game::getSquare(int i, int j) {
int squareSize = 0;
while(true){
for(i; i == playerId; i++) {
if(grid.[i] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
for(j; j == playerId; j++) {
if(grid.[j] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
squareSize ++;
}
}
smth like this ?
almost! :)
notice how in this picture both the green and orange loops are always at the same offset from the top-left, namely the blue squareSize number at the top?
my brain's burning
I'm between both, like a bit of yes and a bit of no
I can see it but not fully understand how I can do it
that's understandable, when you're beginning with programming it's normal to struggle with translating loop ideas into actual code
this'd be infinitely easier for me to explain if you renamed stuff to use x and y, could you pretty please do that?
int Game::getSquare(int x, int y) {
int squareSize = 0;
while(true){
for(x; x == playerId; x++) {
if(grid.[x] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
for(y; y == playerId; y++) {
if(grid.[y] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
squareSize ++;
}
}
tadaaa
ty! ❤️
Here
So what (x, y) coordinate is this green x at, assuming the top-left gray dot is at (x=0, y=0)?
yep I understand that
it was a question ;p
well, with for(x; x == playerId; x++) { the x; doesn't do anything
you can just remove that x
same for the y loop
I'd personally turn it into a while-loop instead of doing for(; x == playerId; x++) though
nah, you would keep the ;
Okay I just learned a new functionnality of c++
an expression that ends with a ; (semicolon) is called a "statement" btw
I didn't that you could write nothing and still put a ;
so a single line of code like this:
int foo()
{
int a = 1;
int b = 2;
a += b; return a;
}
would return 3, and we'd say that the line a += b; return a; contains 2 statements
and yeah, empty statements are always valid:
int foo()
{
int a = 1;
;
int b = 2;
;
a += b; return a;
;
;
}
int foo()
{
int a = 1;
;;;;;
int b = 2;
a += b; return a;
}
this contains a bunch of empty statements, you see
okay I understand now
adding them is like adding comments, they don't compile to anything
but for-loops require two semicolons in their condition
yep I didn't think it was a must have
so 1 character shorter than while(1) is actually for(;;), which you'll recognize quite often now that I told you to look out for it
using it is a sign of understanding
but it's also not very beginner friendly ;p
totally
so okay, your X check starts at the right value, but you don't check whether your x value is going out of bounds (OOB), so out of the map
and your x == playerId condition there doesn't make much sense, as the x position has nothing to do with player IDs
is it better like this ?
if(grid.grid[i][j] != playerId || grid.grid[i][j] > grid.numRows) {
close, but you want that second check inside of the for-loop's condition instead
the current for-loop's condition doesn't make sense after all
and you'll want to flip the > to be < then of course
Yep I just saw that
for(;grid.grid[i][j] < grid.numRows; i++) {
if(grid.grid[i][j] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
grid.grid[i][j] < grid.numRows is equivalent to id < grid.numRows, which doesn't make sense ;p
Another hint: in the code you sent here your function gets the top-left x and top-left y of the square and you call it x and y, and then inside of those for-loops you edit those x and y.
The problem with that is that you'll need to restore the x and y values to the top-left corner with a new squareSize offset every while-loop, which is now impossible as you edited the function's x and y arguments.
So rename them to int Game::getSquare(int topLeftX, int topLeftY) {, and then do for(int x = topLeftX + squareSize; x < grid.numCols; x++) {
I am not sure whether it should be [x][topLeftY] or [topLeftY][x] since it depends on how you initialized your grid
and instead of topLeftY you'll want to put some other value there, look at my pics closely for inspiration
void Grid::initialize()
{
for(int row = 0; row < numRows; row++)
{
for(int column = 0; column < numCols; column++)
{
grid[row][column] = 0;
}
}
}
I initalitzed it like that
okay, so [y][x], got it
same lul
why x can't be rows 😭
make sure to read this
why ? Isn't topLeftY in this not good ?
for(int x = topLeftX + squareSize; x < grid.numCols; x++) {
if(grid.grid[x][topLeftY] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
try to visualize in your head or on a piece of paper if you want what that loop is doing now
also pls rename that i to x again ty
ups you didn't see anything
it's like that everywhere in my code and I don't have much time left to rename it now
I prefer finishing these functions first
try to visualize in your head or on a piece of paper if you want what that loop is doing now
take a toilet break and grab a cup of coffee/tea or whatever and give yourself the time to mull it over
I don't have the time 😅
I need to finish this before 00:00 and have to write a technical documentation for it
school experience be like
sadly yes
I'm on this project since 3weeks and worked almost everyday but struggling a lot
but for real, you can definitely spare a few minutes to look at what those literal 6 lines of code are actually saying, cause it's kind of dumb haha
try to execute the code line by line in your head including looping back around, pretending like you are a computer
The x loop here is the orange crosses
I'd make sure you get the x loop right first, and then copy-paste and edit that into the green crosses y loop last
so the problem is in the if
I have to exchange the x and topLeftY values
topLeftY in red
think about whether you really meant to use that here
and if so, maybe in a different way
the goal is to produce the orange coordinates
so it's squareSize instead of topLeftY
and my bad, x < grid.numCols isn't correct either LUL
<=
no matter how wide the grid is (numCols), you want to limit how many orange checks you do here with the squareSize
whereas rn x < grid.numCols would try to make orange crosses in a loop until the right edge of the map is reached
but we want to stop it
we do, so we do need the check in order to make sure we don't cross the edge, that's true
but you'll need to use the AND statement && in order to do a second check in that for-loop's condition
so the < was correct ?
yes, x < grid.numCols && ??, where you need to put something instead of ??
the first condition checks whether it's in bounds, the second whether you've slid off the bottom edge of the new square size
so it would be something with a comparison with x and the squareSize
so if the grid is 3x3, and you're checking whether a squareSize of 1 is valid, you want this
instead of only your current condition which is this
x < squareSize + 2 ? Like you want to only check one time for the squareSize + 1
I realized that the initialization of x was also wrong, and I misled you by saying that only the condition was wrong, so have the final, correct version as my apology
for(int x = topLeftX; x < grid.numCols && x < topLeftX + squareSize; x++) {
the x < topLeftX + squareSize is because if the squareSize is 2 you only have 2 orange checks
so + squareSize + 1
and make sure you remember to correctly change everything if you are going to literally copy-paste it
Don't worry I wrote it correctly
can you send me your current code?
int Game::getSquare(int topLeftX, int topLeftY) {
int squareSize = 0;
while(true){
for(int x = topLeftX; x < grid.numCols && x < topLeftX + squareSize; x++) {
if(grid.grid[x][topLeftY] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
for(int y = topLeftY; y < grid.numRows && y < topLeftY + squareSize + 1; y++) {
if(grid.grid[topLeftX][y] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
squareSize ++;
}
}
You have if(grid.grid[x][topLeftY] != playerId) { here, but remember how this Grid::initialize() of yours is [row][column], aka [y][x]?
so it's topLeftY first and x second
yes
but not topLeftY ;p
you have to add smth to it
if the red top-left tile is at Y=10, what Y value is the orange at, and how can you calculate it?
int Game::getSquare(int topLeftX, int topLeftY) {
int squareSize = 0;
while(true){
for(int x = topLeftX; x < grid.numCols && x < topLeftX + squareSize; x++) {
if(grid.grid[topLeftX + squareSize][x] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
for(int y = topLeftY; y < grid.numRows && y < topLeftY + squareSize + 1; y++) {
if(grid.grid[y][topLeftY + squareSize] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
squareSize ++;
}
}
grid.grid[y][topLeftY + squareSize] is nearly correct but not quite
remember, [y][x]
and the same for your grid.grid[topLeftX + squareSize][x]
i'm lost
so you know how if you want to access (y=3, x=5) in your grid you have to do grid.grid[3][5] and not grid.grid[5][3], because your grid was initialized as grid[y][x]?
look at this for reference, you do grid[row][column] = 0; aka grid[y][x] = 0;
So I have to reverse them ?
that's not what I'm saying, I am just asking if you get this or not
if not that's okay too, I just need to know
so you get it's [y][x]?
yep
okay, well you're doing grid.grid[topLeftX + squareSize][x]
mighty strange to see the letter X in the first brackets, eh?
so topLeftY + squareSize
yup
and you made the same mistake in the other loop, so check that too
just remember, [y][x]
yep that's corrected
I misunderstood bcs I asked you If I had to correct like it was and you told me yes
yeah my bad, when I said "but not topLeftY ;p - you have to add smth to it" I meant that it should still be topLeftY, but that it alone isn't enough and that you needed to also add squareSize to it :)
Yep, now I understand but on the moment I was lost
So the function should be finished no ?
can you send the current version?
int Game::getSquare(int topLeftX, int topLeftY) {
int squareSize = 0;
while(true){
for(int x = topLeftX; x < grid.numCols && x < topLeftX + squareSize; x++) {
if(grid.grid[topLeftY + squareSize][x] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
for(int y = topLeftY; y < grid.numRows && y < topLeftY + squareSize + 1; y++) {
if(grid.grid[y][topLeftX + squareSize] != playerId) {
return squareSize;
} else {
squareSize ++;
}
}
squareSize ++;
}
}
Bcs I have some problems on the other functions we wrote 🥲
thanks. so it's almost correct, but look more closely at how many places you're doing squareSize++;, and think about which of those is/are wrong
the wrong one for me is the last one, bcs it will increase the squareSize a 2nd time after the for-loops
try to keep in mind that the first for-loop is adding the orange Xes here, and the second for-loop is adding the green Xes here, and that the squareSize in blue at the top is a constant 2 for this entire screenshot
yep I lost myself, the both elses are bad, because it increases squareSize each time it's correct
int Game::getSquare(int topLeftX, int topLeftY) {
int squareSize = 0;
while(true){
for(int x = topLeftX; x < grid.numCols && x < topLeftX + squareSize; x++) {
if(grid.grid[topLeftY + squareSize][x] != playerId) {
return squareSize;
}
}
for(int y = topLeftY; y < grid.numRows && y < topLeftY + squareSize + 1; y++) {
if(grid.grid[y][topLeftX + squareSize] != playerId) {
return squareSize;
}
}
squareSize ++;
}
}
all you need to do to shut up the compiler about the function never returning a value at the end of it is adding abort(). This tells the compiler "this is impossible"
assert(false) also works
I'm really sorry about that, but others functions have a problem 😭 , especially the playerWithLargestSquare
no worries
But you don't know how thankful I am actually
I was also helped by others, just pay it forward by helping others some day
show me the next issue
And both of the orange warnings are : shadows of variable in the global namespace
use the search tool to see where those variables have already been defined
the magnifying glass button
nevermind I'm just dumb, forgot that if I already initialized it in my global file I don't have to put int before
so the only thing left to do is to return both of the variables
so you are keeping these two variables, right?
yep these are corrected
what had to be changed with them?
delete the int x)
oh I see what you said, nvm me I'm dumb
okay fair enough, but why did you have them as globals as well?
I recommend using globals as little as possible
okay well keep in mind next time that globals are bad
cause they allow cross-contamination, making debugging way harder if a variable can be edited by loads of places
so since this is C++ and not C, you can just return a std::pair<>, instead of creating a struct specifically for those two variables and returning such a struct
to return both ?
Yeah I just want these 2 variables to print them on my screen in my main file
well you might as well just print them right here then, right?
makes things easiest
Nope bcs it's with a drawText that I have in my main file
I already have the players and turns etc.
ahh ok, well then look at this example:
#include <iostream>
#include <tuple>
int main()
{
std::pair<int, double> p2(42, 3.1415);
std::cout << p2.first << std::endl; // 42
std::cout << p2.second << std::endl; // 3.1415
}
pairs are basically shorthand for defining a struct containing exactly two values
I'll try that
(and when I say struct, remember that a struct is the same as a class)
but there isn't a way to just have 2 returns or something to do the same ? Or is it only pair ?
if you have a return statement the function is immediately exited, there is no way to do a return directly after another return unfortunately
hence std::pair
okay okay
(these are good things to mention in technical documentation, if you want to explain your thoughtprocess)
how should I use that in another file ? p2. first doesn't work
send code so I can know what you did
int Game::playerWithLargestSquare(){
largestPlayerSquare = 0;
playerId = 1;
while(playerId <= numberOfPlayers) {
int size = getLargestSquareOfPlayer(playerId);
if(size > largestPlayerSquare) {
largestPlayerSquare = size;
}
playerId += 1;
}
std::pair<int, double> results{playerId, largestPlayerSquare};
}
in my first file
char winText[60];
sprintf(winText, "Le joueur %d ", playerId, "a gagné avec un carré de %d", largestPlayerSquare, "x", largestPlayerSquare);
in my second file
right, and then you want to return that
#include <iostream>
#include <tuple>
std::pair<int, double> foo()
{
return std::pair(42, 3.1415);
}
int main()
{
std::pair<int, double> p = foo();
std::cout << p.first << std::endl; // 42
std::cout << p.second << std::endl; // 3.1415
}
because results.first doesn't work
Make sure you have #include <tuple> in all .cpp files you're doing stuff with tuples
And use this code snippet as reference
well yeah because it doesn't know results
This works in separate files ?
sure
oh
but std::pair is a function, so I can't do it in my function which I want to return values
std::pair() returns a pair, which is a value
just look at this example, I'm doing the exact thing you are trying here
the thing I don't understand is that you create a function that you call foo in which you put the values, but if I don't return the values in my playerWithLargestSquare how can I get'em
This:
std::pair<int, double> foo()
{
return std::pair(42, 3.1415);
}
is basically what you would've tried like so, but doesn't work:
int, double foo()
{
return 42;
return 3.1415;
}
foo() is a function returning two values, but they are packed inside of a std::pair in the actual working version
yes but you created a pair function
no, it's from the standard library
and I can't create a function inside a function
it's a container, just like std::vector
int Game::playerWithLargestSquare(){
largestPlayerSquare = 0;
playerId = 1;
while(playerId <= numberOfPlayers) {
int size = getLargestSquareOfPlayer(playerId);
if(size > largestPlayerSquare) {
largestPlayerSquare = size;
}
playerId += 1;
}
std::pair<int, double> results{playerId, largestPlayerSquare};
}
so in here I can create what you did before ?
my function foo() here is your method Game::playerWithLargestSquare()
compare your code with the example
so it would be :
std::pair<int, double> Game::playerWithLargestSquare()
yes! though in your case you will want to change that double to int as well I think
yep
since you're trying to return two ints, right? cool
the first screenshot is saying you are making a variable called results and aren't doing anything with it in the function
which is correct, refer to my example where I just outright return it without ever making a results variable in the foo() function
okay no error left on this but when I try to launch the game i have an error
ooh, okay, progress!
run it with the debugger button and it should tell you which line it had that issue on, cause by pressing the run button as you did here you get 0 debug info
can you screenshot more, that thing is super cropped
maybe the entire screen even
[1/1] Linking CXX executable C++Project.exe
FAILED: C++Project.exe
cmd.exe /C "cd . && C:\PROGRA~1\JETBRA~1\CLION2~1.2\bin\mingw\bin\G__~1.EXE -g CMakeFiles/C++Project.dir/main.cpp.obj CMakeFiles/C++Project.dir/position.cpp.obj CMakeFiles/C++Project.dir/grid.cpp.obj CMakeFiles/C++Project.dir/colors.cpp.obj CMakeFiles/C++Project.dir/blocks.cpp.obj CMakeFiles/C++Project.dir/block.cpp.obj CMakeFiles/C++Project.dir/game.cpp.obj -o C++Project.exe -Wl,--out-implib,libC++Project.dll.a -Wl,--major-image-version,0,--minor-image-version,0 _deps/raylib-build/raylib/libraylib.a -lopengl32 -lglu32 -lwinmm _deps/raylib-build/raylib/external/glfw/src/libglfw3.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Program Files\JetBrains\CLion 2023.2.2\bin\mingw\bin/ld.exe: CMakeFiles/C++Project.dir/game.cpp.obj:game.cpp:(.rdata$.refptr.largestPlayerSquare[.refptr.largestPlayerSquare]+0x0): undefined reference to largestPlayerSquare' C:\Program Files\JetBrains\CLion 2023.2.2\bin\mingw\bin/ld.exe: CMakeFiles/C++Project.dir/game.cpp.obj:game.cpp:(.rdata$.refptr.playerId[.refptr.playerId]+0x0): undefined reference to playerId'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
hmm rip
lol no bro I just meant rip about it not giving helpful errors
mingw is ass, I had a similar issue with it yesterday and just said fuck it and used ubuntu instead of windows lmao
anyways, try setting a breakpoint on the first line inside your main() function, and press the debug button to run it till that line. does it crash before it reaches that breakpoint?
Is it linked ? I think not, just trying to search
I need bigger screenshots man
so are you trying to print something like Le jouer 42 a gagne avec un carre de 69 x1337?
It would be like, The player 5 won with a square of 3x3 for example
yeah, this is indeed a wrong use of sprintf(), you'll also want to fix any other spot you use it
sorry didn't show you the entire thing
I use it in the else
fck 20mins left and my code won't start
Ah ok no worries, so instead of using sprintf I highly recommend doing this instead. It's way safer and you can put the values in between the strings like you wrongly tried to do with sprintf():
#include <iostream>
#include <sstream>
int main()
{
std::stringstream ss;
ss << "hello " << 42 << " world" << std::endl;
std::cout << ss.str(); // prints "hello 42 world\n"
}
Just chill and accept that you won't hand it in on time
I can't x), the thing will maybe close
I know how it is, I also always handed things in at the very last moment
well still, you can whine or w/e
And I tried to put a breakpoint on the first line in my main
It remains the same thing while not launching anything
probably because of the sprintf misuse
but it worked with others
this is the c++ way to do it, way safer and more readable too
yeah but in this case you misused it, so I'd change it in the other spots too for consistency and because you can never be sure with sprintf
you don't need to create an array with an arbitrary limit of 60 like you did with char winText[60]; either
if that overflows your program can easily crash or even get hacked, though I get that's not top priority rn
don't forget the .str()
nvm
yeah okay so get rid of the %d in the string that you left on accident first of all
yep
second of all I don't think you want that std::endl in the string
maybe you do, but I suspect not
did it
okay, and because it's apparently a C function that expects a char * and not a std::string &, you'll need to use .str().c_str() to get its underlying char *
okay so no more error on this but the code still doesn't work
in what sense
the big terminal error
.
this same one?
ok
yep
yeah so with clion's magnifying glass look for the mentions of largestPlayerSquare
give it a different name in the function then if you want to use the same name for the global
just rename it to playerId_ or smth
so I put it too in the if ?
yes
as you can see I only have these 2
I also have playerId in playerWithLargestSquare but it's the global fct that I want to retun
I think the compilation is failing because you might have a Makefile or ninja build system or something that you forgot to add your new .cpp files to