I have an assignment where I need to make a game using threads and the curses library. I have mostly finished the program, but the player icon is not getting printed to the curses screen even though the function should be doing that. The other functionality of the function is working, it's just that nothing is being printed. For example, when I press q the program will terminate like it is supposed to.
Here is the function itself:
void *run_rocket( void *rocket ) {
object_t * rocket1 = (object_t *) rocket;
int c;
int row = rocket1->row;
mvaddch( rocket1->row, rocket1->col, rock );
curse_refresh();
while( running ){
c = getchar();
if( c == KEY_UP ){
row = row - 1;
rocket1->row = row;
mvaddch( row+1, rocket1->col, ' ' );
mvaddch( row, rocket1->col, rock );
} else if( c == KEY_DOWN ){
if( row!=bheight ){
row = row + 1;
rocket1->row = row;
mvaddch( row-1, rocket1->col, ' ' );
mvaddch( row, rocket1->col, rock );
}
} else if( c == 'q' ){
running = false;
}
if( row == 0 ){
running = false;
int hgt = bheight/2;
mvprintw( hgt, 0, "Congratulations! You won!");
mvprintw( (hgt - 1), 0, "Press 'q' to exit.");
}
curse_refresh();
}
destroy_rocket(rocket);
return NULL;
}
and this is how I start the thread
pthread_t rocket;
check = pthread_create( &rocket, NULL, run_rocket, obj_rock );
if( check != 0 ){
return 1;
}
I have only tried small changes because I have no idea what the problem, since I have another function that calls mvaddch the same way and that one works.
I need some help with some homework. I am supposed to make a Snake Game by using mostly "basic" c, only simple concepts.
To explain my thought process: Controls are the usual WASD. The grid we re playing in is an array. Head is represented by '#' and the tail by "*". What I am trying to do is implement this thinking:
Get input from user, move the head. Check in 4 possible directions of head's initial position, find the " * ", move it to the initial position of the head. Repeat till all '*' have been moved.
Obviously, I am doing something wrong while checking and/or moving, but I cannot quite figure out what parts I am treating wrong and after 2 days I am stuck with this as my closest to working version. I know I have been looking at it for too long, but I cant afford to take more time with it as it needs to be turned in.
Here is my code. I hope my error is very obvious to "fresh eyes".
main:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]){
//get size of grid from args
int size;
size = atoi(argv[1]);
while(size < 6){
printf("Please insert a number greater than 6 so the game is
playable\n");
scanf("%d\n", &size);
}
char grid[size][size];
int sx,sy; //coordinates of snake head
int length = 2; //length of tail (without head)
int score = 0;
sx = 1;
sy = size/2;
//generate empty grid
int x, y;
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
if (y == 0 || y == size - 1) {
grid[y][x] = '-';
} else if (x == 0 || x == size - 1) {
grid[y][x] = '|';
} else {
grid[y][x] = ' ';
}
}
}
//initialize snake position
grid[sx][sy] = '#';
grid[sx+1][sy] = '*';
grid[sx+2][sy] = '*';
grid[sx+3][sy-6] = 'X';//just to test if it works, will be generated
randomly
//print grid
printGrid(size, grid);
play(sx,sy,size,grid,&length);
printf("*********GAME OVER********** \n final score: %d\n", score);
}
play() function. Practically all of the game.
int play(int x, int y, int size, char grid[size][size], int length){
int x0,y0,x1,y1,x2,y2,valid;//x0,y0 = current, x1,y1 next to check,
//x2,y2 = move there x0,y0
char end,dir; //what did the head land on
int score = 0;
int checkl = 0;
while(1){
scanf("%c", &dir);
switch(dir){
//move head, change head coordinates
case 'w': end = grid[x-1][y];
grid[x-1][y] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
x--;
break;
case 's': end = grid[x+1][y];
grid[x+1][y] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
x++;
break;
case 'a': end = grid[x][y-1];
grid[x][y-1] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
y--;
break;
case 'd': end = grid[x][y+1];
grid[x][y+1] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
y++;
break;
}
if ((end == '-') | (end =='|') | (end == '*')){
break;
}
printf("POINT 1\n");
do{
check(x0,y0,&x1,&y1, size, grid);
move(x0,y0, x2,y2, size, grid);
//if(valid == 1){
x2 = x0;
y2 = y0;
x0 = x1;
y0 = y1;
//}
checkl++;
printf("POINT 2\n");
}while(checkl <= length);
printf("POINT 3\n");
if (end == 'X'){
grid[x1][y1] = '*';
length++;
score += 10;
}
clearScreen();
printGrid(size, grid);
}
return score;
}
check() function. Implements the "look for the next '*'" process
int check(int x0, int y0, int *x1, int *y1, int size, char grid[size]
[size]){
if (grid[x0][y0-1] == '*'){
*x1 = x0;
*y1 = y0-1;
return 1;
}
else if (grid[x0][y0+1] == '*'){
*x1 = x0;
*y1 = y0+1;
return 1;
}
else if (grid[x0-1][y0] == '*'){
*x1 = x0-1;
*y1 = y0;
return 1;
}
else if (grid[x0+1][y0] == '*'){
*x1 = x0+1;
*y1 = y0;
return 1;
}
else
return 0;
}
move(). Self-explanatory
void move(int x0, int y0, int x2, int y2, int size, char grid[size]
[size]){
grid[x2][y2] = grid[x0][y0];
grid[x0][y0] = ' ';
}
A function to clear the window
void clearScreen()
{
const char *CLEAR_SCREEN_ANSI = "\e[1;1H\e[2J";
write(STDOUT_FILENO, CLEAR_SCREEN_ANSI, 12);
}
PrintGrid. Also self explanatory, have it as a function for convenience
void printGrid(int size, char grid[size][size]){
int y,x;
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
printf("%c", grid[y][x]);
}
printf("\n");
}
}
I believe the error is either in check, move, and in the do-while condition with the length in play. However, as I said, with a lot of trial and error, I am still here.
All of this should be in one file, but i could not align it properly all together. Thanks for any help, very appreciated.
Edit: Edited part of the code out. Now what happens after running the code is: I get the grid and the snake. The head moves just fine, along with the first '" of the tail but the rest does not follow. When it "eats" an 'X', it grows the tail where it should, but the '' added disappears in the next move. Also, the score goes up 20 instead of 10 so for some reason it enters the if twice for one move. The movement of the head + the first '*' as well as the "game over" scenarios work as they should.
Tidbit: This is only 10 actual characters, not 12 because the \ characters don't count:
const char *CLEAR_SCREEN_ANSI = "\e[1;1H\e[2J";
Better is to let the compiler count for you:
void clearScreen()
{
static const char CLEAR_SCREEN_ANSI[] = "\e[1;1H\e[2J";
write(STDOUT_FILENO, CLEAR_SCREEN_ANSI, sizeof(CLEAR_SCREEN_ANSI)-1);
}
Note that CLEAR_SCREEN_ANSI is now an array, not a pointer, and the -1 is for the trailing NUL byte.
Aha:
if ((end == '-') | (end =='|') | (end == '*')){
The | are bitwise OR and you almost certainly mean logical OR ||:
if ((end == '-') || (end =='|') || (end == '*')){
Edit: They actually do the same thing in this case, but it's a common-enough error that it's worth fixing.
Hat tip to #Sami Kuhmonen
I've spent some time looking at this, and it's clear this is entirely about program logic and less about C, so that makes it a lot more difficult to dive into something unfamiliar (and without a real spec).
The general idea is that the program draws a square playing field with a three-part snake: an # for a head and two * for the body, and the keyboard lets you move the snake around on the field with awds keys. You can't move on top of yourself, you can't go past the walls, and you want to find the food at location marked with X.
I believe your approach was to look for * characters, but I am not sure how it could tell a * from the middle of the snake from one at the end, so my approach is to maintain an array of all the positions of the snake, and in the main function it's initialized:
int ysnake[4] = { 1, 2, 3, 4 };
int xsnake[4] = { 15, 15, 15, 16 };
plus an obvious function to draw the snake given the position array:
static void drawsnake(
int snakelen, int xsnake[snakelen], int ysnake[snakelen],
int size, char grid[size][size])
{
char snakechar = '#'; // start with snake head
for (int i = 0; i < snakelen; i++)
{
grid[ ysnake[i] ]
[ xsnake[i] ] = snakechar;
snakechar = '*'; // all the rest are tails
}
}
So now we have the play() function, and this required quite a bit of refactoring, but it works for me.
int play(
int snakelen, int xsnake[snakelen], int ysnake[snakelen],
int size, char grid[size][size])
{
int score = 0;
while (1)
{
char dir;
scanf ("%c", &dir);
int proposed_xhead = xsnake[0];
int proposed_yhead = ysnake[0];
switch (dir)
{
case 'w': // up
proposed_yhead--;
break;
case 's': // down
proposed_yhead++;
break;
case 'a': // left
proposed_xhead--;
break;
case 'd': // right
proposed_xhead++;
break;
default: // ignore this invalid char
continue;
}
// first make sure we didn't go off the edge of the field
if (proposed_yhead <= 0 || proposed_yhead >= (size-1)
|| proposed_xhead <= 0 || proposed_xhead >= (size-1))
{
// would head off the maze, LOSE
break;
}
const char char_at_proposed_head = grid[proposed_yhead][proposed_xhead];
// now make sure we're not bumping into ourself
if (char_at_proposed_head == '#' // we shouldn't ever be able to bump into our head
|| char_at_proposed_head == '*') // we bumped into our tail
{
break; // would run into ourself: LOSE
}
// NOW we know it's a legal move. Did we find the food?
if (char_at_proposed_head == 'X')
{
// found the food!
// update score, set new food, etc.
score += 10;
}
// blank out the former tail; we're about to lose that position
grid[ ysnake[ snakelen-1 ] ]
[ xsnake[ snakelen-1 ] ] = ' ';
// shift all items down in the array, dropping the last one
for (int i = snakelen-1; i > 0; i--)
{
xsnake[i] = xsnake[i-1];
ysnake[i] = ysnake[i-1];
}
xsnake[0] = proposed_xhead;
ysnake[0] = proposed_yhead;
drawsnake(snakelen, xsnake, ysnake, size, grid);
clearScreen ();
printGrid (size, grid);
}
return score;
}
There's a clear separation of duties, where the decoding of the direction key translates to a change in the snake's head position, then checking for out-of-bounds or running into yourself, and finding if you found the food.
Then we move the snake by shifting the entire array of positions: the tail element drops off and the new one shifts onto the front. Then we re-draw the snake with new positions.
The main function is the same as yours at the top to set up the grid, but the snake configuration and play looks like:
int main(int argc, argv)
{
...
int length = 4;
int ysnake[4] = { 1, 2, 3, 4 };
int xsnake[4] = { 15, 15, 15, 16 };
drawsnake(length, xsnake, ysnake, size, grid);
// Put the food somewhere
grid[sx + 3][sy - 6] = 'X'; //just to test if it works, will be generated randomly
printGrid (size, grid);
score = play(length, xsnake, ysnake, size, grid);
printf ("*********GAME OVER********** \n final score: %d\n", score);
}
I didn't really do anything meaningful with the score and have only barely tested it, but it does let the little guy slither around the screen, and it might be a bit easier to follow.
Good luck.
(program language is c - when correcting please only use stuff noobs can do, I am just learning this since 1 week)
The problem is: See the "int snakelen = 1;" at the start of main?
I never change that integer. But when I end the game it is 0. Why?
And if i TRY TO CHANGE snakelen mid-game, the game completely breaks and i get windows-error sounds.
What's the matter?
(And the food doesnt spawn randomly although i use a randomizer. And it either spawns bottom-only or top-only - changing about every 5 minutes. another wierd glitch.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <time.h>
#include <math.h>
#define SIZE 2048 //32(*2 because every 2nd one is a space) * 32
#define HSIZE 1024 //32 * 32
#define UP_ 1
#define DOWN_ 3
#define LEFT_ 4
#define RIGHT_ 2
#define YSIZE 64 //length of a row (including spaces)
//TO PLAY: Start the game once, right-click the command-promt at the top, click Settings -> Layout . Then change the window size to 64 (hor) * 33 (vert)
int counter = 0;
int gamespeed = 400;//Intervall in which a game-frame gets rendered
int spawnfood(int* freetable, int snakelen)
{
srand ( time(NULL) ); //randomize
int randomIndex = rand()%(HSIZE - 1); //take random non-x-filled position from array
int randomValue = freetable[randomIndex]; //output the random position
return randomValue;
}
int main()
{
int nofood = 1; //is there food in the game? 1 = no
//int tmp = 0; //temporary memory for later
int tmp2 = 0; //temporary memory2
int snakelen = 1; //length of snake
int snakedir = RIGHT_; //Position the snake is looking
int snakeheadxpos = 0; //x-position of snake
int snakeheadypos = 0; //y-position of snake
char q;//The button that was pressed last
char gametable[SIZE]; //the game-screen //fill it with spaces
for(int i = 0; i < SIZE; i++)
{
gametable[i]=' ';
}
gametable[SIZE] = '\0';
int freetable[(HSIZE)]; // 32*32 list of all pixels, which shows whether a pixel is an x or not
for(int i = 0; i < (HSIZE); i++)
{
freetable[i]= i*2; //fill the array with its numbers
}
//START OF GAME
printf("Press any Button to start the game!\n");
getch();
for(int i = 0; i < 31; i++){
printf("\n");
}
while(q != 27)
{
counter++;
if(kbhit()) //if button is pressed
{
q = getch(); //q = that button
switch(q) //change the way the snake looks via WASD
{
case 'w':
if(snakedir != DOWN_)
snakedir = UP_;
break;
case 'a':
if(snakedir != RIGHT_)
snakedir = LEFT_;
break;
case 's':
if(snakedir != UP_)
snakedir = DOWN_;
break;
case 'd':
if(snakedir != LEFT_)
snakedir = RIGHT_;
break;
default:
break;
}
}
if(counter%gamespeed == 0) //Renders a game-frame at the intervall of gamespeed
{
switch(snakedir)
{
case UP_:
if(snakeheadypos==0)
{
goto exit_loop; //ran into a wall
}
snakeheadypos--;
break;
case DOWN_:
if(snakeheadypos==31)
{
goto exit_loop; //ran into a wall
}
snakeheadypos++;
break;
case RIGHT_:
if(snakeheadxpos==31)
{
goto exit_loop; //ran into a wall
}
snakeheadxpos++;
break;
case LEFT_:
if(snakeheadxpos==0)
{
goto exit_loop; //ran into a wall
}
snakeheadxpos--;
break;
default:
break;
}
if((gametable[snakeheadypos*YSIZE + 2*snakeheadxpos] == 'o'))
{
//snakelen++; //<-- WHEN YOU REMOVE THE FIRST //, THE GAME STARTS TO BUG AND I GET WINDOWS ERROR SOUNDS!
nofood = 1; //no more food is in the game
}
gametable[snakeheadypos*YSIZE + 2*snakeheadxpos] = 'x'; //set the pixel ur at the the moment to 'x'
gametable[tmp2] =' ';
tmp2 = snakeheadypos*64+snakeheadxpos*2;
//spawn food if there is none
if(nofood)
{
gametable[spawnfood(freetable, snakelen)] = 'o';
nofood = 0; //food is already placed
}
printf("%s", gametable); // print the gametable
}
}
exit_loop: ; //if you ran into a wall
printf("Game Over - Score: %d", snakelen);
}
char gametable[SIZE]; //the game-screen //fill it with spaces
...
gametable[SIZE] = '\0';
This is wrong. You can index an array of size N with indices 0 through N-1. gametable[SIZE] is outside the array, and assigning to it invokes undefined behavior.
Caveat: This isn't a "give a man a fish" answer. It's a "teach a man to fish' answer.
On every one of your statements that reads or writes to an array, you should check the array index for validity.
For example, instead of
gametable[snakeheadypos*YSIZE + 2*snakeheadxpos] = 'x';
gametable[tmp2] =' ';
...write...
int index;
index=snakeheadypos*YSIZE + 2*snakeheadxpos;
if(index<0 || index >=SIZE){printf("Index error A: value is %d", index);exit(1);}
gametable[index] = 'x';
index=tmp2;
if(index<0 || index >=SIZE){printf("Index error B: value is %d", index);exit(1);}
gametable[index] =' ';
This sort of technique can help you detect array index problems, which can be a very common source of bugs, and can produce all sort of weird symptoms.
This is for Homework
I have to create a game of TicTacToe for a project and I have two issues. Also I apologize if I'm violating a rule by having two questions within one post, If it's not allowed then I'd appreciate someone notifying me in the comments and I'll go ahead and break this into two separate posts. I'll post my code then ask my questions following the code.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char table[3][3];
void clear_table();
void player1_move();
void player2_move();
void the_matrix(); // Like the movie
char check_three();
int main() {
srand(time(NULL));
char win;
printf("This program plays the game of Tic Tac Toe.\n");
win = ' ';
clear_table();
do {
the_matrix(); // Like the movie
player1_move();
win = check_three(); // Check win for player 1
if (win != ' ')
break;
player2_move();
win = check_three(); // Check win for player 2
}
while (win == ' ');
the_matrix(); // Shows the final move+Like the movie
if (win == 'O')
printf("Congratulations, Player 1 wins!\n");
else
printf("Congratulations, Player 1 lost!\n");
// the_matrix (); //Shows the final move+Like the movie
return 0;
}
void clear_table() {
// Creates empty spaces for the user and computer to enter stuff in
int i, j, k;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
// for(l = 0; k < 3; j++)
table[i][j] = ' ';
}
}
void player1_move() {
// Moves that player 1 can and can't make
int x, y, z;
printf("Player 1 enter your selection[row, col]: ");
scanf("%d, %d", &x, &y);
x--;
y--;
// z--;
if (table[x][y] != ' ') {
printf("Space already taken, please try again.\n");
player1_move();
}
else
table[x][y] = 'O'; // O goes first for some reason
}
void player2_move() {
// Needs work!!
// Call srand in the main
int a = rand() % 3;
int b = rand() % 3;
// Make it so the game would end in a tie when possible
for (a = rand() % 3; a < 3; a++) {
for (b = rand() % 3; b < 3;
b++) // For loops causing issues in randomization?
// for(c = 0; c < 3; c++)
if (table[a][b] == ' ')
break;
if (table[a][b] == ' ') // Checks the rows and columns
break;
}
if (a * b == 9)
**Kinda works ? ** {
printf("Game Over, No Player Wins\n");
exit(0);
}
else
table[a][b] = 'X';
}
void the_matrix() { // Like the movie
**Get rid of the underscores **
int m;
printf("The current state of the board:\n");
for (m = 0; m < 3; m++) {
printf("%c_ %c_ %c_\n", table[m][0], table[m][1], table[m][2]);
}
printf("\n");
}
char check_three() {
int w;
// char table[3][3];
for (w = 0; w < 3; w++) {
if (table[w][0] == table[w][2] && table[w][0] == table[w][1])
return table[w][0]; // Row Check
}
for (w = 0; w < 3; w++) {
if (table[0][w] == table[2][w] && table[0][w] == table[1][w])
return table[0][w]; // Col Check
}
if (table[0][0] == table[1][1] && table[1][1] == table[2][2])
return table[0][0];
if (table[0][2] == table[1][1] && table[1][1] == table[2][0])
return table[0][2]; // Diag Check
return ' ';
}
First Question
So my first question is with a draw game. On the player two function I have a snip of code set to determine a draw game. Initially I assumed that if the X's and O's were to multiply to 9 then that would mean that the board would be filled up then that would result in a draw game. [This is within my third function - player2_move near the end of the function] It kind of works, but sometimes the program just preemptively ends the game. It's a bit hard to test it because the computers moves are randomized and most of the times I've tried, I ended up winning accidentally. My question is what would I need to do to set up my program to essentially have a better way of determining a draw game.
Second Question
On my 4th function called the_matrix I need help with formatting. The assignment requires the format to be a little like this where if I were to enter in the coordinates 1,1 then the board would look like this:
O _ _ with the proceeding lines near the bottom to be blank. However as my program is right now, it looks like this:
O_ _ _
What I want to do is swap or replace the underscore with the user's input. Not entirely sure how to do that and any help would be appreciated.
I apologize if I violated any rules for stackoverflow by having two questions in one and I'm also sorry for this huge post.
I'm writing a function that draws # characters onto a console screen, and repeats itself until it draws upon a 'H' which has already been drawn. Basically a "bomb" function. I wrote the function with a while loop so that it may continue to draw the character as long as the space it is drawing upon does not equal 'H'. If it does equal 'H', i've put in an if statement to break the program. However even with the if statement, the program continues to run when it is drawn on an 'H'.
void bomb_until_hit(int home_radius) {
int x = 0, y = 0;
while (mvinch(y, x) != 'H') {
x = get_next_bomb_x();
y = get_next_bomb_y();
mvaddch(y, x, '#' );
refresh();
sleep(1);
if (mvinch(y, x) == 'H') {
break; }
}
}
mvinch is a function which basically checks the coordinates for characters before the new character is drawn.
Why is my if statement not working?
Your code draws an # and then checks for an H (twice). Obviously, it's not going to find an H since it just drew an #.
Let's look at what happens starting from when you move to a new position:
void bomb_until_hit(int home_radius) {
int x = 0, y = 0;
while (mvinch(y, x) != 'H') { // 5) Check for an H here
x = get_next_bomb_x(); // 1) Move to next X
y = get_next_bomb_y(); // 2) Move to next Y
mvaddch(y, x, '#' ); // 3) Put an # here
refresh();
sleep(1);
if (mvinch(y, x) == 'H') { // 4) Check for an H here
break; }
}
}
You need to rearrange the order of your statements so that once you move to a new spot, you check it before you write to it.