Related
I wrote this code to find the prime factorization of a number. I just cannot figure out the last part. If x is entered as a double or float, the program should print an error message and terminate. How do I achieve this?
#include <stdio.h>
int main()
{
int x, i;
printf("Enter an integer: ");
scanf("%d", &x);
if (x <= 1)
{
return 1;
}
printf("The prime factorization of %d is ", x);
if (x > 1)
{
while (x % 2 == 0)
{
printf("2 ");
x = x / 2;
}
for (i = 3; i < 1009; i = i + 2)
{
while (x % i == 0)
{
printf("%d ", i);
x = x / i;
}
}
}
return 0;
}
Your starting point should cover all desired and undesired cases so you should take float number from a user, not int. Then, you should check whether whole decimal part of the number is 0. That is, if all of them equals 0, the user want to provide an int number instead of float.
First step is to declare a float number:
float y;
After, take its value from the user:
scanf("%f", &y);
Second step is to check whether it is int or float. There are many ways for this step. For example, I find roundf() function useful. It takes a float number and computes the nearest integer to this number. So if the nearest integer is the number itself then the number has to be int. Right?
if(roundf(y)!=y)
If you are sure it is an int, you can move onto the third step: convert float type to int type. It is called type-casting. This step is required for the remaining part of your program because in your algorithm you manipulate the number with int type so just convert it to int:
x = (int)y;
After adding the line above, you can use the rest of code which you typed. I give the whole program:
#include <stdio.h>
#include <math.h>
int main()
{
int x,i;
float y;
printf("Enter an integer: ");
scanf("%f", &y);
if(roundf(y)!=y){
printf("%f is not an integer!",y);
return 1;
}
else{
x = (int)y;
}
if (x <= 1)
{
printf("%d <= 1",x);
return 1;
}
else
{
printf("The prime factorization of %d is ", x);
while (x%2 == 0)
{
printf("2 ");
x = x / 2;
}
for ( i = 3; i < 1009; i = i + 2)
{
while (x%i == 0)
{
printf("%d ",i);
x = x / i;
}
}
}
return 0;
}
The use of scanf() is a bit tricky, I would avoid it to scan user generated input at almost all cost. But nevertheless here is a short overview for how to get the errors of scanf()
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(void)
{
int x, i, scanf_return;
printf("Enter an integer: ");
/* Reset "errno". Not necessary here, just in case. */
errno = 0;
/* scanf() returns a value in case of an error */
scanf_return = scanf("%d", &x);
/*
* scanf() returns "EOF" if it didn't find all what you wanted or
* and error happened.
* It sets "errno" to the value of the actual error. See manpage
* for all of the details.
*/
if (scanf_return == EOF) {
/*
* The error is connected to the stream, so we can differ between
* an error within scanf() and and error with the input stream
* (here: stdin)
*/
if (ferror(stdin)) {
fprintf(stderr, "Something went wrong while reading stdin: %s\n", strerror(errno));
exit(EXIT_FAILURE);
} else {
/* e.g. a conversion error, a float instead of an integer, letters
instead of a decimal number */
fprintf(stderr, "Something went wrong within scanf()\n");
exit(EXIT_FAILURE);
}
}
/*
* If no error occurred, the return holds the number of objects
* scanf() was able to read. We only need one, but it would throw an
* error if cannot find any objects, so the check is here for
* pedagogical reasons only.
*/
if (scanf_return != 1) {
fprintf(stderr, "Something went wrong within scanf(): wrong number of objects read.\n");
exit(EXIT_FAILURE);
}
if (x <= 1) {
fprintf(stderr, "Input must be larger than 1!\n");
exit(EXIT_FAILURE);
}
printf("The prime factorization of %d is ", x);
/* No need for that test, x is already larger than one at this point. */
/* if (x > 1) { */
while (x%2 == 0) {
printf("2 ");
x = x / 2;
}
for (i = 3; i < 1009; i = i + 2) {
while (x%i == 0) {
printf("%d ",i);
x = x / i;
}
}
/* } */
/* Make it pretty. */
putchar('\n');
exit(EXIT_SUCCESS);
}
Does it work?
$ ./stackoverflow_003
Enter an integer: 1234
The prime factorization of 1234 is 2 617
$ factor 1234
1234: 2 617
$ ./stackoverflow_003
Enter an integer: asd
Something went wrong within scanf(): wrong number of objects read.
$ ./stackoverflow_003
Enter an integer: 123.123
The prime factorization of 123 is 3 41
No, it does not work. Why not? If you ask scanf() to scan an integer it grabs all consecutive decimal digits (0-9) until there is no one left. The little qualifier "consecutive" is most likely the source of your problem: a floating point number with a fractional part has a decimal point and that is the point where scanf() assumes that the integer you wanted ended. Check:
$ ./stackoverflow_003
Enter an integer: .123
Something went wrong within scanf(): wrong number of objects read
How do you find out? #weather-vane gave one of many ways to do so: check if the next character after the integer is a period (or another decimal separator of your choice):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(void)
{
int x, i, scanf_return;
char c = -1;
printf("Enter an integer: ");
/* Reset "errno". Not necessary here, just in case. */
errno = 0;
/* scanf() returns a value in case of an error */
scanf_return = scanf("%d%c", &x, &c);
/*
* scanf() returns "EOF" if it didn't find all what you wanted or
* and error happened.
* It sets "errno" to the value of the actual error. See manpage
* for all of the details.
*/
if (scanf_return == EOF) {
/*
* The error is connected to the stream, so we can differ between
* an error within scanf() and and error with the input stream
* (here: stdin)
*/
if (ferror(stdin)) {
fprintf(stderr, "Something went wrong while reading stdin: %s\n", strerror(errno));
exit(EXIT_FAILURE);
} else {
/* e.g. a conversion error, a float instead of an integer, letters
instead of a decimal number */
fprintf(stderr, "Something went wrong within scanf()\n");
exit(EXIT_FAILURE);
}
}
/*
* If no error occurred, the return holds the number of objects
* scanf() was able to read. We can use this information now.
* If there is a period (actually any character) after the integer
* it returns 2 (assuming no error happened, of course)
*/
/* If no integer given, the following character ("%c") gets ignored. */
if (scanf_return == 0) {
fprintf(stderr, "Something went wrong within scanf(): no objects read.\n");
exit(EXIT_FAILURE);
}
/* Found two objects, check second one which is the character. */
if (scanf_return == 2) {
if (c == '.') {
fprintf(stderr, "Floating point numbers are not allowed.\n");
exit(EXIT_FAILURE);
}
}
if (x <= 1) {
fprintf(stderr, "Input must be larger than 1!\n");
exit(EXIT_FAILURE);
}
printf("The prime factorization of %d is ", x);
/* No need for that test, x is already larger than one at this point. */
/* if (x > 1) { */
while (x%2 == 0) {
printf("2 ");
x = x / 2;
}
for (i = 3; i < 1009; i = i + 2) {
while (x%i == 0) {
printf("%d ",i);
x = x / i;
}
}
/* } */
/* Make it pretty. */
putchar('\n');
exit(EXIT_SUCCESS);
}
Check:
$ ./stackoverflow_003
Enter an integer: 123
The prime factorization of 123 is 3 41
$ ./stackoverflow_003
Enter an integer: 123.123
Floating point numbers are not allowed.
$ ./stackoverflow_003
Enter an integer: .123
Something went wrong within scanf(): no objects read.
Looks good enough for me. With one little bug:
$ ./stackoverflow_003
Enter an integer: 123.
Floating point numbers are not allowed
But I think I can leave that as an exercise for the dear reader.
You can try this simple C99 implementation of Pollard Rho algorithm :
// Integer factorization in C language.
// Decompose a composite number into a product of smaller integers.
unsigned long long pollard_rho(const unsigned long long N) {
// Require : N is a composite number, not a square.
// Ensure : you already performed trial division up to 23.
// Option : change the timeout, change the rand function.
static const int timeout = 18;
static unsigned long long rand_val = 2994439072U;
rand_val = (rand_val * 1025416097U + 286824428U) % 4294967291LLU;
unsigned long long gcd = 1, a, b, c, i = 0, j = 1, x = 1, y = 1 + rand_val % (N - 1);
for (; gcd == 1; ++i) {
if (i == j) {
if (j >> timeout)
break;
j <<= 1;
x = y; // "x" takes the previous value of "y" when "i" is a power of 2.
}
a = y, b = y; // computes y = f(y)
for (y = 0; a; a & 1 ? b >= N - y ? y -= N : 0, y += b : 0, a >>= 1, (c = b) >= N - b ? c -= N : 0, b += c);
y = (1 + y) % N; // function f performed f(y) = (y * y + 1) % N
for (a = y > x ? y - x : x - y, b = N; (a %= b) && (b %= a););
gcd = a | b; // the GCD(abs(y - x), N) was computed
// it continues until "gcd" is a non-trivial factor of N.
}
return gcd;
}
Usually you performed some trial division before calling the algorithm
The algorithm isn't designed to receive a prime number as input
Two consecutive calls may not result in the same answer
Alternately, there is a pure C quadratic sieve which factors numbers from 0 to 300-bit.
If in doubt about the primality of N you can use a C99 primality checker :
typedef unsigned long long int ulong;
ulong mul_mod(ulong a, ulong b, const ulong mod) {
ulong res = 0, c; // return (a * b) % mod, avoiding overflow errors while doing modular multiplication.
for (b %= mod; a; a & 1 ? b >= mod - res ? res -= mod : 0, res += b : 0, a >>= 1, (c = b) >= mod - b ? c -= mod : 0, b += c);
return res % mod;
}
ulong pow_mod(ulong n, ulong exp, const ulong mod) {
ulong res = 1; // return (n ^ exp) % mod
for (n %= mod; exp; exp & 1 ? res = mul_mod(res, n, mod) : 0, n = mul_mod(n, n, mod), exp >>= 1);
return res;
}
int is_prime(ulong N) {
// Perform a Miller-Rabin test, it should be a deterministic version.
const ulong n_primes = 9, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
for (ulong i = 0; i < n_primes; ++i)
if (N % primes[i] == 0) return N == primes[i];
if (N < primes[n_primes - 1]) return 0;
int primality = 1, a = 0;
ulong b;
for (b = N - 1; ~b & 1; b >>= 1, ++a);
for (ulong i = 0; i < n_primes && primality; ++i) {
ulong c = pow_mod(primes[i], b, N);
if (c != 1) {
for (int j = a; j-- && (primality = c + 1 != N);)
c = mul_mod(c, c, N);
primality = !primality;
}
}
return primality;
}
To try it there is a factor function :
// return the number that was multiplied by itself to reach N.
ulong square_root(const ulong num) {
ulong res = 0, rem = num, a, b;
for (a = 1LLU << 62 ; a; a >>= 2) {
b = res + a;
res >>= 1;
if (rem >= b)
rem -= b, res += a;
}
return res;
}
ulong factor(ulong num){
const ulong root = square_root(num);
if (root * root == num) return root ;
const ulong n_primes = 9, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
for (ulong i = 0; i < n_primes && primes[i] <= root; ++i)
if (num % primes[i] == 0) return primes[i];
if (is_prime(num))
return 1 ;
return pollard_rho(num);
}
Which is completed by the main function :
#include <assert.h>
int main(void){
for(ulong i = 2; i < 63; ++i){
ulong f = factor(i);
assert(f <= 1 || f >= i ? is_prime(i) : i % f == 0);
ulong j = (1LLU << i) - 1 ;
f = factor(j);
assert(f <= 1 || f >= j ? is_prime(j) : j % f == 0);
j = 1 | pow_mod((ulong) &main, i, -5);
f = factor(j);
assert(f <= 1 || f >= j ? is_prime(j) : j % f == 0);
}
}
There are some problems in your code:
you do not check the return value of scanf, so you cannot detect invalid or missing input and will have undefined behavior in those cases.
you only test divisors up to 1009, so composite numbers with larger prime factors do not produce any output.
prime numbers larger than 1009 do not produce any output.
you should probably output a newline after the factors.
Testing and reporting invalid input such as floating point numbers can be done more easily by reading the input as a full line and parsing it with strtol().
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char input[120];
char ch;
char *p;
long x, i;
int last_errno;
printf("Enter an integer: ");
if (!fgets(input, sizeof input, stdin)) {
fprintf(stderr, "missing input\n");
return 1;
}
errno = 0;
x = strtol(input, &p, 0);
last_errno = errno;
if (p == input || sscanf(p, " %c", &ch) == 1) {
fprintf(stderr, "invalid input: %s", input);
return 1;
}
if (last_errno == ERANGE) {
fprintf(stderr, "number too large: %s", input);
return 1;
}
if (x < 0) {
fprintf(stderr, "number is negative: %ld\n", x);
return 1;
}
if (x <= 1) {
return 1;
}
printf("The prime factorization of %ld is", x);
while (x % 2 == 0) {
printf(" 2");
x = x / 2;
}
for (i = 3; x / i >= i;) {
if (x % i == 0) {
printf(" %ld", i);
x = x / i;
} else {
i = i + 2;
}
}
if (x > 1) {
printf(" %ld", x);
}
printf("\n");
return 0;
}
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];
}
recently i read this topic about generating mazes in c . see here https://www.algosome.com/articles/maze-generation-depth-first.html
and i want to write it in c . here is my code and it's not working right .
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int check[5][5];
int v[5][5];
int border(int x , int y ){
if(x> -1 && x< 6 && y > -1 && y<6)
return 1;
else
return 0 ;
}
int wall[6][6][6][6];
void dfs ( int x , int y){
srand(time(NULL));
int s = 1/*rand() % 4 ;*/ ;
if(s=1 ){
if(border(x ,y-1)&& check[x][y-1]==0){
check[x][y]=1;
wall[x][y][x+1][y]=1;
dfs(x , y-1);
}
else
return ;
}
else if(s=2){
if(border(x+1 ,y)&&check[x+1][y]==0){
check[x][y]=1;
wall[x+1][y][x+1][y+1]=1;
dfs(x+1 , y);
}
else return ;
}
else if(s=3){
if(border(x ,y+1)&&check[x][y+1]==0){
check[x][y]=1;
wall[x][y+1][x+1][y+1]=1;
dfs(x , y+1);
}
else return ;
}
else if(s=0){
if(border(x-1 ,y)&&check[x-1][y]==0){
check[x][y]=1;
wall[x][y][x][y+1]=1;
dfs(x-1 , y);
}
else return ;
}
return ;
}
int main(){
dfs( 4, 4);
for(int i =0 ; i < 6 ; i++)
for (int j =0 ; j < 6 ; j++)
for ( int h =0 ; h <6 ; h++)
for (int k =0 ; k < 6 ; k ++)
printf("%d \n" , wall[i][j][h][k]);
return 0 ;
}
i invert my table to graph , and i want to show me the coordinates of my walls .
what's the problem ?
You have several errors – programming errors and logic errors – in your code:
When you distiguish between the directions the s=1 and so on should be s == 1. You want a comparison, not an assignment. (Your code is legal C, so there is no error.)
You call srand at the beginning of dfs, which you call recursively. This will make your single (commented) rand call always create the same random number. You should seed the pseudo random number generator only once at the beginning of main.
You can store the paths the way you do, but it is wasteful. There are only four possible paths from each cell, so you don't need an array that allows to create a path between (0,0) and (3,4), for example.
Your code would benefit from using constants or enumerated values instead of the hard-coded 5's and 6's. This will allow you to change the dimensions later easily.
But your principal error is in how you implement the algorithm. You pick one of the for directions at random, then test whether that direction leads to a valid unvisited cell. If so, you recurse. If not, you stop. This will create a single unbranched path through the cells. Note that if you start in a corner cell, you have already a 50% chance of stopping the recursion short.
But you want something else: You want a maze with many branches that leads to every cell in the maze. Therefore, when the first recursion returns, you must try to branch to other cells. The algorithm goes like this:
Make a list of all possible exits.
If there are possible exits:
Pick one exit, create a path to that exit and recurse.
Update the list of possible exits.
Note that you cannot re-use the old list of exits, because the recursion may have rendered some possible exits invalid by visiting the destination cells.
Below is code that creates a maze with the described algorithm. I've used two distinct arrays to describe horizontal and vertical paths:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
enum {
W = 36, // width of maze
H = 25 // height of maze
};
enum {
North,
East,
South,
West,
NDir
};
char visited[H][W];
char horz[H][W - 1]; // horizontal E-W paths in the maze
char vert[H - 1][W]; // veritcal N-S paths in the maze
/*
* Fill dir with directions to unvisited cells, return count
*/
int adjacent(int dir[], int x, int y)
{
int ndir = 0;
if (y > 0 && visited[y - 1][x] == 0) dir[ndir++] = North;
if (x < W - 1 && visited[y][x + 1] == 0) dir[ndir++] = East;
if (y < H - 1 && visited[y + 1][x] == 0) dir[ndir++] = South;
if (x > 0 && visited[y][x - 1] == 0) dir[ndir++] = West;
return ndir;
}
/*
* Traverse cells depth first and create paths as you go
*/
void dfs(int x, int y)
{
int dir[NDir];
int ndir;
visited[y][x] = 1;
ndir = adjacent(dir, x, y);
while (ndir) {
int pick = rand() % ndir;
switch (dir[pick]) {
case North: vert[y - 1][x] = 1; dfs(x, y - 1); break;
case East: horz[y][x] = 1; dfs(x + 1, y); break;
case South: vert[y][x] = 1; dfs(x, y + 1); break;
case West: horz[y][x - 1] = 1; dfs(x - 1, y); break;
}
ndir = adjacent(dir, x, y);
}
}
/*
* Print a map of the maze
*/
void map(void)
{
int i, j;
for (i = 0; i < W; i++) {
putchar('_');
putchar('_');
}
putchar('\n');
for (j = 0; j < H; j++) {
putchar('|');
for (i = 0; i < W; i++) {
putchar(j < H - 1 && vert[j][i] ? ' ' : '_');
putchar(i < W - 1 && horz[j][i] ? '_' : '|');
}
putchar('\n');
}
}
int main()
{
srand(time(NULL));
dfs(0, 0);
map();
return 0;
}
You can test it here. If you replace the while in dsf with a simple if, you get more or less what you implemented. Note that this creates only a single, usually short path.
I made this program in C where an object R is placed on a grid and it's supposed to move taking inputs from they keyboard. For example, thi is what happens if you press N.
0 1 2
0 - - - R - - - - -
1 R - - PRESS N -> GO UP -> - - - PRESS N AGAIN -> - - -
2 - - - - - - R - -
So R makes it go up. The object has to move around, so when it is at [A0][B0], for example, it needs to go all the way down [A2][B0]. See above.
It will move up, down, left and right.
Right now i'm creating the function to make it move up, but i'm having a lot of troubles: sometimes it randomly freezes to 2:0 and 0:0 without goind up, and when it's at A = 2, instead of going up of 1, it goes to 0, although i set it to do 2-1 (to go up it has to subtract 1).
I don't understand what's causing those troubles, any advice?
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define X 3
#define Y 3
struct coords{
int a;
int b;
};
typedef struct coords cord;
// Print the array
char printArray(char row[][Y], size_t one, size_t two, struct coords cord)
{
row[cord.a][cord.b] = 'X';
// output column heads
printf("%s", " [0] [1] [2]");
// output the row in tabular format
for (size_t i = 0; i < one; ++i) {
printf("\nrow[%lu] ", i);
for (size_t j = 0; j < two; ++j) {
printf("%-5c", row[i][j]);
}
}
}
int moveUp(struct coords * cord);
int main(void)
{
struct coords cord;
char row[X][Y] =
{ { '-', '-', '-'},
{ '-', '-', '-'},
{ '-', '-', '-'} };
srand(time(NULL));
cord.a = (rand() % 3);
cord.b = (rand() % 3);
printf("\nValori rand: A %d, B %d\n", cord.a, cord.b);
// output the row
//printf("\nrobot:%c\n", robot);
puts("The array is:");
printf("\n");
printArray(row, X, Y, cord);
row[cord.a][cord.b] = '-';
//printArray(row, X, Y, &m, &n);
char h;
while(h != '3'){
switch (h) {
case 'N':
moveUp(&cord);
printArray(row, X, Y, cord);
row[cord.a][cord.b] = '-';
break;
}
scanf("%s", &h);
}
printf("\n");
}
int moveUp(struct coords * cord)
{
cord->a - 1;
if (cord->a == 2){
cord->a - 1;
} else if (cord->a == 1){
cord->a - 1;
} else if (cord->a == 0){
cord->a + 2;
}
/*
if (cord->a == 0) {
cord-> a = 2;
} else {
cord->a - 1;
}
*/
printf("\n A = %d, B = %d\n", cord->a, cord->b);
}
In the below code, you are checking the value of h before having read anything into it. If the uninitialized value of h happens to be 3, then execution will not enter the while loop.
char h;
while(h != '3')
So read in a value into h and then do the check in the while loop.
In the moveUp function, you can use the ternary conditional operator to assign the next position or the object R.
cord->a = (cord->a)? (cord->a - 1): 2;
I'm trying to implement MiniMax algorithm based on Wikipedia pseudocode in Tic-Tac-Toe game written in C. However, I can't manage to obtain the best possible move. Here's my code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
// compile and run: gcc minimax.c -std=c99 && ./a.out
int max(int x, int y) {
return x > y ? x : y;
}
int min(int x, int y) {
return x < y ? x : y;
}
int whoWon(char ch) {
switch (ch) {
case 'O':
return -1;
break;
case 'X':
return 1;
break;
}
}
void printArray(char array[]) {
printf("# START\n"
"%c | %c | %c\n"
"--|---|--\n"
"%c | %c | %c\n"
"--|---|--\n"
"%c | %c | %c\n"
"# END\n\n", array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8]);
}
int anyWinners(char board[])
{
int i;
/* check every row */
for(i = 0; i < 7; i += 3)
if(board[i] != ' ' && board[i] == board[i+1] && board[i] == board[i+2])
return whoWon(board[i]);
/* check every column */
for(i = 0; i < 3; i++)
if(board[i] != ' ' && board[i] == board[i+3] && board[i] == board[i+6])
return whoWon(board[i]);
/* check diagonals */
if(board[4] != ' ' && ((board[0] == board[4] && board[0] == board[8]) || (board[2] == board[4] && board[2] == board[6])))
return whoWon(board[4]);
return 0;
}
int fullBoard(char board[]) {
for (int i = 0; i < 9; ++i) {
if (board[i] == ' ')
return 0;
}
return 1;
}
int minimax(char node[], int depth, bool maximizingPlayer, int * move) {
int terminalNode = anyWinners(node);
if (depth == 0 || terminalNode || fullBoard(node)) {
printf("################## END OF SUBTREE ##################\n");
return terminalNode;
}
int bestValue, val;
if (maximizingPlayer) {
bestValue = -2;
for (int i = 0; i < 9; ++i) {
if (node[i] == ' ') {
char child[9];
strcpy(child, node);
child[i] = 'X';
// debug
printArray(child);
val = minimax(child, depth - 1, false, move);
// debug
printf("X: ^^ i = %d ^^ depth = %d ^^ val = %d\n", i, depth, val);
//bestValue = max(bestValue, val);
if (val > bestValue) {
bestValue = val;
if (depth == 9) *move = i;
}
}
}
return bestValue;
} else {
bestValue = 2;
for (int i = 0; i < 9; ++i) {
if (node[i] == ' ') {
char child[9];
strcpy(child, node);
child[i] = 'O';
// debug
printArray(child);
val = minimax(child, depth - 1, true, move);
// debug
printf("O: ^^ i = %d ^^ depth = %d ^^ val = %d\n", i, depth, val);
bestValue = min(bestValue, val);
}
}
return bestValue;
}
}
int main() {
int move = -999; // initialize only for debug
// X will always win no matter what, first best move for X is 8
// char board[] = {'O', ' ', ' ',
// ' ', ' ', ' ',
// 'X', 'X', ' '};
// best move for X is 3
char board[] = {'O', 'O', ' ',
' ', 'X', 'X',
' ', ' ', ' '};
// Initial call for maximizing player
int result = minimax(board, 9, true, &move);
printf("minimax returned: %d\n", result);
printf("chosen move: %d\n", move);
return 0;
}
Code prints board for each move with state of all variables. There are also two failing tests commented out in main. Right now algorithm returns bad moves and I can't find the error.
I see two problems:
The heuristic is wrong
There is a problem with strcpy.
The heuristic is wrong
The Wikipedia pseudo-code says:
if depth = 0 or node is a terminal node
return the heuristic value of node
Your implementation does this:
if depth = 0 or node is a terminal node
return 1 if X wins, -1 if O wins, 0 if it is a draw
But that isn't a very good heuristic. With that heuristic, all the possible ways that X could win are equally weighted. So if X finds a way to win in 3 moves, that is weighted just the same as if X finds a way to win in 2 moves, and that is weighted just the same as if X finds a way to win in 1 move.
So, here is what happens in your test case:
X tries position 2.
O tries position 3.
X tries position 6.
This is a terminal node. X wins. So return positive 1.
Heuristic for this decision path = 1
Another possibility it hits is:
X tries position 3.
This is a terminal node. X wins. So return positive 1.
Heuristic for this decision path = 1
Since both of these solutions have the same heuristic, so they are both of equal value. You probably meant for this solution to be suboptimal, because it took too many moves to win. I suggest a heuristic based on the number of moves it took to get here, multiplied who the winner is. So if X wins in 1 moves, heuristic is 5000. If X wins in 2 moves, then heuristic is 2500. If O wins in 2 moves, heuristic is -2500. Something like that.
There is a problem with strcpy
This line:
strcpy(child, node);
should be:
memcpy(child, node, 9*sizeof(char));
Because "node" is not a null terminated string. When I run this on VS2013/Windows 8.1 my output is garbage because. You might be getting lucky on your platform.