Activity bot - parallax - moving the robots with sensors - C Programming - c

This is my code for moving an activity bot from its starting point to the ending point. It detects obstacles on both sides and turns away from them.
I save the sequence of moves in an array so that I can return to the starting point without using any sensors. **(Which is the code after the "//return" comment)
#include "simpletools.h"
#include "abdrive.h"
#include "ping.h"
int back[200];
int i = 0;
int main() {
int distance;
int irLeft = 0, irRight = 0;
low(26);
low(27);
while (1) {
if (ping_cm(8) < 5) {
break;
}
freqout(11, 1, 38000);
irLeft = input(10);
freqout(1, 1, 38000);
irRight = input(2);
if (irLeft == irRight == 1) {
drive_goto(10,10);
back[i] = 10;
++i;
back[i]= 10;
++i;
}
if (irLeft == 0) {
drive_goto(20,10);
back[i] = 20;
++i;
back[i] = 10;
++i;
}
if (irRight == 0) {
drive_goto(10,20);
back[i]= 10;
++i;
back[i]= 20;
++i;
}
}
drive_goto(51, 0); // Make a 180 degree turn
drive_goto(51, 0);
//return
while (1) {
if (i == 0) {
break;
}
drive_goto(back[i], back[--i]);
--i;
}
return 0;
}
The robot successfully moves to the goal, but it does not move back to the starting point. What can the problem be?

You appear to have an off-by-one error. As you move forward, you track in variable i the index of the next available position in your movement history array. When you start the trip back, you use the current value of i as if it were instead the index of the last value recorded. On the way back you need to decrement i before each read, mirroring the behavior on the forward path of incrementing it after each write.

Related

how to see if there are 1 or 2 poker pairs in a hand in C

