How do I change the binary search function to intake the compare? - c

I am having trouble with the logic of combining these two stipulations in my assignment. How do I change the below binary search function to intake the compareTo the coordinate structures. I wrote it wrong the first time because I used the original string locations. I also dont understand how the compareTo function is suppose to keep track of the length away from the target. Which is confusing to me because the way it reads below for the compareTo function says the opposite to me and asking me to compare individual x and y coordinates. how am I suppose to do that if i am just using the pointers? Am i just passing coordinates *ptrPt1 into the binary search? Number 3 is the most confusing mess of words.
Context for the function relationship:
You must write a function compareTo which takes in two pointers, ptrPt1 and ptrPt2, to
coordinate structs and returns a negative integer if the point pointed to by ptrPt1 is closer to you
than the point pointed to by ptrPt2, 0 if the two locations pointed to by both are identical locations,
and a positive integer if the point pointed to by ptrPt1 is farther from you than the point pointed to
by ptrPt2. Exceptions to this will be when the two pointers are pointing to points that are the same
distance from you, but are distinct points. In these cases, if ptrPt1's x coordinate is lower than
ptrPt2's x coordinate, a negative integer must be returned. Alternatively, if ptrPt1's x coordinate is
greater than ptrPt2's x coordinate a positive integer must be returned. Finally, if the x coordinate
of both points is the same, if ptrPt1's y coordinate is lower than ptrPt2's y coordinate, a negative
integer must be returned. If ptrPt1's y coordinate is greater than ptrPt2's y coordinate, a positive
integer must be returned.
Since your location must be used for sorting, please make the variable that stores your x and y
coordinates global. Your program should have no other global variables.
A Binary Search function must be used when answering queries.
int binarysearch(int searchval, int* array, int length) {
int low = 0, high = length-1;
// Search while there is a valid search space.
while (low <= high) {
int mid = (low+high)/2;
// Value is too small.
if (searchval < array[mid])
high = mid-1;
// too big.
else if (searchval > array[mid])
low = mid+1;
// found it!
else
return 1;
}
// Never found it.
return 0;
}
int
compareTo(coordinates *ptrPt1, coordinates *ptrPt2) {
if (ptrPt1 > ptrPt2)
return -1;
if(ptrPt1 == ptrPt2)
return 0;
if(ptrPt1 < ptrPt2)
return 1;
}

