Finding a spotlight vector in openGL - c

I'm trying to find the proper vector for a direction of a spot light I have (I am trying to make it flashlight-like). I want it to face the same direction as the camera is always facing, like you're holding a flashlight out in front of you.
I can't seem to find the right directional vector, however.
At the moment, I have the light sort of following the front/back movement of the camera, but not the turn angle. In addition, the actual spot is pointed upwards, instead of directly ahead, like I want.
I know all the normals of the individual objects are working; I tested just general lighting already.
I'll just post code that's relevant to the question. If you really need my whole code, please say so.
Light code:
float sco=20; // Spot cutoff angle
float Exp=0; // Spot exponent
float Ambient[] = {0.01*ambient ,0.01*ambient ,0.01*ambient ,1.0};
float Diffuse[] = {0.01*diffuse ,0.01*diffuse ,0.01*diffuse ,1.0};
float Specular[] = {0.01*specular,0.01*specular,0.01*specular,1.0};
// Light direction
float Position[] = {Ox+3, 2, Oz,1};
float Direction[] = {Ox+lx, here, Oz+lz, 0};
glLightfv(GL_LIGHT0,GL_AMBIENT ,Ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE ,Diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,Specular);
glLightfv(GL_LIGHT0,GL_POSITION,Position);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,Direction);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,sco);
glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,Exp);
Camera code:
// Camera Values
double Ox=0, Oz=0;
float Oy=1.0;
float angle = 0.0;
float lx=0.0,lz=-1.0;
float deltaAngle = 0.0;
float deltaMove = 0;
double here;
void computePos(float deltaMove) {
Ox += deltaMove * lx * 0.1f;
Oz += deltaMove * lz * 0.1f;
}
void computeDir(float deltaAngle) {
angle += deltaAngle;
lx = sin(angle);
lz = -cos(angle);
}
void display() {
here = 2.0f*Oy;
if (deltaMove)
computePos(deltaMove);
if (deltaAngle)
computeDir(deltaAngle);
gluLookAt(Ox,2,Oz, Ox+lx, here, Oz+lz, 0,1,0);
}
void key(unsigned char ch,int x,int y) {
// Exit on ESC
if (ch == 27)
exit(0);
// WASD controls
else if (ch == 'a' || ch == 'A')
deltaAngle = -0.01;
else if (ch == 'd' || ch == 'D')
deltaAngle = 0.01;
else if (ch == 'w' || ch == 'W') {
collidefront=collision(1);
collidextra=collision(3);
if (collideback == 2 && collidextra == 3) { deltaMove = 0; collideback = 0; }
else if (collideback == 2) { deltaMove = 0.1; collidefront = 0;}
else if (collidefront == 1) deltaMove = 0;
else
deltaMove = 0.1;
}
else if (ch == 's' || ch == 'S') {
collideback=collision(2);
if (collidefront == 1) { deltaMove = -0.3; collidefront = 0; }
else if (collideback == 2) deltaMove = 0;
else
deltaMove = -0.1;
}
else if ((ch == 'e' || ch == 'E') && here < 4)
Oy += 0.01;
else if ((ch == 'c' || ch == 'C') && here > .5)
Oy -= 0.01;
Project(fov,asp,dim);
glutPostRedisplay();
}
Thank you for your help.

Since you are using gluLookAt, you can easily compute the vector subtracting the center and the eye:
(...)
gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
(...)
spotlightVecX = centerX - eyeX;
spotlightVecY = centerY - eyeY;
spotlightVecZ = centerZ - eyeZ;
You may normalize it after you calculate the vector.
Hope it helps.

Related

if statement doesn't work on a triangle type function

