Using 2D-array as a workspace - c++

I am working on a snake game and made a prototype. I have attached the code. It may not be so good but still it is messy. I could make it move but I don't know why the lower bound region is flickering. How to reduce this overall flickering, which almost makes me dizzy? Also, one more question: How to make the character move (like in the original snake game), not wait until my command? Please help me! Sorry for the language.
#include<iostream.h>
#include<stdlib.h>
#include<windows.h>
int main() {
char a[25][80]={0};
system("Color 0");
int x=40,y=15;
int m=0,n;
a[16][2]='X';
a[y][x]='O';
for(int i=0;i<25;++i) {
for(int j=0;j<80;++j) cout<<a[i][j];
}
while(m!=1000) {
Sleep(70);
if(GetAsyncKeyState(VK_LEFT)) {
a[y][x]=0;
x--;++m;a[y][x]='O';
}
if(GetAsyncKeyState(VK_RIGHT)) {
a[y][x]=0;
x++;
++m;
a[y][x]='O';
}
if(GetAsyncKeyState(VK_UP)) {
a[y][x]=0;
y--;
++m;
a[y][x]='O';
}
if(GetAsyncKeyState(VK_DOWN)) {
a[y][x]=0;
y++;
++m;
a[y][x]='O';
}
system("cls");
for(int i=0;i<25;++i) {
for(int j=0;j<80;++j) cout<<a[i][j];
}
}
}
return 0;
}

Youve chosen a graphics rendering method which nobody ever planned to be flicker-free. You need to draw graphics to a window, or learn how to use the windows console functions. Considering your tight timetable, I suggest you just ignore the flickering.
To make the snake continue to move, remember the last direction the player moved the snake; if there is no key pressed, then move that direction.
Your code doesn't compile as-is. Practice copying and pasting harder (copy it back out of stackoverflow into your compiler to make sure it works)

to overcome on flickering you have to reduce your system ("cls") time. and after one turn, your code is not giving other feed for snake. make it in loop.
and also make boundary wall of your map so that one can understand scope of map. and when you press any movement key, you have to run loop for its movement so that it move continuously .Hope that will help.