Your compareTo needs to be refactored.
Comparing the addresses of the structs [vs. the X/Y coordinates within them] is incorrect.
For compareTo, it must first compute the distance from an arbitrary reference point (e.g.) self for each of the two points passed as arguments. Per the problem definition, self can [and should] be a [the only] global.
It gets the distance to self for each of the two [argument] points. It chooses the closer of these two points [if they are different].
If the two points are the same distance from the self point, it first chooses the one with the lower X coordinate value. If the X coordinates are the same for the two points, it chooses the one that has the lower of the two Y values.
Thus, it's a three step process.
Your binarysearch needs to be refactored. Upon mismatch/failure, it returns 0. But, zero is a valid index/value for a match. So, it needs to return -1 on failure.
There are some issues with the problem definition.
Issue (1):
It's not clear [to me] what "rank" is supposed to be. The only thing that makes sense is that "rank" is the index into the list that is sorted by compareTo.
Issue (2):
It's not clear what "distance" means. It could be (e.g.):
sqrt((p1->x - p2->x)**2 + (p1->y - p2->y)**2)
But, that uses floating point, and it may be overkill for this problem.
Another "distance" is the manhattan distance which is just the sum of the absolute differences of the X and Y values of the two coordinates:
abs(p1->x - p2->x) + abs(p1->y - p2->y)
Issue (3):
I think that two sorted lists are required.
One sorted by compareTo. Another sorted just by X/Y coordinates.
This is because it is required to use a binary search when matching a search coordinate. Because the search coordinate does not know the rank, it can't use the compareTo list and must use the X/Y list.
There are two possible approaches.
This can be achieved by using two lists that are either pointers or indices into the person list. The binarysearch should be modified to accept an array of indices/pointers.
Or, it can be achieved by sorting the person list by compareTo, recording the rank in the coordinate struct and then resorting the list by X/Y coordinates. The binarysearch should be modified to accept an array of coordinates.
I've chosen to use the latter approach.
And, I've added some test code to generate a randomized input file, if desired.
I've just implemented a simple insertion sort [algorithm is a cut-n-paste from the wikipedia entry for insertion sort]. So, you'll still have to code up the combined merge/insertion sort logic.
Spoiler Alert: Below is the complete/refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <time.h>
typedef struct {
int x;
int y;
int rank;
} coord_t;
// maximum coordinate
#ifndef COORDMAX
#define COORDMAX 10000
#endif
// max # of [infected] people
#ifndef PERSONMAX
#define PERSONMAX 106
#endif
#define SEARCHMAX (2 * (PERSONMAX - 1)) // max # of search coordinates
#define THRESHMAX 30 // maximum threshold
coord_t self; // coordinates of tracer
typedef int (*cmpfnc_p)(const coord_t *,const coord_t *);
int opt_d; // 1=debug
int opt_f; // distance mode (0=manhattan, 1=sqrt)
unsigned int opt_R; // random fill
void gentest(FILE *fi);
// disti -- get distance from given coordinate to self (manhattan distance)
int
disti(const coord_t *pt)
{
int dif;
int tot = 0;
dif = pt->x - self.x;
if (dif < 0)
dif = -dif;
tot += dif;
dif = pt->y - self.y;
if (dif < 0)
dif = -dif;
tot += dif;
return tot;
}
// distf -- get distance from given coordinate to self (floating pt distance)
int
distf(const coord_t *pt)
{
double dif;
double tot = 0;
int rtn;
dif = pt->x - self.x;
dif *= dif;
tot += dif;
dif = pt->y - self.y;
dif *= dif;
tot += dif;
tot = sqrt(tot);
// scale result
// FIXME -- this is untested and may not be necessary
tot *= INT_MAX;
tot /= COORDMAX;
rtn = round(tot);
return rtn;
}
// dist -- get distance from given coordinate to self
int
dist(const coord_t *pt)
{
int tot;
if (opt_f)
tot = distf(pt);
else
tot = disti(pt);
return tot;
}
// compareAbs -- compare two coordinates for lowest X/Y values
int
compareAbs(const coord_t *p1,const coord_t *p2)
{
int cmp;
do {
// use lower X coordinate
cmp = p1->x - p2->x;
if (cmp)
break;
// use lower Y coordinate
cmp = p1->y - p2->y;
if (cmp)
break;
} while (0);
return cmp;
}
// compareTo -- compare two coordinates for distance from self and then position
int
compareTo(const coord_t *p1,const coord_t *p2)
{
int cmp;
do {
// compare distance to self
cmp = dist(p1) - dist(p2);
if (cmp)
break;
// compare against absolute coordinates
cmp = compareAbs(p1,p2);
} while (0);
return cmp;
}
// sortswap -- swap array elements
void
sortswap(coord_t *p1,coord_t *p2)
{
coord_t tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
// sortinsert -- insertion sort
void
sortinsert(coord_t *list,int count,cmpfnc_p cmp)
{
for (int i = 1; i < count; ++i) {
for (int j = i; j > 0; --j) {
if (cmp(&list[j - 1],&list[j]) <= 0)
break;
sortswap(&list[j - 1],&list[j]);
}
}
}
// sortany -- outer sort routine
void
sortany(coord_t *list,int count,int threshold,cmpfnc_p cmp)
{
// TODO: do mergesort
if (count < threshold) {
}
// finish with insertion sort
sortinsert(list,count,cmp);
}
// binarysearch -- perform binary search on coordinate list
int
binarysearch(const coord_t *search,const coord_t *array,int length,
cmpfnc_p cmpfnc)
{
int low = 0;
int high = length - 1;
int match = -1;
// Search while there is a valid search space.
while (low <= high) {
int mid = (low + high) / 2;
int cmp = cmpfnc(search,&array[mid]);
// found it
if (cmp == 0) {
match = mid;
break;
}
// Value is too small.
if (cmp < 0)
high = mid - 1;
// too big.
else
low = mid + 1;
}
return match;
}
// main -- main program
int
main(int argc,char **argv)
{
const char *file = NULL;
char *cp;
FILE *fi;
int person_count;
int search_count;
int threshold;
coord_t *pt;
coord_t *person_list;
coord_t *search_list;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'd':
opt_d = ! opt_d;
break;
case 'f':
opt_f = ! opt_f;
break;
case 'R':
cp += 2;
opt_R = (*cp != 0) ? atoi(cp) : time(NULL);
printf("R=%u\n",opt_R);
srand(opt_R);
break;
}
}
// get/open input file
do {
fi = stdin;
if (argc <= 0) {
if (opt_R)
fi = stdout;
else
fi = stdin;
break;
}
file = *argv;
fi = fopen(file,opt_R ? "w" : "r");
if (fi == NULL) {
perror(file);
exit(1);
}
} while (0);
// generate test data
if (opt_R) {
gentest(fi);
fclose(fi);
exit(0);
}
fscanf(fi,"%d %d %d %d %d",
&self.x,&self.y,&person_count,&search_count,&threshold);
person_list = calloc(person_count,sizeof(*person_list));
if (person_list == NULL) {
perror("person_list");
exit(1);
}
search_list = calloc(search_count,sizeof(*search_list));
if (search_list == NULL) {
perror("search_list");
exit(1);
}
// read in coordinates of all people
for (int idx = 0; idx < person_count; ++idx) {
pt = &person_list[idx];
fscanf(fi,"%d %d",&pt->x,&pt->y);
}
// read in all search coordinates
for (int idx = 0; idx < search_count; ++idx) {
pt = &search_list[idx];
fscanf(fi,"%d %d",&pt->x,&pt->y);
}
// get the ranking
sortany(person_list,person_count,threshold,compareTo);
// remember the ranking and print the ranked list
for (int idx = 0; idx < person_count; ++idx) {
pt = &person_list[idx];
pt->rank = idx;
if (opt_d)
printf("%d %d dist=%d rank=%d\n",pt->x,pt->y,dist(pt),idx);
else
printf("%d %d\n",pt->x,pt->y);
}
// reorder list for search points
sortany(person_list,person_count,threshold,compareAbs);
// perform all queries
for (int idx = 0; idx < search_count; ++idx) {
pt = &search_list[idx];
int match = binarysearch(pt,person_list,person_count,compareAbs);
if (match < 0) {
printf("%d %d not found\n",pt->x,pt->y);
continue;
}
pt = &person_list[match];
printf("%d %d found at rank %d\n",pt->x,pt->y,pt->rank);
}
if (file != NULL)
fclose(fi);
free(person_list);
free(search_list);
return 0;
}
// gencoord -- generate a random coordinate
void
gencoord(coord_t *pt)
{
int val;
int neg;
for (int mode = 0; mode <= 1; ++mode) {
val = rand();
neg = (val & 1);
val >>= 1;
val %= (COORDMAX + 1);
if (neg)
val = -val;
if (mode == 0)
pt->x = val;
else
pt->y = val;
}
}
// genrand -- genrate a random number in the inclusive range
int
genrand(int lo,int hi)
{
int val;
val = rand();
val %= (hi + 1);
if (val < lo)
val = lo;
return val;
}
// gensame -- decide if coordinate already in use
int
gensame(coord_t *pt,coord_t *list,int length)
{
int match;
do {
// coordinate may _not_ be the starting/self point
match = (compareAbs(pt,&self) == 0);
if (match)
break;
// coordinate may not match any previous point in the list
for (int idx = 0; idx < length; ++idx) {
match = (compareAbs(pt,&list[idx]) == 0);
if (match)
break;
}
} while (0);
return match;
}
// gentest -- generate a random test file
void
gentest(FILE *fi)
{
int val;
int threshold;
int person_count;
int search_count;
int same;
coord_t *person_list;
coord_t *pt;
coord_t tmp;
gencoord(&self);
person_count = genrand(2,PERSONMAX);
search_count = genrand(1,SEARCHMAX);
threshold = genrand(1,THRESHMAX);
fprintf(fi,"%d %d %d %d %d\n",
self.x,self.y,person_count,search_count,threshold);
person_list = calloc(person_count,sizeof(*person_list));
if (person_list == NULL) {
perror("person_list");
exit(1);
}
// generate coordinates of all people
fprintf(fi,"\n");
for (int idx = 0; idx < person_count; ++idx) {
pt = &person_list[idx];
pt->rank = 0;
// ensure [proposed] coordinate is unique
same = 1;
while (same) {
gencoord(pt);
same = gensame(pt,person_list,idx);
}
fprintf(fi,"%d %d\n",pt->x,pt->y);
}
// generate search coordinates
fprintf(fi,"\n");
for (int idx = 0; idx < search_count; ++idx) {
pt = &tmp;
val = rand();
val %= 100;
// generate a random point that is _not_ a person or self (10% of the
// time)
if (val < 10) {
same = 1;
while (same) {
gencoord(pt);
same = gensame(pt,person_list,person_count);
}
}
// randomly select an infected person
else {
val = genrand(0,person_count - 1);
pt = &person_list[val];
}
fprintf(fi,"%d %d\n",pt->x,pt->y);
}
free(person_list);
}