I am trying to develop a C program that checks if there are 1 or 2 pairs in a 5 card poker hand.
I am using a 5x3 array where every line is a card (the 3rd column being for the \0 character). Every time I execute the code it always shows the "two pairs" print.
I want to make sure that each letter (i, j, a, b) representing each line is different. Any help?
P.S.: This is for a university/college project, I have only started programming a few months ago from absolute scratch, so any detailed explanations on my mistakes would be very much appreciated :)
#include <stdio.h>
#include <stdlib.h>
char (cards[5][3])=
{
"5S", "6D", "4H", "KD", "5C"
};
int main ()
{
pair (cards[5][3]);
return 0;
}
void pair (char (arg[n][0]))
{
int i,j,a,b;
if (i!=j!=a!=b)
{
if ((arg[i][0]==arg[a][0])&&(arg[b][0]!=arg[j][0]))
{
printf("2 -> pair");
}
if ((arg[i][0]==arg[a][0])&&(arg[b][0]==arg[j][0]));
{
printf("3 -> two pairs");
}
if ((arg[i][0]!=arg[a][0])&&(arg[b][0]!=arg[j][0]))
{
printf("there is no pair");
}
}
else
{
printf("there is no pair");
}
}
The posted code has several issues, both logical and syntactical, some have been pointed out in the comments.
Just to pick one, consider this line
if ((arg[i][0]==arg[a][0])&&(arg[b][0]==arg[j][0]));
{
// This body will never be executed ^
}
I'd suggest to restart from scratch and to proceed in small steps. See, for instance, the following minimal implementation
// Include all the needed header files, not the unneeded ones.
#include <stdio.h>
// Declare the functions prototype before their use, they will be defined after.
int count_pairs(int n, char const cards[][3]);
// Always specify the inner size, ^ when passing a multidimensional array
void show_score(int n_pairs);
int have_the_same_value(char const *a, char const *b);
int main (void)
{
char hand[5][3] = {
// ^^^^^^ You could omit the 5, here
"5S", "6D", "4H", "KD", "5C"
};
int n_pairs = count_pairs(5, hand);
// Always pass the size ^ if there isn't a sentinel value in the array
show_score(n_pairs);
return 0;
}
// This is a simple O(n^2) algorithm. Surely not the best, but it's
// a testable starting point.
int count_pairs(int n, char const cards[][3])
{
// Always initialize the variables.
int count = 0;
// Pick every card...
for (int i = 0; i < n; ++i)
{
// Compare (only once) with all the remaining others.
for (int j = i + 1; j < n; ++j)
{ // ^^^^^
if ( have_the_same_value(cards[i], cards[j]) ) {
++count;
}
}
}
return count;
}
int have_the_same_value(char const *a, char const *b)
{
return a[0] == b[0];
}
// Interpret the result of count_pairs outputting the score
void show_score(int n_pairs)
{
switch (n_pairs)
{
case 1:
printf("one pair.\n");
break;
case 2:
printf("two pairs.\n");
break;
case 3:
printf("three of a kind.\n");
break;
case 4:
printf("full house.\n");
break;
case 6:
printf("four of a kind.\n");
break;
default:
printf("no pairs.\n");
}
}
Note that my count_pairs function counts every possible pair, so if you pass three cards of the same kind, it will return 3 (given AC, AS, AD, all the possible pairs are AC AS, AC AD, AS AD).
How to correctly calculate all the poker ranks is left to the reader.
Major improvements can be made to the pair function to make it slimmer. However, this answers your questions and solves several corner cases:
#include <stdio.h>
#include <stdlib.h>
void pairCheck(char hand[][2])
{
int pairCount = 0;
int tmpCount = 0;
char tmpCard = '0';
char foundPairs[2] = {0};
// Check Hand One
for(int i =0; i < 5; i++)
{
tmpCard = hand[i][0];
for(int j = 0; j < 5; j++)
{
if(tmpCard == hand[j][0] && i != j)
{
tmpCount++;
}
if(tmpCount == 1 && (tmpCard != foundPairs[0] && tmpCard != foundPairs[1]))
{
foundPairs[pairCount] = tmpCard;
pairCount++;
}
tmpCount = 0;
}
}
printf("Pair Count Hand One: %i\r\n",pairCount);
//Reset Variables
foundPairs[0] = 0;
foundPairs[1] = 0;
tmpCard = '0';
pairCount = 0;
// Check Hand One
for(int i =0; i < 5; i++)
{
tmpCard = hand[i][1];
for(int j = 0; j < 5; j++)
{
if(tmpCard == hand[j][1] && i != j)
{
tmpCount++;
}
if(tmpCount == 1 && (tmpCard != foundPairs[0] && tmpCard != foundPairs[1]))
{
foundPairs[pairCount] = tmpCard;
pairCount++;
}
tmpCount = 0;
}
}
printf("Pair Count Hand Two: %i",pairCount);
}
int main ()
{
char cards[5][2] = { {'5','H'},{'6','D'},{'4','H'},{'K','D'},{'5','C'}};
pairCheck(cards);
return 0;
}
This function will treat three, four, or five of a kind as a single pair. If you want a different behavior the change should be easy.

Snake Game implementation in C

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.

Replace a character with another character + Setting a tie game

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.

Simple problem moving enemy in game (C / SDL)