You can partially avoid flickering considering that you can draw your "screen" without clearing it before. For example, in the windows console environment (which apparently you are using), this function can be used to clear the screen instead of system("cls"):
void clear_screen ( void ) {
DWORD n; /* Number of characters written */
DWORD size; /* number of visible characters */
COORD coord = {0,0}; /* Top left screen position */
CONSOLE_SCREEN_BUFFER_INFO csbi;
/* Get a handle to the console */
HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo ( h, &csbi );
/* Find the number of characters to overwrite */
size = csbi.dwSize.X * csbi.dwSize.Y;
/* Overwrite the screen buffer with whitespace */
FillConsoleOutputCharacter ( h, TEXT ( ' ' ), size, coord, &n );
GetConsoleScreenBufferInfo ( h, &csbi );
FillConsoleOutputAttribute ( h, csbi.wAttributes, size, coord, &n );
/* Reset the cursor to the top left position */
SetConsoleCursorPosition ( h, coord );
}
Reading the code, you can notice that it overwrites the screen with enough spaces and then resets the cursor position to the top left position. So, instead of blanking the screen and then drawing the strings, we can set the cursor at the origin and then write our string, which already contains spaces.
Moreover, we can use a mono dimensional null terminated array of char, big enough to represent the whole screen. You use a size of 80x25, but in Windows the console is bigger (at least mine is ~100 char wide), so I'll consider a size of 81x25 putting a \n in the extra char of every row. So I end up with this:
void update_screen ( char *buffer )
{
COORD coord = {0,0}; /* Top left screen position */
/* Get a handle to the console */
HANDLE h = GetStdHandle ( STD_OUTPUT_HANDLE );
/* Reset the cursor to the top left position */
SetConsoleCursorPosition ( h, coord );
/* Draw the screen buffer */
cout << buffer;
}
To make your character move you have to update its position every time you draw it and change direction of movement only when a key is pressed. It's better to check for bounds collision too, at least to stop the game:
#include<iostream>
#include<stdlib.h>
#include<windows.h>
#include<string>
using std::cout;
using std::string;
const int scr_rows = 25;
const int scr_cols = 80;
constexpr int buf_rows = scr_rows;
constexpr int buf_cols = scr_cols + 1;
constexpr int buf_size = scr_rows * buf_cols;
void draw( char *buf, int x, int y, char c) {
// warning, unchecked out of bounds;
buf[y * buf_cols + x] = c;
}
char value_at( char *buf, int x, int y ) {
// warning, unchecked out of bounds;
return buf[y * buf_cols + x];
}
int main() {
// initialize buffer
char screen[buf_size + 1];
for ( int i = 0, pos = 0; i < scr_rows; ++i ) {
for ( int j = 0; j < scr_cols; ++j ) {
screen[pos] = ' ';
++pos;
}
screen[pos] = '\n';
++pos;
}
screen[buf_size] = '\0';
clear_screen();
int x = 40, y = 15;
draw(screen, 2, 16,'X');
draw(screen, x, y, 'O');
int vx = -1;
int vy = 0;
bool victory = false;
while( !GetAsyncKeyState(VK_ESCAPE) ) {
Sleep(100);
if (GetAsyncKeyState(VK_LEFT)) {
vx = -1;
vy = 0;
}
if (GetAsyncKeyState(VK_RIGHT)) {
vx = 1;
vy = 0;
}
if (GetAsyncKeyState(VK_UP)) {
vx = 0;
vy = -1;
}
if (GetAsyncKeyState(VK_DOWN)) {
vx = 0;
vy = 1;
}
draw(screen, x, y, ' ');
x += vx;
y += vy;
// check bounds
if ( x < 0 || x >= scr_cols || y < 0 || y >= scr_rows )
break;
if ( 'X' == value_at(screen, x, y) ) {
victory = true;
break;
}
draw(screen, x, y, 'O');
update_screen(screen);
}
if ( victory )
cout << "\n **** You win! ****\n";
else
cout << "\n **** You loose! ****\n";
return 0;
}

Related

Need A Bit Of Assistance With My First C++ Program (Simple)