Related

Cycle through an array in either direction based on a bool

I'm looking for a method of looping through some array in either direction based on some passed bool value, with the same functionality as:
void Transfer(bool *_payload, int _size, bool _isLSB)
{
if (_isLSB)
{
for (int i = _size - 1; i >= 0; i--)
{
digitalWrite(dataPin, _payload[i]);
}
}
else
{
for (int i = 0; i < _size; i++)
{
digitalWrite(dataPin, _payload[i]);
}
}
}
or
void Transfer(bool *_payload, int _size, bool _isLSB)
{
int _index = 0;
if (_isLSB) _index = _size - 1;
for (;;)
{
printf("%d",_payload[_index]);
if (_isLSB) _index--;
else _index++;
if (_isLSB && _index < 0) break;
if (!_isLSB && _index >= _size) break;
}
}
Other than creating a method that reverses the array, is there a nice simplification of this?
You can define the starting and ending point and the increment conditionally:
void Transfer(bool *_payload, int _size, bool _isLSB)
{
int increment = _isLSB ? -1 : 1;
int i = _isLSB ? _size : -1; // one before the area to scan
int end = _isLSB ? -1 : _size; // one past the area
while ((i += increment) != end) // incr/decr before testing
{
digitalWrite(dataPin, _payload[i]);
}
}
We do not know in advance which way the index will be changing (incrementing or decrementing), so we can't use less-than or greater-than in the loop condition. And after processing the last item the index will be modified once more, hence the stopping point is one past the area being processed.
Similarly we need the starting point one position before the scanned area, so that after incrementing (or decrementing) the index we process the valid, first item.
You can calculate the direction and the start/end position for the for loop depending on _isLSB
void Transfer(bool* _payload, int _size, bool _isLSB) {
int dir;
int start;
int end;
if(_isLSB) {
dir = -1;
start = _size-1;
end = -1;
}else {
dir = 1;
start = 0;
end = _size;
}
for(int i = start; i != end; i+=dir) {
digitalWrite(dataPin, _payload[i]);
}
}
What you could do for example, since in C true and false are expanded to integer values in reality, is to use said integer value for calculations.
In the following example I will extract the main problem from your question which is: Looping over a size in a direction depending on a boolean value
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
int main()
{
int size = 5;
bool condition = false;
// Option #1
printf("Option #1\n");
for (int i = (size - 1) * condition; (i >= 0 && condition) || (i < size && !condition); i += 1 * pow(-1, condition))
{
printf("%d", i);
}
// Option #2
printf("\nOption #2\n");
int i = (size - 1) * condition;
for (;;)
{
printf("%d", i);
i += 1 * pow(-1, condition);
if ((i < 0 && condition) || (i >= size && !condition))
break;
}
return 0;
}
With the main function giving the following output for condition = true
Option #1
01234
Option #2
01234
And the following output for condition = false
Option #1
43210
Option #2
43210