I'm a complete newbie, so please excuse me.
I tried using online compiler but they unresponsive, and I get no return value (or return 0 for whatever I enter)
I tried to write a function that check if triangle is right, isosceles or both, and return 1,2,3 respectively, all other cases should return 0.
int main() {
int TriangleType(unsigned angle1, unsigned angle2) {
unsigned angleSum = angle1 + angle2;
if (angleSum >= 180) {
return 0;
}
/* if triangle is right ---> */
if (angle1==90 || angle2==90 || angleSum==90) {
/*if it is also an isosceles --->*/
if (angle2==45 || angle1==45) {
return 3;
}
return 1;
}
/*check if it only a isosceles*/
if (angle1==(180-angle2)/2 ||
angle2== (180-angle1)/2 ||
angle1==angle2) {
return 2;
}
return 0;
}
TriangleType(110, 111);
}
First, don't try to use nested functions in C. Pulling that function out of main.
int TriangleType(unsigned angle1, unsigned angle2) {
unsigned angleSum = angle1 + angle2;
if (angleSum >= 180) {
return 0;
}
/* if triangle is right ---> */
if (angle1==90 || angle2==90 || angleSum==90) {
/*if it is also an isosceles --->*/
if (angle2==45 || angle1==45) {
return 3;
}
return 1;
}
/*check if it only a isosceles*/
if (angle1==(180-angle2)/2 ||
angle2== (180-angle1)/2 ||
angle1==angle2) {
return 2;
}
return 0;
}
int main() {
TriangleType(110, 111);
}
Second, this doesn't do anything with the return value from the function, so of course you see no output.
int main(void) {
switch (TriangleType(110, 111)) {
case 1:
printf("Right triangle\n");
break;
case 2:
printf("Isosceles triangle\n");
break;
case 3:
printf("Both types\n");
break;
default:
printf("None of the above\n");
}
return 0;
}
Code is functionally wrong
Even after re-organizing and moving the nested function, code attempts to be clever and not perform simple tests.
if (angle1 == (180 - angle2) / 2 || angle2 == (180 - angle1) / 2 || angle1 == angle2) fails in cases like TriangleType(45,89) --> 2 as (180 - angle2) / 2 rounds down. angle1 * 2 == (180 - angle2) would make more sense.
TriangleType(90, 90), where the 3rd angle is 0, returns 0. That is asymmetric. TriangleType(0, 90), TriangleType(90, 0) do not return 0.
TriangleType(0, 0) returns 2. I would expect that to return 0, a rejected triangle.
Below is a test harness for OP to use and test TriangleType().
#include <stdio.h>
int TriangleType(unsigned angle1, unsigned angle2) {
unsigned angleSum = angle1 + angle2;
if (angleSum >= 180) {
return 0;
}
/* if triangle is right ---> */
if (angle1 == 90 || angle2 == 90 || angleSum == 90) {
/*if it is also an isosceles --->*/
if (angle2 == 45 || angle1 == 45) {
return 3;
}
return 1;
}
/*check if it only a isosceles */
if (angle1 == (180 - angle2) / 2 || angle2 == (180 - angle1) / 2
|| angle1 == angle2) {
return 2;
}
return 0;
}
int my_TriangleType(unsigned angle1, unsigned angle2) {
unsigned angle3 = 180 - angle1 - angle2;
if (angle1 >= 180 || angle2 >= 180 || angle3 >= 180) {
return 0;
}
if (angle1 == 0 || angle2 == 0 || angle3 == 0) {
return 0;
}
int retval = angle1 == 90 || angle2 == 90 || angle3 == 90 ? 1 : 0;
if (angle1 == angle2 || angle2 == angle3 || angle3 == angle1)
retval += 2;
return retval;
}
#include <string.h>
#define MAX_LIMIT 127
int main() {
printf("score:%d my_score:%d\n", TriangleType(45,89), my_TriangleType(45,89));
int error_count = 0;
int flags[4][4] = {0};
for (unsigned angle1 = 0; angle1 <= 181; angle1++) {
for (unsigned angle2 = 0; angle2 <= 181; angle2++) {
int score = TriangleType(angle1, angle2);
int my_score = my_TriangleType(angle1, angle2);
if (score != my_score) {
error_count++;
if (flags[score][my_score] == 0) {
flags[score][my_score] = 1;
printf("%3d angle1:%2u angle2:%2u score:%d my_score:%d\n", //
error_count, angle1, angle2, score, my_score);
}
}
}
}
printf("total errors:%d\n", error_count);
return 0;
}
Output:
score:2 my_score:0
1 angle1: 0 angle2: 0 score:2 my_score:0
2 angle1: 0 angle2:90 score:1 my_score:0
total errors:181
another_TriangleType() could be made that is more efficient than my_TriangleType(), yet it would needed to functionally match.
Well your questions is lacking some information, but I assume you got as inputs of your program, two angles.
THe fisrt thing we need to think is:
If you got a right triangle, than there is one of those values equals 90 degrees, instead the sum of them must be 90.
On the other hand, if you got an isosceles triangle you should have 2 equal values, instead you must have the 180 deg - sum of both angles should result in one of those two.
Let's try to code this out:
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define RIGHT 0x01
#define ISOSCELES 0x02
#define BOTH 0x03
// If you got a right triangle, than there is one of those values equals 90 degrees, instead the sum of them must be 90.
int bIsRightTriangle(int iAngDeg1, int iAngDeg2){
if ( iAngDeg1 == 90 || iAngDeg2 == 90 )
return TRUE;
if ( (iAngDeg1 + iAngDeg2) == 90 )
return TRUE;
return FALSE;
}
// On the other hand, if you got an isosceles triangle you should have 2 equal values,
// instead you must have the 180 deg - sum of both angles should result in one of those two.
int bIs_IsoscelesTriangle(int iAngDeg1, int iAngDeg2){
int iAngDeg3 = 180 - iAngDeg1 + iAngDeg2;
if ( iAngDeg1 == iAngDeg2 )
return TRUE;
if ( (iAngDeg3 == iAngDeg1) || (iAngDeg3 == iAngDeg2) )
return TRUE;
return FALSE;
}
int iGetTriangleTypeByAngles(int iAngDeg1, int iAngDeg2){
int iReturnType = 0;
iReturnType = bIsRightTriangle(iAngDeg1, iAngDeg2) ? (iReturnType | RIGHT) : iReturnType;
iReturnType = bIs_IsoscelesTriangle(iAngDeg1, iAngDeg2) ? (iReturnType | ISOSCELES) : iReturnType;
return iReturnType;
}
int main(int argc, char *argv[]){
if ( argc < 3 ){
return -1;
}
// In case you want an output
// printf("%d\n", iGetTriangleTypeByAngles(atoi(argv[1]), atoi(argv[2])));
return iGetTriangleTypeByAngles(atoi(argv[1]), atoi(argv[2]));
}