I've begun into C++ from a heavy C background. This is my first program, which I'm using as a learning experience. A simple Snake Game. Everything runs smoothly, the only issue is that no matter what I do, after the players score reaches 4, the next bit of food is ALWAYS spawned inside of the wall, in the bottom left corner (1 row up from the bottom.) Running into it = Game Over.
This is running on a Linux server. I've tried messing with the border parameters, but I'm having a hard time figuring out what to change, because everything looks fine to my eyes. (Clearly something is not.)
I'm pasting the entire program below. It's quite short. I just need one of you guru's to read through/run the program and take me to school on something that's probably a simple fix. Pardon the excessive comments. I use these to teach (I have a following on pastebin as odd as that is to say)
/*
Snake Game - Tragedy
My First Program In C++
I'm Using This Much As A Learning Experience For Myself
And Would Like To Help Those Reading The Code For This Goofy Game
Understand C++ A Bit Better Too
Therefore I'm Trying To Explain As Much As Possible In Real Time
*/
#include <iostream> //Standard
#include <stdlib.h> //Standard
#include <unistd.h> //For POSIX Access
#include <sys/ioctl.h> //For Display Window, TTY Window (Console Window)
#include <termios.h> //For Line Buffering - See Below
#include <stdio.h> //Old Friend
#define CLRSCR "\e[1;1H\e[2J" //Command To Clear Terminal Screen - Change Accordingly
using namespace std; /*
A NameSpace Is Used As Additional Information
To Differentiate Between Similar Functions/Variables
That Have The Same Name In Different Libraries
Using 'namespace' You Can Define The Context
In Which Names Are Defined
Withoug Using The STD NameSpace, The Computer Will Try
To Call cout Or cin As If It Weren't Defined In A NameSpace
Trying To Call Something That Doesn't Exist = Error
So, Without Using namespace std; When You Write For Example:
'cout << value;' You'd Have To Write 'std::cout << value;''
*/
//Create Boundaries
const int width = 50;
const int height = 25;
const char block = 'o';
void ClearScreen(void)
{
cout << CLRSCR;
}
//Global Arrays For Data Records
int background[height][width]; // Background
int snake[50][2]; // Max Snake Length
int food[2] = {0,0}; // Snake Food
int score = 0; // Score
int snakelen = 3; // Snake Starting Length
int snakespeedx = 1; // Horizontal Speed
int snakespeedy = 1; // Vertical Speed
int lap = 200; // Waiting Time Betweeen Frames
//Declaring Global Temporary Variables To Save Memory
int px, py, nx, ny; //Postions
char k;
int h, w;
int x, y;
int movementx = snakespeedx; //Snake Movement
int movementy = 0; //Snake Movement
//Check For Keyboard Press
/*
Reference Link:
https://www.quora.com/With-which-function-can-I-replace-kbhit-in-C++-because-the-header-conio-h-doesnt-exist-in-linux
Ubuntu Users:
sudo apt-get install libncurses5-dev libncursesw5-dev
Life Saver:
http://www.flipcode.com/archives/_kbhit_for_Linux.shtml
*/
int bytesWaiting, i;
int _kbhit()
{
static const int STDIN = 0;
static bool initialized = false; //The Boolean Data Type Is Used To Declare A Variable Whose Value Will Be Set As True (1) Or False (0)
if (! initialized)
{
//Use Termios To Turn Off Line Buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
//Initialise background borders Onto Array
void initialise_background(void)
{
//int i;
// Insert Top Border
for(i=0; i<width; i++)
{
background[0][i]=1;
}
//Insert Left Border
for(i=0; i<height; i++)
{
background[i][0]=1;
}
//Insert Right Border
for(i=0; i<height; i++)
{
background[i][width-1]=1;
}
//Insert Bottom Border
for(i=0; i<width; i++)
{
background[height-1][i]=1;
}
}
//Initialise Snake Coordinates
void initialise_snake(void)
{
snake[0][0]=3; //Coordinates X
snake[0][1]=3; //Coordinates Y
snake[1][0]=3+1; //Coordinates X
snake[1][1]=3; //Coordinates Y
snake[2][0]=3+2; //Coordinates X
snake[2][1]=3; //Coordinates Y
snake[3][0]=3+3; //Coordinates X
snake[3][1]=3; //Coordinates Y
snake[4][0]=3+4; //Coordinates X
snake[4][1]=3; //Coordinates Y
}
//Update Snake
void update_snake_coordination(void)
{
//int px,py,nx, ny;
px = snake[0][0];
py = snake[0][1];
snake[0][0] = px + movementx;
snake[0][1] = py + movementy;
nx = snake[0][0];
ny = snake[0][1];
for(i=1; i<snakelen; i++)
{
nx = snake[i][0];
ny = snake[i][1];
snake[i][0] = px;
snake[i][1] = py;
px = nx;
py = ny;
}
}
//Install Snake Coordinates Into Background Array = ( 1 To Draw And 0 To Erase)
void draw_snake_in_background(const int rev)
{
//int x, y;
for(i = 0; i<snakelen; i++)
{
x = snake[i][0];
y = snake[i][1];
if((x!=0)&&(y!=0))
{
background[y][x] = rev;
}
}
}
//Print Array Frame
void print_array_frame(void)
{
for(h=0; h<height; h++)
{
for(w=0; w<width; w++)
{
i=background[h][w];
if(i==1)
{
cout << block;
}
else if (i == 2)
{
cout << "+";
}
else
{
cout << " ";
}
}
cout << endl;
}
}
//Update Loop
void mainloop(void)
{
ClearScreen();
draw_snake_in_background(1); // Install Snake
print_array_frame(); // Print Frame
draw_snake_in_background(0); // Uninstall Snake
}
//Waiting Function
void sleepcp(int milliseconds) // Cross-Platform Sleep Function
{
clock_t time_end;
time_end = clock() + milliseconds * CLOCKS_PER_SEC/1000;
while (clock() < time_end)
{
//
}
}
//Reaction To Keyboard Press
void reaction_on_keyboard(const char k)
{
if(k=='d'||k=='6')
{
//Right Turn
movementx = snakespeedx;
movementy = 0;
}
else if(k=='a'||k=='4')
{
//Left Turn
movementx = -snakespeedx;
movementy = 0;
}
else if(k=='w'||k=='8')
{
//Turn Up
movementx = 0;
movementy = -snakespeedy;
}
else if(k=='s'||k=='2')
{
//Turn Down
movementx = 0;
movementy = snakespeedy;
}
else if(k=='q'||k=='z'||k=='c')
{
cout << "[+] Exit Safely [+]"<<endl;
exit(0);
}
}
//Create Snake Food
void cook_food(void)
{
if (food[0]==0)
{
x = rand() % width + 1;
y = rand() % height + 1;
food[0] = x;
food[1] = y;
background[y][x] = 2;
}
}
//Check Snake & Food Status
void capture_food(void)
{
x = food[0];
y = food[1];
if ((x==snake[0][0])&&(y==snake[0][1]))
{
background[y][x] = 0;
food[0] = 0;
score ++;
snakelen ++;
cook_food();
}
}
//Check Snake is Not Touching Boundary
void check_over_lapping(void)
{
//int px,py;
px = snake[0][0];
py = snake[0][1];
if((px==0)||(px==(width-1))||(py==0)||(py==(height-1)))
{
cout << "[+] Game Over [+]" << endl;
exit(0);
}
}
//Loop
void loop(void)
{
int frame = 0;
x = 0;
y = 0;
while(x<500)
{
sleepcp(lap);
if(_kbhit()) //If Keyboard Pressed
{
cin >> k; //Character
reaction_on_keyboard(k);
}
mainloop(); //RUn Main Loop FUnction
update_snake_coordination();//Update Snake Coordinates
check_over_lapping(); //Check Snake Status
cook_food(); //Make Sure Food is Available
capture_food(); //Snake Eaten Food?
cout << "[ Frame : " << frame << " | Score : " << score << " ] "<< endl; //Print Status
frame ++;
}
}
//Main Trigger Function
main()
{
initialise_background(); //Install All Variables
initialise_snake(); //Install Snake data
loop(); //Run Update Loop
}
This is what happens when running the game:
oooooooooooooooooooooooooooooooooooooooooooooooooo
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o o
o ooooooo o
o o
o o
o o
+<---Places Here Every Time o
oooooooooooooooooooooooooooooooooooooooooooooooooo
[ Frame : 169 | Score : 4 ]
Any Help or Input is greatly appreciated!
Your background array is height * width. When you place food into the array, you place it at rand() % width + 1 and rand() % height + 1, which have a range of 1 to width and 1 to height respectively. If you generate food at an x coordinate of width or a y coordinate of height, you will read outside the bounds of your background array. What is happening is that the seed your program is initialised with is generating food at an x position of width and because of the way memory is laid out that is the same array location as background[y + 1][0].
You probably want to change cook_food as follows:
void cook_food(void)
{
if (food[0]==0)
{
x = rand() % (width - 1) + 1;
y = rand() % (height - 1) + 1;
food[0] = x;
food[1] = y;
background[y][x] = 2;
}
}
I would note that this isn't really a C++ program, no matter what you're compiling it with. Your are using a very C style, storing data in a C way, and calling C standard library functions. You may want to read the isocpp C++ FAQ, which has some pointers to resources for people learning C++.
A C++ implementation would probably want to use the std::uniform_int_distribution class in the standard library, which makes it much clearer what your minimum and maximum values are for your food X and Y coordinates. You would also have 'Food' and 'Snake' objects that tracked their X and Y coordinates, rather than storing those values in arrays that you use directly.
EDIT: You've been asking some questions in the comments about collision detection for the snake. I believe this method will detect snake-on-snake collision given the code above:
bool is_snake_touching_itself() {
for (std::size_t i = 1; i < snakelen; ++i) {
if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
return true;
}
}
return false;
}

Mandelbrot Slicing Image to Improve Speed

The Mandelbrot set currently displays the image in one whole set by calling the function from the main.
// This shows the whole set.
compute_mandelbrot(-2.0, 1.0, 1.125, -1.125);
My plan is to split the image up into 16 horizontal slices and then display it to improve the speed as can then parallel program this in.
I'm unsure how to create these slices, can someone explain, redirect me or show some example code
image details:
// The size of the image to generate.
const int WIDTH = 100;
const int HEIGHT = 100;
// The number of times to iterate before we assume that a point isn't in the
// Mandelbrot set.
const int MAX_ITERATIONS = 500;
For the purpose of testing, ill send the full code, there are no errors - it is not coded efficiently evidently as the whole process takes over 30 seconds to output, which is way too long for a Mandelbrot set, hence the urgency of the slicing and parallel programming.
If anyone has any other pointers then they would be greatly appreciated
e.g. where to implement parallel programming
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::complex;
using std::cout;
using std::endl;
using std::ofstream;
// Define the alias "the_clock" for the clock type we're going to use.
typedef std::chrono::steady_clock the_clock;
// The size of the image to generate.
const int WIDTH = 100;
const int HEIGHT = 100;
// The number of times to iterate before we assume that a point isn't in the
// Mandelbrot set.
const int MAX_ITERATIONS = 500;
// The image data.
// Each pixel is represented as 0xRRGGBB.
uint32_t image[HEIGHT][WIDTH];
// Write the image to a TGA file with the given name.
// Format specification: http://www.gamers.org/dEngine/quake3/TGA.txt
void write_tga(const char *filename)
{
ofstream outfile(filename, ofstream::binary);
uint8_t header[18] = {
0, // no image ID
0, // no colour map
2, // uncompressed 24-bit image
0, 0, 0, 0, 0, // empty colour map specification
0, 0, // X origin
0, 0, // Y origin
WIDTH & 0xFF, (WIDTH >> 8) & 0xFF, // width
HEIGHT & 0xFF, (HEIGHT >> 8) & 0xFF, // height
24, // bits per pixel
0, // image descriptor
};
outfile.write((const char *)header, 18);
for (int y = 0; y < HEIGHT; ++y)
{
for (int x = 0; x < WIDTH; ++x)
{
uint8_t pixel[3] = {
image[y][x] & 0xFF, // blue channel
(image[y][x] >> 8) & 0xFF, // green channel
(image[y][x] >> 16) & 0xFF, // red channel
};
outfile.write((const char *)pixel, 3);
}
}
outfile.close();
if (!outfile)
{
// An error has occurred at some point since we opened the file.
cout << "Error writing to " << filename << endl;
exit(1);
}
}
// Render the Mandelbrot set into the image array.
// The parameters specify the region on the complex plane to plot.
void compute_mandelbrot(double left, double right, double top, double bottom)
{
for (int y = 0; y < HEIGHT; ++y)
{
for (int x = 0; x < WIDTH; ++x)
{
// Work out the point in the complex plane that
// corresponds to this pixel in the output image.
complex<double> c(left + (x * (right - left) / WIDTH),
top + (y * (bottom - top) / HEIGHT));
// Start off z at (0, 0).
complex<double> z(0.0, 0.0);
// Iterate z = z^2 + c until z moves more than 2 units
// away from (0, 0), or we've iterated too many times.
int iterations = 0;
while (abs(z) < 2.0 && iterations < MAX_ITERATIONS)
{
z = (z * z) + c;
++iterations;
}
/*if (iterations == MAX_ITERATIONS)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0x58DC77; // green
}*/
if (iterations <= 10)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0xA9C3F6; // light blue
}
else if (iterations <=100)
{
// This point is in the Mandelbrot set.
image[y][x] = 0x36924B; // darkest green
}
else if (iterations <= 200)
{
// This point is in the Mandelbrot set.
image[y][x] = 0x5FB072; // lighter green
}
else if (iterations <= 300)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0x7CD891; // mint green
}
else if (iterations <= 450)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0x57F97D; // green
}
else
{
// z escaped within less than MAX_ITERATIONS
// iterations. This point isn't in the set.
image[y][x] = 0x58DC77; // light green
}
}
}
}
int main(int argc, char *argv[])
{
cout << "Processing" << endl;
// Start timing
the_clock::time_point start = the_clock::now();
// This shows the whole set.
compute_mandelbrot(-2.0, 1.0, 1.125, -1.125);
// This zooms in on an interesting bit of detail.
//compute_mandelbrot(-0.751085, -0.734975, 0.118378, 0.134488);
// Stop timing
the_clock::time_point end = the_clock::now();
// Compute the difference between the two times in milliseconds
auto time_taken = duration_cast<milliseconds>(end - start).count();
cout << "Computing the Mandelbrot set took " << time_taken << " ms." << endl;
write_tga("output.tga");
return 0;
}
Lets say you want to use N parallel threads for the rendering, then each thread will handle HEIGHT / N lines.
For simplicities sake I pick an N that divides your HEIGHT evenly, like 5. That means each thread will handle 20 lines each (with your HEIGHT being equal to 100).
You could implement it something like this:
constexpr int THREADS = 5; // Our "N", divides HEIGHT evenly
void compute_mandelbrot_piece(double left, double right, double top, double bottom, unsigned y_from, unsigned y_to)
{
for (unsigned y = y_from; y < y_to; ++y)
{
for (unsigned x = 0; y < WIDTH; ++x)
{
// Existing code to calculate value for y,x
// ...
}
}
}
void compute_mandelbrot(double left, double right, double top, double bottom)
{
std::vector<std::thread> render_threads;
render_threads.reserve(THREADS); // Allocate memory for all threads, keep the size zero
// Create threads, each handling part of the image
for (unsigned y = 0; y < HEIGHT; y += HEIGHT / THREADS)
{
render_threads.emplace_back(&compute_mandelbrot_piece, left, right, top, bottom, y, y + HEIGHT / THREADS);
}
// Wait for the threads to finish, and join them
for (auto& thread : render_threads)
{
thread.join();
}
// Now all threads are done, and the image should be fully rendered and ready to save
}