How to find the minimum number of coins needed for a given target amount(different from existing ones)

This is a classic question, where a list of coin amounts are given in coins[], len = length of coins[] array, and we try to find minimum amount of coins needed to get the target.
The coins array is sorted in ascending order
NOTE: I am trying to optimize the efficiency. Obviously I can run a for loop through the coins array and add the target%coins[i] together, but this will be erroneous when I have for example coins[] = {1,3,4} and target = 6, the for loop method would give 3, which is 1,1,4, but the optimal solution is 2, which is 3,3.
I haven't learned matrices and multi-dimensional array yet, are there ways to do this problem without them? I wrote a function, but it seems to be running in an infinity loop.
int find_min(const int coins[], int len, int target) {
int i;
int min = target;
int curr;
for (i = 0; i < len; i++) {
if (target == 0) {
return 0;
}
if (coins[i] <= target) {
curr = 1 + find_min(coins, len, target - coins[i]);
if (curr < min) {
min = curr;
}
}
}
return min;
}
I can suggest you this reading,
https://www.geeksforgeeks.org/generate-a-combination-of-minimum-coins-that-results-to-a-given-value/
the only thing is that there is no C version of the code, but if really need it you can do the porting by yourself.
Since no one gives a good answer, and that I figured it out myself. I might as well post an answer.
I add an array called lp, which is initialized in main,
int lp[4096];
int i;
for (i = 0; i <= COINS_MAX_TARGET; i++) {
lp[i] = -1;
}
every index of lp is equal to -1.
int find_min(int tar, const int coins[], int len, int lp[])
{
// Base case
if (tar == 0) {
lp[0] = 0;
return 0;
}
if (lp[tar] != -1) {
return lp[tar];
}
// Initialize result
int result = COINS_MAX_TARGET;
// Try every coin that is smaller than tar
for (int i = 0; i < len; i++) {
if (coins[i] <= tar) {
int x = find_min(tar - coins[i], coins, len, lp);
if (x != COINS_MAX_TARGET)
result = ((result > (1 + x)) ? (1+x) : result);
}
}
lp[tar] = result;
return result;
}

Snake Game implementation in C

