So I have been creating a game in C where you start with a bunch of rooms, and you have to connect them with hallways, so what I have been doing is run a bfs on the screen and then get the through a whereFrom array. But so far it only works if the xStart and yStart are (0,0), if they are anything else something weird happens to the output, I will first show you my code.
u[0]=yStart;
u[1]=xStart;
eq(q,u);
int count = 0;
/*while there are elements in the q*/
while(dq(q,&u))
{
uX = u[1];
uY = u[0];
/*if(uX ==3)
mvprintw(++count,10,"%d %d",uY,uX);
*/
/*break if at the end*/
if((uX == xEnd) && (uY == yEnd))
{
break;
}
seen[uY][uX]=1;
/*Neighbours around the current cell*/
for(i=0;i<4;++i)
{
vX = uX + neighbours[i][1];
vY = uY + neighbours[i][0];
if(!bounds(vX,vY)||seen[vY][vX])
{
continue;
}
c=map[vY][vX];
if((c == '+')||(c=='|')||(c=='-')||(c=='.'))
{
continue;
}
if((p->prev[vY][vX][0]==9999)&&(p->prev[vY][vX][1]==9999))
{
p->prev[vY][vX][1]=uX;
p->prev[vY][vX][0]=uY;
}
u[0]=vY;
u[1]=vX;
/*enqueue*/
eq(q,u);
}
}
uX = xEnd;
uY = yEnd;
coord = malloc(sizeof(int)*2);
while((uX<COL)&&(uY<ROW)&&(p->prev[uY][uX][0]!=9999)&&(p->prev[uY][uX][1]!=9999))
{
count++;
coord[0]=uY;
coord[1]=uX;
uY = p->prev[uY][uX][0];
uX = p->prev[uY][uX][1];
if((uY!=coord[0])&&(coord[1]!=uX))
{
c = map[coord[0]][uX];
if((c == '|')||(c=='-')||(c=='+')||(c=='.'))
{
p->screen[uY][coord[1]]=1;
}
else
{
p->screen[coord[0]][uX]=1;
}
}
p->screen[coord[0]][coord[1]]=1
}
So even if I take out all walls and obstructions, it will only construct a path if it starts from (0,0), if the xStart and yStart are non zero, the path won't even show up. By the way dq and eq and dequeue and enqueue respectively, and they work perfectly, I already tested it.
Related
When the coef is 0, I used continue to not print, but only printTerm(a) comes out and the printTerm(b) part does not come out.
When I delete the (if & continue) statement, both printTerm(a) and printTerm(b) appear, so it seems that there is a problem here (if & continue) statement.
How can I solve this?
int main() {
a[0].coef = 2;
a[0].expon = 1000; // 2x^1000
a[1].coef = 1;
a[1].expon = 2; // x^2
a[2].coef = 1;
a[2].expon = 0; // 1
b[0].coef = 1;
b[0].expon = 4; // x^4
b[1].coef = 10;
b[1].expon = 3; // 10x^3
b[2].coef = 3;
b[2].expon = 2; // 3x^2
b[2].coef = 1;
b[2].expon = 0; // 1
printTerm(a);
printTerm(b);
return 0;
}
void printTerm(polynomial *p) {
int i=0;
printf("polynomial : ");
while(p[i].expon != -1) {
if(p[i].coef == 0) continue;
printf("%dx^%d", p[i].coef, p[i].expon);
i++;
if(p[i].expon != -1 && p[i].coef > 0) printf(" + ");
}
printf("\n");
}
Because you only increment i if p[i].coef is not equal to 0.
If p[i].coef == 0 it skips the increment part and function is stuck in infinite loop, always checking the same array item.
EDIT:
Way to fix this:
Instead of if(p[i].coef == 0) continue; use:
if (p[i].coef == 0)
{
i++;
continue;
}
This way while loop evaluetes next array item instead of being stuck on the same.
I have made a (pretty bad) line follower.
Here is a sketch to roughly know the shape of the robot and location of the treads and sensors
[-] 0 0 [-] // 0 = color sensor
[-]------[-] // - = robot body
[-]------[-] // [-] = tank tread
[-] [-]
Here's what it does:
get Red, Green & Blue, make average of sensor 1 readings, do the same for 2
subtract to get value
this value will go through the PID part
steer with calculated steering
repeat (all of this is in a loop)
I use RGB and not reflected intensity (which is what is commonly used), because sometimes I need to detect if there's green color under the sensor (if there is, turn).
The real problem comes with the steering part. Unfortunately, it only accelerates a motor, meaning that in very tight turns we just lose the line.
Optimally, it should compensate a bit with the other motor (maybe going in the other direction?), but I am not sure how to calculate the speed of the motor, nor how to enforce this very strict line following policy.
Here is the code (I am also very grateful for any kind of tips on how to clean up the code! This is my first project in C :D ). I am not asking to read it all (it is pretty long), you could also just look at the steering function, and work your way back to rawFollowLine, this should hopefully shorten the code.
void rawFollowLine(int speed, float Kp, float Ki, float Kd){
_checkInit();
set_sensor_mode(sn_lx_color, "RGB-RAW");
set_sensor_mode(sn_rx_color, "RGB-RAW");
//printAllSensors();
int wasBlackCounter = 0;
int wasBlack = 0;
int lastBlack = 0;
for (int i = 0; i < 2000; i++)
{
if (isTerminating == 1)
{
killMotors(0);
break;
}
int greenCheck = rawGreenCheck(&wasBlack, &wasBlackCounter, &lastBlack);
if (wasBlack == 1){
wasBlackCounter++;
if (wasBlackCounter > 50){
wasBlackCounter = 0;
wasBlack = 0;
}
}
if (greenCheck == 1)
{
// lx is green
killMotors(1);
usleep(400 * 1000);
drive(200, 70);
waitIfMotorIsRunning();
killMotors(1);
pivotTurn(-90);
}
else if (greenCheck == 2)
{
// rx is green
killMotors(1);
usleep(400 * 1000);
drive(200, 70);
waitIfMotorIsRunning();
killMotors(1);
pivotTurn(90);
}
else if (greenCheck == 3)
{
// both rx and lx are green
killMotors(1);
turn(180);
}
else if (greenCheck == 5)
{
if(lastBlack == 2)
{
lastBlack = 0;
drive(100, -200);
//pivotTurn(50);
}
else if (lastBlack == 1)
{
lastBlack = 0;
drive(100, -200);
//pivotTurn(-50);
} else {
pidLineRaw(speed, Kp, Ki, Kd, &lastBlack);
}
}
else
{
pidLineRaw(speed, Kp, Ki, Kd, &lastBlack);
}
}
killMotors(1);
}
int rawGreenCheck(int *wasBlack, int *wasBlackCounter, int *lastBlack)
{
// Some documentation
// return nums:
// 3 = double green
// 2 = right green
// 1 = left green
// 0 = no green
int lx_red;
int lx_green;
int lx_blue;
int rx_red;
int rx_green;
int rx_blue;
get_sensor_value(0, sn_lx_color, &lx_red);
get_sensor_value(0, sn_rx_color, &rx_red);
get_sensor_value(1, sn_lx_color, &lx_green);
get_sensor_value(1, sn_rx_color, &rx_green);
get_sensor_value(2, sn_lx_color, &lx_blue);
get_sensor_value(2, sn_rx_color, &rx_blue);
//printf("rx_red %d\n", rx_red);
rx_red = (rx_red * rx_ratio_r);
rx_green = (rx_green * rx_ratio_g);
rx_blue = (rx_blue * rx_ratio_b);
//printf("rx_red (again) %d\n", rx_red);
if(
lx_red < 55 &&
lx_green > 90 &&
lx_blue < 55 &&
rx_red < 55 &&
rx_green > 90 &&
rx_blue < 55
)
{
// rx and lx see green
if (*wasBlack == 1)
{
// Apparently we crossed an intersection!
printf("Apparently we crossed an intersection!\n");
// We need to go straight.
*wasBlack = 0;
*wasBlackCounter = 0;
return 0;
}
else
{
return 3;
}
}
else if(lx_red < 55 && lx_green > 90 && lx_blue < 55)
{
// lx sees green
return 1;
}
else if(rx_red < 55 && rx_green > 90 && rx_blue < 55)
{
// rx sees green
return 2;
}
else if(rx_red < 50 && rx_green < 50 && rx_blue < 50 && lx_red < 50 && lx_green < 50 && lx_blue < 50)
{
// rx and lx see black
// this is needed if the intersection has the green tiles after the black line
printf("We are on the line? Is this an intersection?\n");
*wasBlack = 1;
return 0;
}
else if(lx_red < 55 && lx_green < 55 && lx_blue < 55)
{
// lx = right sees black
// this is needed if the intersection has the green tiles after the black line
//printf("We are on the line? Is this an intersection?\n");
killMotor(1, motor[R]);
rotateTillBlack(motor[L], sn_rx_color);
//printf("ASS2\n");
return 0;
}
else if(rx_red < 55 && rx_green < 55 && rx_blue < 55)
{
// rx = left sees black
killMotor(1, motor[L]);
rotateTillBlack(motor[R], sn_lx_color);
//printf("ASS1\n");
return 0;
}
//*lx_color_status = 0;
//*rx_color_status = 0;
*lastBlack = 0;
return 0;
}
void pidLineRaw(int speed, float Kp, float Ki, float Kd, int *lastBlack)
{
int red_lx_color;
int red_rx_color;
int green_lx_color;
int green_rx_color;
int blue_lx_color;
int blue_rx_color;
int lx_color;
int rx_color;
int last_error = 0;
int integral = 0;
int derivative = 0;
//float Kp = 0.1;
//float Ki = 0;
//float Kd = 0;
//set_sensor_mode(sn_lx_color, "COL-REFLECT");
//set_sensor_mode(sn_rx_color, "COL-REFLECT");
get_sensor_value(0, sn_lx_color, &red_lx_color);
get_sensor_value(0, sn_rx_color, &red_rx_color);
get_sensor_value(1, sn_lx_color, &green_lx_color);
get_sensor_value(1, sn_rx_color, &green_rx_color);
get_sensor_value(2, sn_lx_color, &blue_lx_color);
get_sensor_value(2, sn_rx_color, &blue_rx_color);
lx_color = (red_lx_color + green_lx_color+ blue_lx_color)/3;
rx_color = ( (red_rx_color*rx_ratio_r) + (green_rx_color*rx_ratio_g) + (blue_rx_color*rx_ratio_b))/3;
if(*lastBlack == 0)
{
int error = lx_color - rx_color;
integral = integral + error;
derivative = error - last_error;
last_error = error;
int steering_val = (error * Kp) + (integral * Ki) + (derivative * Kd);
// printf("error: %d\nsteering: %d\n",error, steering_val);
move_steering(-steering_val, speed, 1, 0);
} else if (*lastBlack == 1)
{
printf("lx_color_status\n");
move_steering(35, speed, 1, 0);
move_steering(-2, speed, 1, 0);
}
else if (*lastBlack == 2)
{
printf("rx_color_status\n");
move_steering(-35, speed, 1, 0);
move_steering(2, speed, 1, 0);
}
else
{
printf("HMMM: %d\n", *lastBlack);
exit(666);
}
}
static void _getSteeringSpeed(int speed, int *lx_speed, int *rx_speed, int steering)
{
if(steering > 100 || steering < -100)
{
printf("Yo wtf steering is %d\n", steering);
}
else
{
int speed_factor = (50 - abs(steering)) / 50;
*lx_speed = speed;
*rx_speed = speed;
if(steering >= 0)
{
*rx_speed = *rx_speed * speed_factor;
}
else
{
*lx_speed = *lx_speed * speed_factor;
}
}
}
Some parts are omitted, yes, they are not required to solve the problem.
I am also extremely sorry as there might be unused variables and such. I am working on refactoring the project, I'll update the post when I'm done.
So, summing everything up, I need to make sure that the steering part properly turns and follows the line. How do I do that? Is the code that I wrote even suitable? I'm guessing the steering itself might need some sort of feedback loop, to check if it's on the line?
I'm creating a game where you can move a dot along the x axis in the middle of the screen and there will be elements falling from the top that you will need to try and dodge, clearly for this I need some form of collision detection, which I have implemented and it appears to work correctly.
My problem is that when the character (dot) has moved towards the object and the collision has occurred, you are no longer able to move the character, it simply stays in a fixed position. This does not happen when the character collides with the edges of the window, however as you will see below both the window collision and object collision have the same code to run.
Main game loop:
while(running) {
// Queue of the events happening
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
running = false;
}
else if(event.type == SDL_KEYDOWN && event.key.repeat == 0) {
switch(event.key.keysym.sym) {
case SDLK_UP:
//sprite->yVel -= VELOCITY;
break;
case SDLK_DOWN:
//sprite->yVel += VELOCITY;
break;
case SDLK_LEFT:
sprite->xVel -= VELOCITY;
break;
case SDLK_RIGHT:
sprite->xVel += VELOCITY;
break;
}
}
else if(event.type == SDL_KEYUP && event.key.repeat == 0) {
switch(event.key.keysym.sym) {
case SDLK_UP:
//sprite->yVel += VELOCITY;
break;
case SDLK_DOWN:
//sprite->yVel -= VELOCITY;
break;
case SDLK_LEFT:
sprite->xVel += VELOCITY;
break;
case SDLK_RIGHT:
sprite->xVel -= VELOCITY;
break;
}
}
} // Poll event loop
float timeStep = getTicks(ticks) / (float) 1000;
move(sprite, timeStep, WINDOW_WIDTH, WINDOW_HEIGHT, head);
startTimer(ticks);
// Clear window then draw image
SDL_RenderClear(rend);
SDL_RenderCopy(rend, background->element, NULL, NULL);
SDL_RenderCopy(rend, sofa->element, NULL, &sofa->dest);
setPosition(sprite, sprite->xPos, sprite->yPos);
SDL_RenderCopy(rend, sprite->element, NULL, &sprite->dest);
SDL_RenderPresent(rend);
capFrameRate(timeStep);
} // Main game loop
Move and Collision functions:
void move(Character *c, float timeStep, const int WIDTH, const int HEIGHT, Scene *scene) {
c->xPos += c->xVel * timeStep;
// Collision check for the walls
if(((c->xPos < 0) || (c->xPos + c->dest.w > WIDTH)) || (collision(c, scene))) {
c->xPos -= c->xVel * timeStep;
}
}
bool collision(Character *character, Scene *scene) {
if(SDL_HasIntersection(&character->dest, &scene->element->dest)) {
return true;
}
else {
if(scene->nextElement == NULL) {
return false;
}
else {
collision(character, scene->nextElement);
}
}
return false;
}
As there will be a few elements falling from the top of the screen I've implemented a Linked list for those, hence why the recursion on the collision function. If anyone has any idea on why the character does not move after collision I'll be very grateful.
My guess: your collision(c, scene) method looks at collisions for the current time step. In that case, your if statement in the move function
// \/ This here is the problem -- if you're currently colliding with an object you don't allow any movement, even if you're moving out of the object
if(((c->xPos < 0) || (c->xPos + c->dest.w > WIDTH)) || (collision(c, scene))) {
c->xPos -= c->xVel * timeStep;
}
the player is not allowed to move after she has collided with an object. The solution is to check for collision before you take the step:
float newX = c->xPos + c->xVel*timeStep;
float newY = ...;
if (!collision(newX, newY, scene)) {
c->xPos = newX;
...
}
Is it possible to call a line number in embedded C that is outside of the function?
Simple goto label commands can't work because I am in the if statement loop: I want to restart the function once the error is greater than 200.
void followWall(void)
{
begin:
int desired = getADC(); //store the first ADC reading as the desired distance from the wall
int right = 200; //pre set all variables to be called in the drive function
int left = 200; //ints are needed here for bit masking later on to stop overflow
char rightH = 0;
char leftH = 0;
float k = 0.5; //constant to times the error to fine tune the response
drive(rightH,right,leftH,left); //drive the robot to the pre set variables
while( bumpFlag == 0 ) //while the robot has not been bumped or encounted a cliff
{
int actual = getADC(); //call a new ADC reading everytime at start of while as the current reading
rightH = 0;
leftH = 0; //set variables back to default to stop constant increase and decrease in variables
left = 200;
right = 200;
char error = abs(actual-desired); //calculate the error by minusing the actual distance to the desired
if(motorAngle < 180) //wall on left between 1st and 2nd quadrant
{
if(error > 200)
{
stop();
moveStepper(33,0);
goto begin;
}
if (actual > desired)
{
right -=((error)*k);
left += ((error)*k);
}
else if (actual < desired)
{
left -=((error)*k);
right +=((error)*k);
}
}
else if (motorAngle > 180)
{
if(error > 200)
{
stop();
moveStepper(33,1);
goto begin;
}
if (actual > desired)
{
left -=((error)*k);
right +=((error)*k);
}
else if (actual < desired)
{
right -=((error)*k);
left +=((error)*k);
}
}
drive(rightH,right,leftH,left); bumpSensor();
setLCDCursor(0x09);
writeLCDNumber(convert(actual)); //constantly write the converted AC value on the LCD
}
stop(); //stop the robot
}
You should restructure your code to avoid a GOTO. Another loop is needed. Something like this.
void followWall(void)
{
repeat = 0;
do // add this loop here
{
...
...
while( bumpFlag == 0 )
{
repeat = 0;
..
..
if(motorAngle < 180)
{
..
if(error > 200)
{
..
..
repeat = 1;
break;
}
}
else if (motorAngle > 180)
{
..
if(error > 200)
{
..
..
repeat = 1;
break;
}
}
}
} while (repeat == 1);
}
I have a function to check the valid moves in my reversi game. I look at the unoccupied spaces, and check if an adjacent space in any 8 directions are the opposite piece. (If I'm black, I search for white) Now, if I find a piece that's adjacent, I should keep looking towards that direction and see if my own piece is at the end, then I return true, else if its an unoccupied space or off the board boundaries, I return false.
My function doesn't seem to work properly as I print out the wrong moves.
bool checkLegalInDirection(char boardgame[26][26], int size, int row, int col, char color) {
int currentRow, currentCol;
for (int deltaRow = -1; deltaRow < 2; deltaRow++) {
for (int deltaCol = -1; deltaCol < 2; deltaCol++) {
if (deltaRow == 0 && deltaCol == 0) {
break;
} else {
row = row + deltaRow;
col = col + deltaCol;
if (positionInBounds(size, row, col)) {
while (boardgame[row][col] == OppositeColor(color)) {
currentRow = row + deltaRow;
currentCol = col + deltaCol;
if (positionInBounds(size, currentRow, currentCol)) {
if (boardgame[currentRow][currentCol] == color) {
return true;
} else {
return false;
}
}
}
}
}
}
}
}
deltaRow and deltaCol are the increments that go in each direction and add one time to keep searching in a specified location. PositioninBounds is a function I have to make sure my searches are within the board boundaries. My deltarow and deltacol cannot be both 0 at the same time, so somehow I need to skip that step, (which I probably did wrong). Oppositecolor is a function that returns me the opposite color of my own piece.
I think your code has multiple mistakes.
Your code is incorrectly breaking the for loop when you should be continuing with the next iteration (as mentioned by chux).
Change...
if (deltaRow == 0 && deltaCol == 0) {
break;
} else {
...
}
to either chux's suggestion...
if (deltaRow == 0 && deltaCol == 0) {
continue;
} else {
...
}
or to an even simpler solution...
if (deltaRow != 0 || deltaCol != 0) {
...
}
Inside the deltaRow/deltaCol loops, your code is incorrectly modifying the original row/col values which your code will need in later loop iterations.
You can change...
row = row + deltaRow;
col = col + deltaRow;
to...
currentRow = row + deltaRow;
currentCol = col + deltaRow;
Inside the while loop, your code is incorrectly returning false. You can not return false until you have completed all the for loops.
Before entering the while loop, you need to check that the adjacent space is in bounds and opposite color...
if (positionInBounds(size, currentRow, currentCol) && boardgame[currentRow][currentCol] == OppositeColor(color)) {
If so, then skip over all adjacent opposite colors...
while (positionInBounds(size, currentROw, currentColor) && boadgame[currentRow][currentCol] == OppositeColor(color)) {
{
currentRow = currentRow + deltaRow;
currentCol = currentCol + deltaCol;
}
After you have skipped over opposite colors then you need to check for same color. If so then return true.
if (positionInBOunds(size, currentRow, currentCol) && boardgame[currentRow][currentCol] == color) {
return true;
}
You code should only return false after checking all directions...
for (int deltaRow = -1; deltaRow < 2; deltaRow++) {
for (int deltaCol = -1; deltaCol < 2; deltaCol++) {
....
}
}
return false;