What is wrong with my algorithm to render rectangle in 1D array?

I am trying to make optimal algorithm to draw rectangle onto 1D array. I wrote this function:
/** Draws a rectangle in 1D array
* Arguments:
* pixmap - 1D array of Color
* color - rectangle color
* w - rectangle width
* h - rectanhle height
* x - x position, negative coordinates are outside draw area
* y - y position, negative coordinates are outside draw area
* pixmapWidth - width of the image (height can be deducted from width if needed but is practically unnecessary) */
void rectangle(std::vector<int>& pixmap, const int& color, const int w, const int h, int x, const int y, const int pixmapWidth)
{
if(x>=pixmapWidth)
return;
if(x+w<0)
return;
if(y+h<0)
return;
// Width of one consistent line of color of the rectangle
// if the rectangle is partially out of pixmap area,
// thw width is smaller than rectangle width
const int renderWidth = std::min(w, pixmapWidth-x);
// offset in the arrray where the rendering starts
// 0 would be for [0,0] coordinate
int tg_offset = y*pixmapWidth+x;
// maximum offset to ever render, which is the array size
const int tg_end = pixmap.size();
int lines = 0;
for(; tg_offset<tg_end && lines<h; tg_offset+=pixmapWidth) {
for(int cx=0; cx<renderWidth; ++cx) {
// This check keeps failing and my program crashes
if(tg_offset+cx >= pixmap.size())
throw "Oh no, what a bad thing to happen!";
pixmap[tg_offset+cx] = color;
}
lines++;
}
}
Note that I know there's a lot of picture drawing libraries, but I'm trying to learn by doing this. But now I'm stuck and I need help.
The problem is that in the inner loop, condition if(tg_offset+cx >= pixmap.size()) keeps failing meaning I am trying to render outside the array. I have no idea why this keeps happening.
Example problematic code:
const int pixmap_width = 20;
const int pixmap_height = 20;
std::vector<int> pixmap(pixmap_width*pixmap_height);
// tries to render outside the array
rectangle(pixmap, 0, 10, 10, -1, 18, pixmap_width);
Here is a testcase including ASCII output of the pixmap: http://ideone.com/SoJPFF
I don't know how could I improve the question any more...
Making no changes produces a quadrilateral. Is this not the desired functionality?
for(; tg_offset<tg_end && lines<h; tg_offset+=pixmapWidth) {
cout <<"" << endl;
for(int cx=0; cx<renderWidth; ++cx) {
cout << " " << pixmap[tg_offset+cx];
// This check keeps failing and my program crashes
if(tg_offset+cx >= pixmap.size())
throw "Oh no, what a bad thing to happen!";
pixmap[tg_offset+cx] = color;
}
lines++;
}
}
int main()
{
std::vector<int> pixmap(16);
pixmap = { 1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1 };
int color = 0;
int w = 4;
int h = 4;
int x = 0;
int y = 0;
int pixmapWidth = 4;
cout << "Hello World" << endl;
rectangle(pixmap, color, w, h, x, y, pixmapWidth);
return 0;
}
produces:
Hello World
1 1 1 1
1 0 0 1
1 0 0 1
1 1 1 1
I think a large part of the problem with your function is it being a lot more complex than it needs to be. Here's a much simpler version of your function, done by simply looping over x and y.
void rectangle(std::vector<int>& pixmap, const int& color, const int width, const int height,
int left, const int top, const int pixmapWidth)
{
for (int x = std::max(left, 0); x < left + width && x < pixmapWidth; x++)
for (int y = std::max(top, 0); y < top + height && y*pixmapWidth + x < pixmap.size(); y++)
pixmap[y*pixmapWidth + x] = color;
}
I'm not sure exactly what the output you want when x or y are negative. In your actual algorithm things goes wrong if x is negative due the fact that tg_offset goes back, so the tg_offset + cx can fail.
To solve this you can limit the second for to avoid this, like this:
for(int cx=0; cx<std::min(renderWidth, tg_end - tg_offset); ++cx)
but I think that limiting x and y to be only positive is more correct:
if ( x < 0 ) x = 0;
if ( y < 0 ) y = 0;