I'm hacking away at a simple game to teach myself C and I've come up against an infuriatingly simple problem that I haven't been able to Google an answer to.
Code follows, apologies for its noobie terribleness (criticisms appreciated!):
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#define AMOUNT_OF_ENEMIES 10
#define AMOUNT_OF_PIXELS_TO_MOVE 50.0
struct enemy
{
int alive;
SDL_Rect rect;
};
void create_enemy(struct enemy *position)
{
// Take a pointer to an array. Iterate through array looking for any 'dead' instances.
// (Re)initialise when found, ignore entirely if array is full of alive instances.
int j = 0;
while(position[j].alive == 1 && j < AMOUNT_OF_ENEMIES)
{
++j;
}
if(position[j].alive == 0)
{
position[j].alive = 1;
position[j].rect.y = 0;
}
}
void update_enemies(struct enemy *position)
{
// Iterate through a passed array looking for alive instances. If found increment vertical position,
// unless instance is at bottom of screen in which case it's marked as dead.
int j = 0;
while(j < AMOUNT_OF_ENEMIES)
{
if(position[j].alive == 1)
{
position[j].rect.y += 1;
if(position[j].rect.y > 570)
{
position[j].alive = 0;
}
}
++j;
}
}
int main(void)
{
// INITS *********************************************************************
int k;
int current_time = 0;
int previous_time = 0;
float difference_in_time = 0.0;
// Load SDL library
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
printf("Problem, yo\n");
return 1;
}
// Setup event queue
SDL_Event event;
// Create array to store enemys, initialise it
struct enemy *enemy_array = malloc(sizeof(struct enemy) * AMOUNT_OF_ENEMIES);
int j;
for(j = 0; j < AMOUNT_OF_ENEMIES; ++j)
{
enemy_array[j].alive = 0;
enemy_array[j].rect.x = 150;
enemy_array[j].rect.y = 0;
}
// Create an array to flag keypresses, initialise it
int pressed_keys[323];
int l;
for(l = 0; l < 323; ++l)
{
pressed_keys[l] = 0;
}
// Create surfaces
SDL_Surface *screen = SDL_SetVideoMode(300, 600, 0, SDL_HWSURFACE);
int black = SDL_MapRGB(screen->format, 0, 0, 0);
SDL_Surface *tower = SDL_LoadBMP("tower.bmp");
SDL_Rect tower_rect;
tower_rect.x = 50;
tower_rect.y = 0;
tower_rect.w = 200;
tower_rect.h = 600;
SDL_Surface *dude = SDL_LoadBMP("dude.bmp");
float dude_x = 0.0;
SDL_Rect dude_rect;
dude_rect.x = 120;
dude_rect.y = 500;
dude_rect.w = 60;
dude_rect.h = 100;
SDL_Surface *enemy = SDL_LoadBMP("enemy.bmp");
// GAME LOOP *****************************************************************
while(1)
{
current_time = SDL_GetTicks();
difference_in_time = (float)(current_time - previous_time) / 1000;
previous_time = current_time;
if(SDL_PollEvent(&event))
{
if(event.key.keysym.sym == SDLK_DOWN)
{
create_enemy(enemy_array);
}
else
{
switch(event.type)
{
case SDL_QUIT:
printf("NOOOOOO\n");
SDL_FreeSurface(screen);
SDL_FreeSurface(tower);
SDL_FreeSurface(enemy);
free(enemy_array);
SDL_Quit();
return 0;
case SDL_KEYDOWN:
pressed_keys[event.key.keysym.sym] = 1;
break;
case SDL_KEYUP:
pressed_keys[event.key.keysym.sym] = 0;
break;
}
}
}
if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
{
dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
{
dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
update_enemies(enemy_array);
SDL_FillRect(screen, NULL, black);
SDL_BlitSurface(tower, NULL, screen, &tower_rect);
for(k = 0; k < AMOUNT_OF_ENEMIES; ++k)
{
if(enemy_array[k].alive == 1)
{
SDL_BlitSurface(enemy, NULL, screen, &enemy_array[k].rect);
}
}
SDL_BlitSurface(dude, NULL, screen, &dude_rect);
SDL_Flip(screen);
}
return 0;
}
The issue arises at this part:
if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
{
dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
{
dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
The 'dude' object moves to the left correctly, but nothing happens when the right arrow key is pressed.
Adding a printf tells me the if statement is being executed correctly. Removing difference_in_time makes it work, so it's either something to do with that variable or the operation of it and AMOUNT_OF_PIXELS_TO_MOVE.
I just can't for the life of me figure out why the former block executes correctly and the latter (which is essentially the same thing) doesn't. I'm sure it's something simple I've overlooked but I'm going insane trying to find it.
Your problem is due to rounding.
For your "dude" you are using a SDL_Rect, that uses integer coordinates (short int if I remember correct).
You configured your dude speed to 50 and if your game is running at 60fps (probably due to its simplicity and it may be much more if vsync is off) you will get each frame a movement value of 0.83333.
This value will be truncated to a int and the result will be zero, for example, if dude.x is 10 and you press right, the calculated value will be 10.83 and when truncated this will result in 10.
For left, it works because the value is rounded down, assuming again dude.x is 10, when left is pressed, on the first iteration the calculated value would be 9.17, truncating this will give you 9.
Simple, bad and Hack Solution
Increase AMOUNT_OF_PIXELS_TO_MOVE to a higher value that forces the int to increase, this will fix the problem.
Good Solution
Does not use SDL_Rect for storing your characters position, create a "MyRect" and use float values in it and only does rounding when drawing the character. Actually you only need to store the character position, so I would create a Point2D struct with only x and y and use this to keep track of characters position.

Simplify/Neatify this two-way loop?

I've got my wires crossed somewhere (or I had not enough sleep). I need a two-way loop, and my current code is just plain ugly.
Problem: I am running along a linear datastructre using an index. I have an starting index, lets say 120. I want to run alternating into both directions.
Example:
120,121,119,122,118,123,117,...
I have a stopping criterion which needs to be met for each direction separately. If it is met for one direction, I only want to run into the other direction, if both are met I need to exit the loop. In addition I need to stop if the next index is invalid (end of data structure, say smaller than 0 or bigger than 200).
Example: Stopping execution at 116 backwards and 130 forward:
120,121,119,122,118,123,117,124,116,(break),125,126,127,128,129,130.
Running into one direction first, then the other one is unfortunately not an option.
My current code is plain ugly. It is a lot of lines without containing any "productive" code. Only iteration logic:
int start_idx = 120;
int forward_idx = start_idx;
int backward_idx = start_idx;
bool next_step_forward = true; //should next step be forward or backward?
int cur_idx;
while(backward_idx >= 0 || forward_idx >= 0)
{
if(next_step_forward //if we should step forward
&& forward_idx >= 0) //and we still can step forward
{
cur_idx = ++forward_idx;
if(forward_idx >= 200) //200 is fictive "max index"
{
next_step_forward = false;
forward_idx = -1; //end of data reached, no more stepping forward
continue;
}
if(backward_idx >= 0)
{
next_step_forward = false;
}
}
else if(!next_step_forward
&& backward_idx >= 0)
{
cur_idx = --backward_idx;
if(backward_idx < 0) //beginning of data reached, no more stepping backward
{
next_step_forward = true;
continue;
}
if(forward_idx >= 0)
{
next_step_forward = true;
}
}
else
{
next_step_forward = !next_step_forward; //ever hit?, just security case
continue;
}
//loop body
//do something with cur_idx here
if(stoppingCriterionMet())
{
if(cur_idx > start_idx)
{ //this was a forward step, stop forward stepping
forward_idx = -1;
}
else
{ //this was backward step, stop backward stepping
backward_idx = -1;
}
}
}
Am I missing anything? Any hints appreciated. Thanks.
Edit 1: There are lots of very nice answers, which put "do something with cur_idx" into a separate function. While this is a perfect idea for the way my question was asked, I prefer putting the iterating code somewhere else and leave the productive code there. I have a long algorithm and want to split it up after it is finished to minimize rearangement work.
How about this?
void do_loop(SomeType *arr, int start, int low, int high, int arr_max)
{
int downwardIndex, upwardIndex;
downwardIndex = upwardIndex = start;
while (downwardIndex > 0 && upwardIndex < arr_max) {
if (downwardIndex < low && upwardIndex > high) {
break;
}
if (downwardIndex > low) {
processElement(arr[downwardIndex]);
downwardIndex--;
}
if (upwardIndex < high) {
processElement(arr[upwardIndex]);
upwardIndex++;
}
}
}
It so happened that I coded almost this problem today. And I used a C# iterator function to do it. But I think you want a more generic solution.
If you use a language where you can build your own iterators (C++,Java,C#), it's easy. You just make a custom iterator that initially spits out numbers starting from the center. Then you give the iterator an extra function to tell it to stop running in the current direction.
If you're doing something like this in C (it looks C to me), you can mimic this with a struct containing the iterator state, and functions that you call to step it forward or stop it.
First pass at hacking this (assuming C - adaptations needed for other languages, but the concepts are basically language neutral):
void pass1(int start_x, int lo_limit, int hi_limit)
{
assert(start_x >= lo_limit && start_x <= hi_limit);
int lo_x = start_x - 1;
int hi_x = start_x + 1;
Process(start_x);
if (StopCriterion(start_x))
return; // Is that correct?
while (lo_x >= lo_limit && hi_x <= hi_limit)
{
Process(lo_x);
if (StopCriterion(lo_x))
lo_x = lo_limit - 1;
else
lo_x--;
Process(hi_x);
if (StopCriterion(hi_x))
hi_x = hi_limit + 1;
else
hi_x++;
}
while (lo_x >= lo_limit)
{
Process(lo_x);
if (StopCriterion(lo_x))
lo_x = lo_limit - 1;
else
lo_x--;
}
while (hi_x <= hi_limit)
{
Process(hi_x);
if (StopCriterion(hi_x))
hi_x = hi_limit + 1;
else
hi_x++;
}
}
It is not clear what should happen if the starting position matches the stop criterion. Should the search stop altogether, or should it continue upwards, or downwards, or both ways. I chose 'stop altogether', but a case could be made for any of the options listed. In the case of 'both', you would not even bother to run the stop criterion check.
I also chose to do the lower before the upper direction; it is clearly trivially reversed. The order of the final two loops doesn't matter because if both directions terminate in the same iteration, neither trailing loop is executed; if only one direction is terminated, the corresponding loop won't execute at all - only the other will.
Since there is still repeated code in there:
void pass2(int start_x, int lo_limit, int hi_limit)
{
assert(start_x >= lo_limit && start_x <= hi_limit);
int lo_x = start_x - 1;
int hi_x = start_x + 1;
Process(start_x);
if (StopCriterion(start_x))
return; // Is that correct?
while (lo_x >= lo_limit && hi_x <= hi_limit)
{
Process_lo(&lo_x, lo_limit);
Process_hi(&hi_x, hi_limit);
}
while (lo_x >= lo_limit)
Process_lo(&lo_x, lo_limit);
while (hi_x <= hi_limit)
Process_hi(&hi_x, hi_limit);
}
void Process_lo(int *lo_x, int lo_limit)
{
Process(*lo_x);
if (StopCriterion(*lo_x))
*lo_x = lo_limit - 1;
else
*lo_x--;
}
void Process_hi(int *hi_x, int hi_limit)
{
Process(*hi_x);
if (StopCriterion(*hi_x))
*hi_x = hi_limit + 1;
else
*hi_x++;
}
Visibility controls (static functions) etc left out as details of the implementation language.
This is how I'd approach it in C#:
const int UPPER_BOUND = 200;
const int LOWER_BOUND = 0;
const int START = 120;
bool foundlower = false, foundupper = false;
int upper, lower;
upper = lower = START;
while (!foundlower || !foundupper) {
if (!foundlower) {
if (--lower <= LOWER_BOUND) foundlower = true;
if (stoppingCriterionMet(lower)) foundlower = true;
}
if (!foundupper) {
if (++upper >= UPPER_BOUND) foundupper = true;
if (stoppingCriterionMet(upper)) foundupper = true;
}
}

Resources