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;
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 implement the Join Five game. It is a game where, given a grid and a starting configuration of dots, you have to add dots in free crossings, so that each dot that you add forms a 5-dot line with those already in the grid. Two lines may only have 1 dot in common (they may cross or touch end to end)
My game grid is an int array that contains 0 or 1. 1 if there is a dot, 0 if there isn't.
I'm doing kinda well in the implementation, but I'd like to display all the possibles moves.
I made a very long and ugly function that is available here : https://pastebin.com/tw9RdNgi (it was way too long for my post i'm sorry)
here is a code snippet :
if(jeu->plat[i][j] == 0) // if we're on a empty spot
{
for(k = 0; k < lineSize; k++) // for each direction
{
//NORTH
if(jeu->plat[i-1-k][j] == 1) // if there is a dot north
{
n++; // we count it
}
else
{
break; //we change direction
}
} //
This code repeats itself 7 other times changing directions and if n or any other variable reaches 4 we count the x and y as a possible move.
And it's not even treating all the cases, if the available spot is between 2 and 2 dots it will not count it. same for 3 and 1 and 1 and 3.
But I don't think the way I started doing it is the best one. I'm pretty sure there is an easier and more optimized way but i can't figure it out.
So my question is: could somebody help me figure out how to find all the possible 5-dot alignments, or tell me if there is a better way of doing it?
Ok, the problem is more difficult than it appears, and a lot of code is required. Everything would have been simpler if you posted all of the necessary code to run it, that is a Minimal, Complete, and Verifiable Example. Anyway, I resorted to putting together a structure for the problem which allows to test it.
The piece which answers your question is the following one:
typedef struct board {
int side_;
char **dots_;
} board;
void board_set_possible_moves(board *b)
{
/* Directions
012
7 3
654 */
static int dr[8] = { -1,-1,-1, 0, 1, 1, 1, 0 };
static int dc[8] = { -1, 0, 1, 1, 1, 0,-1,-1 };
int side_ = b->side_;
char **dots_ = b->dots_;
for (int r = 0; r < side_; ++r) {
for (int c = 0; c < side_; ++c) {
// The place already has a dot
if (dots_[r][c] == 1)
continue;
// Count up to 4 dots in the 8 directions from current position
int ndots[8] = { 0 };
for (int d = 0; d < 8; ++d) {
for (int i = 1; i <= 4; ++i) {
int nr = r + dr[d] * i;
int nc = c + dc[d] * i;
if (nr < 0 || nc < 0 || nr >= side_ || nc >= side_ || dots_[nr][nc] != 1)
break;
++ndots[d];
}
}
// Decide if the position is a valid one
for (int d = 0; d < 4; ++d) {
if (ndots[d] + ndots[d + 4] >= 4)
dots_[r][c] = 2;
}
}
}
}
Note that I defined a square board with a pointer to pointers to chars, one per place. If there is a 0 in one of the places, then there is no dot and the place is not a valid move; if there is a 1, then there is a dot; if there is a 2, then the place has no dot, but it is a valid move. Valid here means that there are at least 4 dots aligned with the current one.
You can model the directions with a number from 0 to 7 (start from NW, move clockwise). Each direction has an associated movement expressed as dr and dc. Moving in every direction I count how many dots are there (up to 4, and stopping as soon as I find a non dot), and later I can sum opposite directions to obtain the total number of aligned points.
Of course these move are not necessarily valid, because we are missing the definition of lines already drawn and so we cannot check for them.
Here you can find a test for the function.
#include <stdio.h>
#include <stdlib.h>
board *board_init(board *b, int side) {
b->side_ = side;
b->dots_ = malloc(side * sizeof(char*));
b->dots_[0] = calloc(side*side, 1);
for (int r = 1; r < side; ++r) {
b->dots_[r] = b->dots_[r - 1] + side;
}
return b;
}
board *board_free(board *b) {
free(b->dots_[0]);
free(b->dots_);
return b;
}
void board_cross(board *b) {
board_init(b, 18);
for (int i = 0; i < 4; ++i) {
b->dots_[4][7 + i] = 1;
b->dots_[7][4 + i] = 1;
b->dots_[7][10 + i] = 1;
b->dots_[10][4 + i] = 1;
b->dots_[10][10 + i] = 1;
b->dots_[13][7 + i] = 1;
b->dots_[4 + i][7] = 1;
b->dots_[4 + i][10] = 1;
b->dots_[7 + i][4] = 1;
b->dots_[7 + i][13] = 1;
b->dots_[10 + i][7] = 1;
b->dots_[10 + i][10] = 1;
}
}
void board_print(const board *b, FILE *f)
{
int side_ = b->side_;
char **dots_ = b->dots_;
for (int r = 0; r < side_; ++r) {
for (int c = 0; c < side_; ++c) {
static char map[] = " oX";
fprintf(f, "%c%s", map[dots_[r][c]], c == side_ - 1 ? "" : " - ");
}
fprintf(f, "\n");
if (r < side_ - 1) {
for (int c = 0; c < side_; ++c) {
fprintf(f, "|%s", c == side_ - 1 ? "" : " ");
}
fprintf(f, "\n");
}
}
}
int main(void)
{
board b;
board_cross(&b);
board_set_possible_moves(&b);
board_print(&b, stdout);
board_free(&b);
return 0;
}
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 was given a char *map that contains the different elements that you can find on screen. Those elements are e, for electricity, c, for coin, and _, for empty space.
I've done a loop that will go through the array and will detect whenever I have one of those characters. Here's the problem though, when I look to blit the corresponding sprite for each letter my program segfaults.
When I took out SDL_BlitSurface() the program works correctly, doing the amount of loops necesary.
I feel that I'm missing something before SDL_BlitSurface()
Here's the function where everything goes wrong:
void print_map()
{
int i;
SDL_Rect pos;
int x;
int y;
if ((th_client[1].coin = IMG_Load("./images/coin.png")) == NULL)
printf("Erreur\n");
y = 0;
i = 0;
while (y != 10)
{
pos.y = (y * 10) + 5;
x = 0;
while (x != 95)
{
pos.x = (x * 10) + 5;
printf("pos x: %d\n", pos.x);
if (th_client[1].map[i] == 'c')
{
printf("char : %c\n", th_client[1].map[i]);
if ((SDL_BlitSurface(th_client[i].screen, NULL,th_client[i].coin, &pos)) == -1) // <- it blows up right here
printf("Erreur\n");
}
x++;
i++;
}
y++;
printf("y : %d\n", y);
}
SDL_FreeSurface(th_client[1].coin);
}
th_client[1] corresponds to the graphics thread, inside there's I've got a structure with everything needed to initialize SDL.
Output:
pos x: 5
...
pos x: 945
y : 1 // <- jumps into the next line
pos x: 5
...
pos x: 355
char : c // <- Coin found
Segmentation fault
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.