Solving a maze with only vision of a 15x15 grid around the current square (C++)

So I'm writing a program that solves a maze in the fastest time possible but you're only given a small area around where you currently are to see the surrounding area. I had planned to make it so that it always steps in the order of right > forward > left > backward. To make it go faster I intended to add a function that checks a path to see if it results in a dead end. Whether or not you can go in a certain direction is represented by the last 4 digits. I tried using a breadth first search algorithm to find dead ends. The function works by checking to see if it steps outside of the given area and if it does it returns false, otherwise it returns true. I'm not entirely sure where it's going wrong but it definitely does not work. The function is passed an array that represents the visible area, the height and width of the area, the x,y coordinates and the direction it is originally facing represented as a unsigned char. this is & with the last 4 bits to check if it's possible to move in that direction. Any help would be appreciated.
//WILL RETURN TRUE IF THERE IS A DEAD END, FALSE OTHERWISE
bool ActualPlayer::deadEnd(const AdvancedMapTile* area, const uint width, const uint height, const uint x, const uint y, unsigned char dir)
{
//dynamic allocation
bool *marked = nullptr;
marked = new bool[height * width];
for(uint i = 0; i < (height * width) ; i++)
marked[i] = false;
queue<cord> q;
bool deadEnd = true;
cord temp;
marked[x + y*width] = true;
temp.x = x;
temp.y = y;
q.push(temp);
//perform bfs
while(!q.empty())
{
AdvancedMapTile loc = area[x + y*width];
temp = q.front();
q.pop();
for(unsigned char i = 1; i < 9; i = i*2)//goes for 1, 2, 4, 8
{
uint tempx = temp.x;
uint tempy = temp.y;
changeXY(tempx, tempy, i, height, width);
if(!marked[tempx + tempy*width] && (loc.exits & i) != 0)
{
q.push(temp);
marked[tempx + tempy*width] = true;
if(tempx < 0 || tempx == width || tempy < 0 || tempy == height)
return false;
}
}
}
delete [] marked;
return deadEnd;
}