Convolution function gives segmentation error while getting pixel value of relative image coordinates

I'm trying to write a convolution function in C for my computer vision study.
In this function, every pixel in the convolved image is a sum of product of original image and filter kernel like in this image and this gif.
In the code below pixel values are float. get_pixel() function gets the pixel value at given indexes. set_pixel() function sets the value to given indexes.
image convolve(image im, image filter) {
// imx, imy, imc: indexes of image pixels
// fix, fiy: indexes of filter pixels
// rx, ry: relative indexes of pixels
image convolved_img = make_image(im.w, im.h, im.c); // image with same dimensions
float value = 0; // pixel value
int oxo = floor(filter.w / 2); // half of the kernel width
int xox = floor(filter.h / 2); // half of the kernel height
// Convolution Loop
for(int imc = 0; imc < im.c; imc++) { // for every channel
for(int imx = 0; imx < im.w; imx++) {
for(int imy = 0; imy < im.h; imy++) { // for every pixel
value = 0;
for(int fix = 0; fix < filter.w; fix++) {
for(int fiy = 0; fiy < filter.h; fiy++) {
int rx = imx - oxo + fix;
int ry = imy - xox + fiy;
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
}
}
set_pixel(convolved_img, imx, imy, imc, value);
}
}
}
return convolved_img;
}
I'm getting segmentation fault (core dumped) error. After debugging I realized its because of line:
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
When I gave fixed values of rx and ry, the program executes successfully. Inside the loop I printed the values of imx, imy, fix, fiy, rx, ry and everything works until a portion of the image has processed; after uncertain time of loop then program crushes without any reason.
I'm sure that it cannot be a index bounds related because I truncated indexes inside get_pixel() function below which I get stored value from a long array of floats.
float get_pixel(image im, int x, int y, int c) {
if(x > im.w) {x = im.w;}
else if(y > im.h) {y = im.h;}
else if(c > im.c) {c = im.c;}
else if(x < 0) {x = 0;}
else if(y < 0) {y = 0;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}
Here is my thought about this operation as pseudo-code:
create convolved_image with same dimensions
for every pixel (imx, imy) in image {
float value = 0;
for every pixel (fix, fiy) in filter {
// calculate relative pixel coordinates
int rx = imx - (filter / 2) + fix;
int ry = imy - (filter / 2) + fiy;
value += filter(fix, fiy) * image(rx, ry);
}
set pixel of convolved_image to value
}
Am I missing something? What is the fault in my approach? Or is there a better way for this operation?
This is clearly an out of bounds access:
for(int fix = 0; fix < filter.w; fix++) {
for(int fiy = 0; fiy < filter.h; fiy++) {
int rx = imx - oxo + fix;
int ry = imy - xox + fiy;
value += get_pixel(filter, fix, fiy, 0) * get_pixel(im, rx, ry, imc);
}
}
With imx going up to im.x and fix going up to 2*oxo you are clearly larger than im.x. Same for imy.
You try to limit the range but that is not correct:
float get_pixel(image im, int x, int y, int c) {
if(x > im.w) {x = im.w;}
else if(y > im.h) {y = im.h;}
else if(c > im.c) {c = im.c;}
else if(x < 0) {x = 0;}
else if(y < 0) {y = 0;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}
You forgot that all parameters can be wrong. You stop after first.
Also you limit to size+1 which also is wrong.
Change like this:
float get_pixel(image im, int x, int y, int c) {
if(x >= im.w) {x = im.w-1;}
else if(x < 0) {x = 0;}
if(y >= im.h) {y = im.h-1;}
else if(y < 0) {y = 0;}
if(c >= im.c) {c = im.c-1;}
else if(c < 0) {c = 0;}
int index = (c * (im.h * im.w)) + (y * im.w) + x;
return im.data[index];
}

PID Line follower with tank treads

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?

Tic-Tac-Toe without AI

I'm doing homework for UNI and I got to do a Tic-Tac-Toe without any decision taken by player, the moves are all chosen randomly. So if the character on matrix is ' ' it means it's free, while if it's 'X' or 'O' it should generate another move. This is the code (language C):
if (playerTurn == 1){
playerSymb = 'X';
}
else if (playerTurn == 2){
playerSymb = 'O';
}
if (matrix[rand1][rand2] == ' '){
matrix[rand1][rand2] = playerSymb;
} else if(matrix[rand1][rand2] == 'X' || matrix[rand1][rand2] == 'O'){
do{
randAlt1 = MINRND + rand()%(MAXRND - MINRND +1);
randAlt2 = MINRND + rand()%(MAXRND - MINRND +1);
}while (matrix[randAlt1][randAlt2] != 'X' && matrix[randAlt1][randAlt2] != 'O');
matrix[randAlt1][randAlt2] = playerSymb;
}
I did not copied the whole code because it's not finished at all, i just need help solving this. But if I try to run this, the Symbols can be overwritten, like if I have a 'X' at matrix[1][2], it's possible that it will be a 'O' after some turns. So how can I make moves do not overwrite? (sorry for bad english).
Just put correct condition:
while (matrix[randAlt1][randAlt2] == 'X' || matrix[randAlt1][randAlt2] == 'O')
(i.e. try again if this cell is not empty)
Also it is easy to simplify your code without loosing of anything:
randAlt1 = rand1;
randAlt2 = rand2;
while (matrix[randAlt1][randAlt2] != ' ') {
randAlt1 = MINRND + rand()%(MAXRND - MINRND +1);
randAlt2 = MINRND + rand()%(MAXRND - MINRND +1);
}
matrix[randAlt1][randAlt2] = (playerTurn == 1) ? 'X' : 'O';
And it is better to add loop guard to prevent infinite loop (or to add special checks for this case):
randAlt1 = rand1;
randAlt2 = rand2;
int nbAttempts = 0;
while (matrix[randAlt1][randAlt2] != ' ' && nbAttempts < 100) {
randAlt1 = MINRND + rand()%(MAXRND - MINRND +1);
randAlt2 = MINRND + rand()%(MAXRND - MINRND +1);
nbAttempts++;
}
if (matrix[randAlt1][randAlt2] != ' ') {
// show error message and stop the game
}
matrix[randAlt1][randAlt2] = (playerTurn == 1) ? 'X' : 'O';
You choose an arbitrary position and then test if it is free – possibly multiple times. But you can also choose a number of a free position and then find it.
First set up a turn counter
int turnNo = 0;
then make a loop for alternate moves, which chooses one of 9-turnNo unused positions, finds it, marks is with a player mark and tests if the move made a line of three:
while(turnNo < 9)
{
char currPlayerMark = ...choose 'X' or 'O';
int freePos = 9 - turnNo;
int currPos = rand() % freePos; // 0 .. freePos-1
for(x=0; x<3; x++)
{
for(y=0; y<3; y++)
{
if(matrix[x][y] == ' ') // a free position
if(--currPos < 0) // the sought one
break; // break the inner loop
}
if(currPos < 0)
break; // break the outer loop
}
matrix[x][y] = currPlayerMark;
if(test_for_win_position(x,y))
{
message_a_win_of_player(currPlayerMark);
break; // turnNo < 9 here
}
turnNo ++;
}
Finally test if the loop terminated with no 'win':
if(turnNo == 9)
message_its_a_draw(); // no-one wins
A function to test the win position might look like this:
int test_for_win_position(int x, int y)
{
char mark = matrix[x][y];
// check a column
if(matrix[x][0] == mark && matrix[x][1] == mark && matrix[x][2] == mark)
return 1;
// check a row
if(matrix[0][y] == mark && matrix[1][y] == mark && matrix[2][y] == mark)
return 1;
// check one diagonal
if(x==y)
if(matrix[0][0] == mark && matrix[1][1] == mark && matrix[2][2] == mark)
return 1;
// check another diagonal
if(x+y==2)
if(matrix[0][2] == mark && matrix[1][1] == mark && matrix[2][0] == mark)
return 1;
// current player has not won (yet)
return 0;
}

Breadth first search for getting path

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.

Resources