I need some help with some homework. I am supposed to make a Snake Game by using mostly "basic" c, only simple concepts.
To explain my thought process: Controls are the usual WASD. The grid we re playing in is an array. Head is represented by '#' and the tail by "*". What I am trying to do is implement this thinking:
Get input from user, move the head. Check in 4 possible directions of head's initial position, find the " * ", move it to the initial position of the head. Repeat till all '*' have been moved.
Obviously, I am doing something wrong while checking and/or moving, but I cannot quite figure out what parts I am treating wrong and after 2 days I am stuck with this as my closest to working version. I know I have been looking at it for too long, but I cant afford to take more time with it as it needs to be turned in.
Here is my code. I hope my error is very obvious to "fresh eyes".
main:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]){
//get size of grid from args
int size;
size = atoi(argv[1]);
while(size < 6){
printf("Please insert a number greater than 6 so the game is
playable\n");
scanf("%d\n", &size);
}
char grid[size][size];
int sx,sy; //coordinates of snake head
int length = 2; //length of tail (without head)
int score = 0;
sx = 1;
sy = size/2;
//generate empty grid
int x, y;
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
if (y == 0 || y == size - 1) {
grid[y][x] = '-';
} else if (x == 0 || x == size - 1) {
grid[y][x] = '|';
} else {
grid[y][x] = ' ';
}
}
}
//initialize snake position
grid[sx][sy] = '#';
grid[sx+1][sy] = '*';
grid[sx+2][sy] = '*';
grid[sx+3][sy-6] = 'X';//just to test if it works, will be generated
randomly
//print grid
printGrid(size, grid);
play(sx,sy,size,grid,&length);
printf("*********GAME OVER********** \n final score: %d\n", score);
}
play() function. Practically all of the game.
int play(int x, int y, int size, char grid[size][size], int length){
int x0,y0,x1,y1,x2,y2,valid;//x0,y0 = current, x1,y1 next to check,
//x2,y2 = move there x0,y0
char end,dir; //what did the head land on
int score = 0;
int checkl = 0;
while(1){
scanf("%c", &dir);
switch(dir){
//move head, change head coordinates
case 'w': end = grid[x-1][y];
grid[x-1][y] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
x--;
break;
case 's': end = grid[x+1][y];
grid[x+1][y] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
x++;
break;
case 'a': end = grid[x][y-1];
grid[x][y-1] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
y--;
break;
case 'd': end = grid[x][y+1];
grid[x][y+1] = grid[x][y];
grid[x][y] = ' ';
x0 = x;
y0 = y;
y++;
break;
}
if ((end == '-') | (end =='|') | (end == '*')){
break;
}
printf("POINT 1\n");
do{
check(x0,y0,&x1,&y1, size, grid);
move(x0,y0, x2,y2, size, grid);
//if(valid == 1){
x2 = x0;
y2 = y0;
x0 = x1;
y0 = y1;
//}
checkl++;
printf("POINT 2\n");
}while(checkl <= length);
printf("POINT 3\n");
if (end == 'X'){
grid[x1][y1] = '*';
length++;
score += 10;
}
clearScreen();
printGrid(size, grid);
}
return score;
}
check() function. Implements the "look for the next '*'" process
int check(int x0, int y0, int *x1, int *y1, int size, char grid[size]
[size]){
if (grid[x0][y0-1] == '*'){
*x1 = x0;
*y1 = y0-1;
return 1;
}
else if (grid[x0][y0+1] == '*'){
*x1 = x0;
*y1 = y0+1;
return 1;
}
else if (grid[x0-1][y0] == '*'){
*x1 = x0-1;
*y1 = y0;
return 1;
}
else if (grid[x0+1][y0] == '*'){
*x1 = x0+1;
*y1 = y0;
return 1;
}
else
return 0;
}
move(). Self-explanatory
void move(int x0, int y0, int x2, int y2, int size, char grid[size]
[size]){
grid[x2][y2] = grid[x0][y0];
grid[x0][y0] = ' ';
}
A function to clear the window
void clearScreen()
{
const char *CLEAR_SCREEN_ANSI = "\e[1;1H\e[2J";
write(STDOUT_FILENO, CLEAR_SCREEN_ANSI, 12);
}
PrintGrid. Also self explanatory, have it as a function for convenience
void printGrid(int size, char grid[size][size]){
int y,x;
for (y = 0; y < size; ++y) {
for (x = 0; x < size; ++x) {
printf("%c", grid[y][x]);
}
printf("\n");
}
}
I believe the error is either in check, move, and in the do-while condition with the length in play. However, as I said, with a lot of trial and error, I am still here.
All of this should be in one file, but i could not align it properly all together. Thanks for any help, very appreciated.
Edit: Edited part of the code out. Now what happens after running the code is: I get the grid and the snake. The head moves just fine, along with the first '" of the tail but the rest does not follow. When it "eats" an 'X', it grows the tail where it should, but the '' added disappears in the next move. Also, the score goes up 20 instead of 10 so for some reason it enters the if twice for one move. The movement of the head + the first '*' as well as the "game over" scenarios work as they should.
Tidbit: This is only 10 actual characters, not 12 because the \ characters don't count:
const char *CLEAR_SCREEN_ANSI = "\e[1;1H\e[2J";
Better is to let the compiler count for you:
void clearScreen()
{
static const char CLEAR_SCREEN_ANSI[] = "\e[1;1H\e[2J";
write(STDOUT_FILENO, CLEAR_SCREEN_ANSI, sizeof(CLEAR_SCREEN_ANSI)-1);
}
Note that CLEAR_SCREEN_ANSI is now an array, not a pointer, and the -1 is for the trailing NUL byte.
Aha:
if ((end == '-') | (end =='|') | (end == '*')){
The | are bitwise OR and you almost certainly mean logical OR ||:
if ((end == '-') || (end =='|') || (end == '*')){
Edit: They actually do the same thing in this case, but it's a common-enough error that it's worth fixing.
Hat tip to #Sami Kuhmonen
I've spent some time looking at this, and it's clear this is entirely about program logic and less about C, so that makes it a lot more difficult to dive into something unfamiliar (and without a real spec).
The general idea is that the program draws a square playing field with a three-part snake: an # for a head and two * for the body, and the keyboard lets you move the snake around on the field with awds keys. You can't move on top of yourself, you can't go past the walls, and you want to find the food at location marked with X.
I believe your approach was to look for * characters, but I am not sure how it could tell a * from the middle of the snake from one at the end, so my approach is to maintain an array of all the positions of the snake, and in the main function it's initialized:
int ysnake[4] = { 1, 2, 3, 4 };
int xsnake[4] = { 15, 15, 15, 16 };
plus an obvious function to draw the snake given the position array:
static void drawsnake(
int snakelen, int xsnake[snakelen], int ysnake[snakelen],
int size, char grid[size][size])
{
char snakechar = '#'; // start with snake head
for (int i = 0; i < snakelen; i++)
{
grid[ ysnake[i] ]
[ xsnake[i] ] = snakechar;
snakechar = '*'; // all the rest are tails
}
}
So now we have the play() function, and this required quite a bit of refactoring, but it works for me.
int play(
int snakelen, int xsnake[snakelen], int ysnake[snakelen],
int size, char grid[size][size])
{
int score = 0;
while (1)
{
char dir;
scanf ("%c", &dir);
int proposed_xhead = xsnake[0];
int proposed_yhead = ysnake[0];
switch (dir)
{
case 'w': // up
proposed_yhead--;
break;
case 's': // down
proposed_yhead++;
break;
case 'a': // left
proposed_xhead--;
break;
case 'd': // right
proposed_xhead++;
break;
default: // ignore this invalid char
continue;
}
// first make sure we didn't go off the edge of the field
if (proposed_yhead <= 0 || proposed_yhead >= (size-1)
|| proposed_xhead <= 0 || proposed_xhead >= (size-1))
{
// would head off the maze, LOSE
break;
}
const char char_at_proposed_head = grid[proposed_yhead][proposed_xhead];
// now make sure we're not bumping into ourself
if (char_at_proposed_head == '#' // we shouldn't ever be able to bump into our head
|| char_at_proposed_head == '*') // we bumped into our tail
{
break; // would run into ourself: LOSE
}
// NOW we know it's a legal move. Did we find the food?
if (char_at_proposed_head == 'X')
{
// found the food!
// update score, set new food, etc.
score += 10;
}
// blank out the former tail; we're about to lose that position
grid[ ysnake[ snakelen-1 ] ]
[ xsnake[ snakelen-1 ] ] = ' ';
// shift all items down in the array, dropping the last one
for (int i = snakelen-1; i > 0; i--)
{
xsnake[i] = xsnake[i-1];
ysnake[i] = ysnake[i-1];
}
xsnake[0] = proposed_xhead;
ysnake[0] = proposed_yhead;
drawsnake(snakelen, xsnake, ysnake, size, grid);
clearScreen ();
printGrid (size, grid);
}
return score;
}
There's a clear separation of duties, where the decoding of the direction key translates to a change in the snake's head position, then checking for out-of-bounds or running into yourself, and finding if you found the food.
Then we move the snake by shifting the entire array of positions: the tail element drops off and the new one shifts onto the front. Then we re-draw the snake with new positions.
The main function is the same as yours at the top to set up the grid, but the snake configuration and play looks like:
int main(int argc, argv)
{
...
int length = 4;
int ysnake[4] = { 1, 2, 3, 4 };
int xsnake[4] = { 15, 15, 15, 16 };
drawsnake(length, xsnake, ysnake, size, grid);
// Put the food somewhere
grid[sx + 3][sy - 6] = 'X'; //just to test if it works, will be generated randomly
printGrid (size, grid);
score = play(length, xsnake, ysnake, size, grid);
printf ("*********GAME OVER********** \n final score: %d\n", score);
}
I didn't really do anything meaningful with the score and have only barely tested it, but it does let the little guy slither around the screen, and it might be a bit easier to follow.
Good luck.

Iterator and Pointer on Matrix in C

For a JPEG image compression, I manipulate image in grey levels and 8bits by pixels
I have this type of matrix I dynamically allocated :
typedef char pixel_t;
pixel_t ** pix_matrix;
after allocating and filling it, I have a bidimensional array with the values (from -128 to +127) of the luminance of the picture.
For the JPEG compression, I need to iterate this array in zigzag like this:
So I want to create an Iterator structure for this type. This iterator must have 'current' and 'begin' members and I want those members to be pointers to the current element and first one of the matrix. In other words, I want to store the addresses and not the indexes. But after hours of tests, prints and researches, I couldn't find the way to make that possible. What type of pointer do I have to use? how make it point to the first address of my matrix? Is my request simply possible?
And if all of this is possible, how can I get the next element, and the value of the current one?
You can write an interator structure:
struct zigzag_t {
int width; // width, must be initialised
int height; // height, must be initialised
int x; // current x index
int y; // current y index
int underway; // dummy value to start at (0, 0)
};
which you must initialise with the width and height of your image. Write an interator function, so that you can use this iterator like this:
struct zigzag_t zz = {8, 8};
while (zigzag_next(&zz)) {
printf("(%d, %d)\n", zz.y, zz.x);
}
The iterator itself is not too complicated: If the sum of the x and y indices is odd, you walk southwest until you hit either the west or south edge. If the sum is even, you walk northeast until you hit either the north or east wall. If you hit the ne or sw edges, the east and south edges get priority. The iteration ends after you have visited the se edge.
Because the struct starts off with x and y both zero, the first point is (0, 1). In order to fix this, the dummy field underway, which also is zero, is used.
The iterator must be reset if you want to use it a second time. better yet, define and initialise a fresh iterator.
The iterator function:
int zigzag_next(struct zigzag_t *zz)
{
int odd = (zz->x + zz->y) % 2;
if (zz->underway == 0) {
zz->x = zz->y = 0;
zz->underway = 1;
return 1;
}
if (odd) {
/* walk southwest */
int w_edge = zz->x == 0;
int s_edge = zz->y == zz->height - 1;
if (s_edge) {
zz->x++;
return zz->x < zz->width;
} else if (w_edge) {
zz->y++;
} else {
zz->x--;
zz->y++;
}
} else {
/* walk northeast */
int e_edge = zz->x == zz->width - 1;
int n_edge = zz->y == 0;
if (e_edge) {
zz->y++;
return zz->y < zz->height;
} else if (n_edge) {
zz->x++;
} else {
zz->x++;
zz->y--;
}
}
return 1;
}
This solution returns the x and y positions, which you can use as indices to your double pointer to pixel data. It would not be hard to extend the struct to hold the base pointer to your pixel data and have the iterator function return a pointer to a pixel or NULL if the iteration has run out.
An example solution with pointers is below.
#include <stdlib.h>
#include <stdio.h>
typedef char pixel_t;
struct zigzag_t {
pixel_t **p; // base data
int width; // width, must be initialised
int height; // height, must be initialised
int x; // current x index
int y; // current y index
int underway; // dummy value to start at (0, 0)
};
pixel_t *zigzag_next(struct zigzag_t *zz)
{
int odd = (zz->x + zz->y) % 2;
if (zz->underway == 0) {
zz->x = zz->y = 0;
zz->underway = 1;
return *zz->p;
}
if (odd) {
/* walk southwest */
int w_edge = zz->x == 0;
int s_edge = zz->y == zz->height - 1;
if (s_edge) {
zz->x++;
if (zz->x == zz->width) return NULL;
} else if (w_edge) {
zz->y++;
} else {
zz->x--;
zz->y++;
}
} else {
/* walk northeast */
int e_edge = zz->x == zz->width - 1;
int n_edge = zz->y == 0;
if (e_edge) {
zz->y++;
if (zz->y == zz->height) return NULL;
} else if (n_edge) {
zz->x++;
} else {
zz->x++;
zz->y--;
}
}
return zz->p[zz->y] + zz->x;
}
int main()
{
pixel_t *data[] = {
"abcde", "fghij", "klmno", "pqrst", "uvwxy"
};
struct zigzag_t zz = {data, 5, 5};
for (;;) {
pixel_t *p = zigzag_next(&zz);
if (p == NULL) break;
putchar(*p);
}
putchar('\n');
return 0;
}
This solution is a C solution. There is no begin member function; initialisation is done via simple struct initialisation. There is no increment operator and no end member function; moving the iterator forward and checking for the end is done in a plain old function.
You have tagged the question C, but iterators are more frequent in C++, where they can be implemented as classes. The above C example may serve as a base for such an implementation.
Something nice and simple.
Function next is the iterator; it returns true until all cells have been visited.
A variable of type POSITION holds the iterator state.
Function current returns a pointer to the current cell in the matrix.
Demo function sample_application puts it all together.
#define MAX_XY 7
typedef struct { int x, y; } POSITION;
static int sign_of(int i)
{
return i < 0 ? -1 : i > 0 ? 1 : 0;
}
static int get_direction(int a, int b, int odd_is_forward)
{
return sign_of(((a + b) % 2 == odd_is_forward || b >= MAX_XY ? MAX_XY : 0) - a);
}
int next(POSITION *pos)
{
int x = pos->x;
int y = pos->y;
pos->x += get_direction(x, y, 0);
pos->y += get_direction(y, x, 1);
return x < MAX_XY || y < MAX_XY;
}
pixel_t *current(POSITION *pos)
{
return &pix_matrix[pos->y][pos->x];
}
void sample_application() // just demonstrating the use of POSITION
{
POSITION pos = {-1, -1}; // always start from these dummy coordinates
while (next(&pos)) // this iterates through the matrix
{
int coord_x = pos.x; // this is how you get the current coordinates
int coord_y = pos.y;
*current(&pos) = 12; // this is how you access the current cell
}
}

Find number of paths in a 2d binary array (C)

I have been asked this question during an interview, and have been struggling to find an elegant solution (in C), Problem statement:
You are given a two-dimensional array with M rows and N columns.
You are initially positioned at (0,0) which is the top-left cell in
the array.
You are allowed to move either right or downwards.
The array is filled with 1′s and 0′s. A 1 indicates that you can move
through that cell, a 0 indicates that you cannot move through the
cell.
Write a function in C ‘numberOfPaths’ which takes in the above two dimensional array, return the number of valid paths from the top-left cell to the bottom-right cell (i.e. [0,0] to [M-1,N-1]).
Edit: forgot to mention that the requirement is for a recursive solution
help would be greatly appreciated!
Thanks
If you are looking for a recursive solution you can use DFS.
DFS (array, x, y)
{
if (array [x][y]==0 || x>M || y>N){
return;
}
if (x==M && y==N){
count++;
return;
}
DFS (array, x, y+1);
DFS (array, x+1, y);
}
The number of paths to a given point is just the number of paths to the point above, plus the number of paths to the point to the left. So, the pseudo-code would roughly be:
num_paths[0][0] = 1;
for (x = 0; x < M; ++x)
for (y = 0; y < N; ++y)
if (!allowed_through[x][y])
num_paths[x][y] = 0;
else
num_paths[x][y] = num_paths[x-1][y] + num_paths[x][y-1];
You need special cases for x=0 and y=0, but otherwise, I think that should do.
#include <stdio.h>
int count=0;
int maxrows = 10;
int maxcols = 10;
int M, N;
void DFS (int array[][10], int x, int y)
{
int r, c;
/* process element at input row and column */
if (array [x][y]==0 || x>M || y>N){
/* no path forward; return */
return;
}
if (x==M-1 && y==N-1){
/* found path; increment count */
count++;
return;
}
/* recurse: to matrix starting from same row, next column */
r = x;
c = y +1;
if (c < N-1) {
DFS (array, r,c);
} else {
/* if last column - check to see */
/* if rest of rows in last column allow for a path */
int tr = r;
while ( tr <= M-1) {
if (array[tr][c] == 1) {
tr++;
}
else {
return;
}
}
/* reached last node - path exists! */
count++;
}
/* recurse: to matrix starting from next row, same column */
r = x+1;
c = y;
if (r < M-1) {
DFS (array, r,c);
} else {
/* if last row - check to see */
/* if rest of columns in last row allow for a path */
int tc = c;
while ( tc <= N-1) {
if (array[r][tc] == 1) {
tc++;
} else {
return;
}
}
/* reached last node - path exists! */
count++;
}
}
int main () {
int i, j;
scanf("%d %d",&M,&N);
int a[10][10] = {};
int row, col;
for(i=0;i<M;i++)
for(j=0;j<N;j++)
scanf("%d", &a[i][j]);
if ((M > maxrows) || (N > maxcols)) {
printf("max of 10 rows and 10 cols allowed for input\n");
return (-1);
};
/* print input matrix */
for(row=0;row<M;row++) {
for(col=0;col<N;col++){
printf("%d ",a[row][col]);
}
printf(" EOR\n");
}
DFS(a,0,0);
printf("number of paths is %d\n", count);
return 0;
}
Try this function its a preliminary step before printing all the paths.
If the size of the vector Out is 0 then the # of paths are 0, but if size(Out) > 0 then the size of vector Nodes + 1 are the total number of paths from top left to bottom right.
#include <iostream>
#include <vector>
using namespace std;
typedef vector<pair<int,int> > vPii;
bool pathTL2BR( int Arr2D[][4], vPii &Out, vPii &Nodes,
int _x,int _y, int _M, int _N)
{
bool out1 = false;
bool out2 = false;
if( Arr2D[_x][_y] == 1 )
{
if( _y+1 < _N )
out1 = pathTL2BR( Arr2D, Out, Nodes, _x, _y+1, _M, _N);
if( _x+1 < _M )
out2 = pathTL2BR( Arr2D, Out, Nodes, _x+1, _y, _M, _N);
if( (out1 || out2) ||
( (_x == (_M-1)) && (_y == (_N-1)) ) )
{
if(out1 && out2)
Nodes.push_back( make_pair(_x,_y ) );
Out.push_back( make_pair(_x,_y ) );
return true;
}
else
return false;
}
else
return false;
}
// Driver program to test above function
int main()
{
int Arr2D[][4] = {
{1,1,1,1},
{0,1,0,1},
{0,1,0,1},
{0,1,0,1}
};
vPii Out;
vPii Nodes;
vector<vPii> Output;
pathTL2BR( Arr2D, Out, Nodes, 0, 0, 4, 4);
return 0;
}
This is a python solution, I have put explanations in the comments.
def find_num_paths(arr_2D, i, j):
# i,j is the start point and you have to travel all the way back to 0,0
if i == j and i == 0:
return 1 # you have reached the start point
if i < 0 or j < 0 or arr_2D[i][j] == 0: # out of range or no path from that point
return 0
if arr_2D[i][j] == 1:
return find_num_paths(arr_2D, i, j-1) + find_num_paths(arr_2D, i-1, j) + find_num_paths(arr_2D, i-1, j-1) # you could go one step above, to the left or diagonally up.

Resources