How to add/subtract to value rather than just be that value

Using the Openframeworks library in C++, I have the radius of a glow (max_distance) that is determined by the stretch of the mouse dragging across the screen (mouseDragX). It works fine.
But rather than every time I resize it (by dragging the mouse), I want it not to start at 0 and follow the mouse drag directly.
max_distance = mouseDragX/2;
But rather, if I have already dragged the mouse to the right to say 200 on a previous drag, that the next time I drag the mouse, and go into the opposite direction (negative numbers) that the value of max_distance decreases by that amount, instead of just being that amount.
I thought it would be
max_distance += mouseDragX/2;
but that seems to kill it altogether
Can you help me?
#include "testApp.h"
//--------------------------------------------------------------
void testApp::setup(){
ofSetWindowShape(700,700);
max_distance = 700; // ofDist didn't work(?) // ofDist(0,0,700,700);
ofEnableSmoothing();
ofEnableAlphaBlending();
}
//--------------------------------------------------------------
void testApp::update(){
max_distance = mouseDragX/2;
if (max_distance < 0) max_distance = 0;
}
//--------------------------------------------------------------
void testApp::draw(){
string str = "mouseDragX: ";
str += ofToString(mouseDragX)+" ";
ofSetWindowTitle(str);
int i,j;
int height = ofGetHeight();
int width = ofGetWidth();
for(i = 0; i <= height; i += 20) {
for(j = 0; j <= width; j += 20) {
float dist_color = getDistance(mouseX, mouseY, i, j); // for definition of getDistance, look below!
dist_color = dist_color/max_distance * 100;
// to get the colors into the range between 0 and 255, multiply the values by 5.
ofSetColor(dist_color*5,dist_color*5,dist_color*5, 123);
ofEllipse(i, j, 20, 20);
}
}
}
//--------------------------------------------------------------
void testApp::keyPressed (int key){
}
//--------------------------------------------------------------
void testApp::keyReleased (int key){
}
//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
// shift values down
for (int i = 0; i < 1; /*<<- length of array*/ i++) {
pmouseX[i] = pmouseX[i+1];
pmouseY[i] = pmouseY[i+1];
}
// make pmouseX/Y[0] be the previous mouse position. [1] = current
pmouseX[1] = mouseX;
pmouseY[1] = mouseY;
}
//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
mouseDragX = (mouseX - pmouseX[0]);
}
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
// mouseDragX = mouseDragY = 0; // The drag starts here
}
//--------------------------------------------------------------
void testApp::mouseReleased(){
}
float testApp::getDistance(int startX, int startY, int endX, int endY){
return sqrt((endX-startX)*(endX-startX) + (endY-startY)*(endY-startY));
}
Thank you so much.
If I understand correctly, you want todo something like this.
// Every time the mouse *stops* moving, (say on mouse-up
// message) save previous max_distance
int base = max_distance;
// when mouse moves
max_distance = base + mouseDragX/2;
If max_distance and mouseDragX are int values, the division by 2 results in an integer division that can induce losses.
This is especially true if mouseDragX value's is 1 at some time. This will result in 1 / 2 (integer division) and returns 0.
Example:
Lets consider that mouseDragX takes 3 different values (3 cycles):
3, 1, -4
One would expect that max_distance will be increased by (3 / 2) + (1 / 2) - (4 / 2) = 0.
But due to integer truncation, this will infact result to 1 + 0 - 2 = -1.
What if you use floats instead of int, and just round max_distance to an int when you really need it's value ?