Array element disappears - c

I'm trying to track a player's location with x marking their spot. When the player enters a string I increment the coordinates accordingly. However when the player is located one space from the perimeter, then attempts to move to the edge of the map, the player disappears.
Example:
.....
...x.
.....
.....
.....
Player located at 'x'
If player enters string "right" and I move player_loc, array simply returns:
.....
.....
.....
.....
.....
I attempted to add a sort of buffer by increasing the size of the array. No luck. I've been stuck on this for almost a week now. Any help would be appreciated. I apologize for messy code. I'm a total newbie at this and I'm really just futzing around in the dark with all this stuff. I've researched this across the forums here and haven't found a solution. If you know of something that I possibly (probably) missed feel free to point me in that direction.
#include <stdio.h>
#include <string.h>
char map[6][6];
char player_loc = 'x';
int row;
int col;
void init_map()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
map[i][j] = '.';
}
}
}
void print_map()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%c", map[i][j]);
}
printf("\n");
}
}
int get_player_loc()
{
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if(map[j][k] == player_loc)
{
row = k;
col = j;
}
}
}
return row;
return col;
}
void init_player_loc()
{
int check = 1;
for (int g = 0; g < 5; g++) {
for (int h = 0; h < 5; h++) {
if (map[g][h] == 'x') {
check = 0;
}
}
}
if(check == 1) {
map[0][0] = player_loc;
} else {
get_player_loc();
}
}
void move_left()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j-1] = player_loc;
map[i][j] = '.';
}
}
}
}
void move_right()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
}
}
}
}
int main(int argc, char* argv[])
{
char input[15];
printf("You enter a room...you can go left, right, or straight. Which way do you go?\n");
int done = 0;
init_map();
map[3][3] = player_loc;
//init_player_loc();
print_map();
while (!done) {
scanf("%s", input);
if (strcmp("left", input) == 0) {
move_left();
printf("You go left...\n");
print_map();
get_player_loc();
printf("%d %d\n", row, col);
done = 1;
}
else if (strcmp("right", input) == 0) {
move_right();
printf("You go right...\n");
print_map();
get_player_loc();
printf("%d %d\n", row, col);
done = 1;
}
else if (strcmp("straight", input) == 0) {
printf("You go straight...");
done = 1;
}
else {
printf("Sorry, can't do that.\n");
}
}
}

You must break the loop if you find the player location, e.g
void move_right()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
return;
}
}
}
}
In your code you move right the player, and the next loop will find the player in the new location and do the right move again, forever.
Moreover in your code you are not taking care of boundaries of your 2d matrix: j+1 is valid only if j<5.
Then a better code should be
void move_right()
{
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
return;
}
}
}
}

The problem is that your move_right function picks up the player and moves them completely off of the map. Let's say your player is at [0, 2] and step through the code.
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
}
}
[0, 0] No player here, move along
[0, 1] No player here, move along
[0, 2] Found a player! Move them right to [0, 3]
[0, 3] Found a player! Move them right to [0, 4]
[0, 4] Found a player! Move them right to [0, 5]
At 5, the loop ends. Because of the buffer you added, your array is 6x6, so the player is stashed in the wings without crashing the program. There are a few things you should do:
Once you've found and moved the player, break or return so they'll only move once.
Make your array 5x5 (or print all 6x6) so you can see everything.
Do some bounds checking so the player isn't allowed to move right from j = 5.
Watch out for this same bug in move_up, where it would happen as you increment i.

Your loops allow for checking the position twice, once at i,j, and again at i,(j+1) (or some other variant). This probably isn't what you intend. After you find the player you should make the updates and then break out of the loops.
Also, the code as is allows for indexing passed the bounds of the array, in theory. Also not what is desired. You may consider bounds checking. I don't know what is supposed to happen when the player moves right and there is a wall to the right. Does he not move? Wrap around? LR corner could cause seg fault as it is now.

You appear to have row and column indeces transposed in the get_player_loc function, as well as having two return statements (the compiler should warn you about unreachable code), neither of which is required or used by the calling code.
At the start, initialise the row and col variables. (Values taken from your main.)
int row = 3;
int col = 3;
Change the get_player_loc function so that it just updates the globals row and col. It sets row and col to 0 if the player is not found, as per the original.
void get_player_loc(void)
{
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if(map[j][k] == player_loc)
{
// The meaning of row and col is set by how they are used
// to index the array in the move and print functions. Keep
// the same order and meaning here.
row = j;
col = k;
return;
}
}
}
// Set row and col to 0 if the location is not found.
row = 0;
col = 0;
map[0][0] = player_loc;
}
You'll still have problems when they reach an edge, due to the index into the array going out of bounds in the move functions, but that's a different problem.

Related

"If statement" whith array is not working

I wrote a function where a 1-dimensional array (int8_t tabelle1[768]) is transferred into a 2-dimensional array (int8_t tabelle[24][32]).
I now want to find a "Hotspot" in the 2-dimensional array. A "Hotspot" is an 2x2 block in the array (can be located anywhere) where each value of the block has to be equal or over 30.
My Problem is now that my program is not going into my if statement.
The "Checkpoint" is not being printed.
The function:
bool Hotspotberechnung(int8_t tabelle1[768],int8_t tabelle2[24][32])
{
int i=0, j=0, x=0, y=0;
for(j=0; j<24; j++) //Transfer from 1D into 2D
{
for(i=0; i<32; i++)
{
tabelle2[j][i] = tabelle1[(j*32)+i];
}
}
for(y=0; y<24; y++) //search for hotspot
{
for(x=0; x<32; x++)
{
if(tabelle2[y][x]>=30)
{
printf ("1\n"); // checkpoint
if(tabelle2[y][x+1]>=30)
{
if(tabelle2[y+1][x]>=30)
{
if(tabelle2[y+1][x+1]>=30)
{
for(j=0; j<24; j++)
{
for(i=0; i<32; i++)
{
printf("%d.%d=%d\n",j+1,i+1,tabelle2[j][i]);
}
}
printf ("Hotspot!");
return true;
}
else
return false;
}
else
return false;
}
else
return false;
}
else
return false;
}
}
return 0;
}
It never reaches the print, because one of your many returns ends the function much sooner than you think. Specifically the one in the else of the then wich contains the print.
Use a debugger and you will see that.
Alternatively put a print next to each else, make sure to use {} for that. Also put a print after the call to the shown function.
for(y=0; y<24; y++) //search for hotspot
{
for(x=0; x<32; x++)
{
if(tabelle2[y][x]>=30)
{
/* this is not reached for y=0 and x=0, i.e. first */
printf ("1\n"); // checkpoint
/* much code deleted */
}
else
return false;
/* this is reached first,
end of the function,
end of the loop,
no printing ever */
}
}
A few things ...
The kernal width/height is 2, so we have to stop short of the array width/height or we'll go beyond the end of the array
Once we find an element that matches, we have to use that element as the upper left anchor of the 2x2 box
Here's the refactored code (it compiles, but is not tested):
#include <stdio.h>
#include <stdint.h>
#define YMAX 24
#define XMAX 32
#define BOXWID 2
#define MARG (BOXWID - 1)
int
Hotspotberechnung(int8_t tabelle1[YMAX * XMAX], int8_t tabelle2[YMAX][XMAX])
{
int i = 0,
j = 0,
x = 0,
y = 0;
// Transfer from 1D into 2D
for (j = 0; j < YMAX; j++) {
for (i = 0; i < XMAX; i++)
tabelle2[j][i] = tabelle1[(j * XMAX) + i];
}
for (y = 0; y < (YMAX - MARG); y++) {
int8_t *row = tabelle2[y];
for (x = 0; x < (XMAX - MARG); x++) {
if (row[x] < 30)
continue;
int8_t *box = &row[x];
int match = 1;
for (int yoff = 0; yoff < BOXWID; ++yoff) {
for (int xoff = 0; xoff < BOXWID; ++xoff) {
if (box[(yoff * XMAX) + xoff] < 30) {
match = 0;
break;
}
}
if (! match)
break;
}
if (! match)
continue;
for (int yoff = 0; yoff < BOXWID; ++yoff) {
for (int xoff = 0; xoff < BOXWID; ++xoff) {
int8_t val = box[(yoff * XMAX) + xoff];
printf("[%d,%d] = %d\n",y + yoff,x + xoff,val);
}
}
}
}
return 0;
}

optimizing C code with imbedded for loops

void evolve(board prv, board nxt){
int i, j;
int n;
printf("\rGeneration %d\n", generation++);
if (printLazy == 1){
lazyPrint(prv);
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
if (prv[i][j] && (n == 3 || n == 2))
nxt[i][j] = true;
else if (!prv[i][j] && (n == 3))
nxt[i][j] = true;
else
nxt[i][j] = false;
}
}
}
** Some asked me to add the neighbors method so
static int neighbors (board b, int i, int j) {
int n = 0;
int i_left = max(0,i-1);
int i_right = min(HEIGHT, i+2);
int j_left = max(0,j-1);
int j_right = min(WIDTH, j+2);
int ii, jj;
for (ii = i_left; ii < i_right; ++ii) {
for (jj = j_left; jj < j_right; ++jj) {
n += b[ii][jj];
}
}
return n - b[i][j];
}
So I am working on optimizing this so that it will go faster and I'm stuck on how to optimize this more. Here's what I have so far
void evolve(board prv, board nxt) {
register int i, j;
int n;
bool next;
printf("\rGeneration %d\n", generation++);
if (printLazy == 1){
lazyPrint(prv);
}
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
if (prv[i][j])
if (n == 2)
next = true;
else if (n == 3)
next = true;
else
next = false;
else
if(n == 3)
next = true;
else
next = false;
nxt[i][j] = next;
}
}
}
Is there a better way to do this or are there any resources or videos y'all recommend?
Thanks, any help is appreciated.
Some ideas Inline your function neighbors(). Or turn it into a macro. Tidy up the conditional. To unroll the inner loop replace every use of i with the literal values so your code looks like :
for (j =0;.......
n = fun(prev, 0 ,j);
If.....
n = fun(prev, 1, j);
if......
and so on.
If the value of HEIGHT was let's say 100, then you get a code explosion of 100 function calls and 100 compound conditionals. Even worse if you unroll the outer loop.
If n was limited to say 8 neighbors, use a lookup table
bool foo[2][8] = { [1][2] = true, [1][3] = true, [0][3] = true };
for (j=0; j < WIDTH; ++j) {
for (i = 0; i < HEIGHT; ++i) {
n = neighbors(prv, i, j);
nxt[i][j] = foo[prv[i][j]][n];
}
}
A common weakness is the neighbors(prv, i, j) function itself. One trick to to oversize the 2D array by 1 on all four sides and populate the edge with false so neighbors() can always check 8 neighbors as it is never used on the edge/corners.
Making sure the 2nd dimension is a power of 2 helps also - simplifies index calculation. So if the original array way 12*11, make the new array (1+12+1)*(1+11+1+4) or 14*16.

Print repeating diamond shapes with custom rows, columns and length

I am new to C, and I am trying to print diamond shapes according to the rows(2~10), columns(2~10) and the length(3, 5, 7, 9) of the diamond input from the user.
Using the code below I can print diamond and number of diamonds correctly, but I just can't get the correct distance between them.
void printDiamondWith(int diamondlength, int numberOfDiamonds) {
int i, j, k;
int star, space;
star = 1;
space = diamondlength;
for (i = 1; i < diamondlength * 2 - 1; i++) {
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space; j++) {
printf(" "); // Print the distance for the previous star
}
for (j = 1; j < star * 2; j++) {
printf("*");
}
for (j = 0; j < space; j++) {
printf(" "); // Print the distance for the next star
}
}
printf("\n");
// Check if length is equal 3, else length -1 to get the correct rows of second half of the diamond
if (diamondlength == 3) {
// Loops until the first half of the diamond is finished, then reverse the process to print the second half
if(i < (diamondlength - diamondlength / 3)) {
space--;
star++;
} else {
space++;
star--;
}
} else if (diamondlength >= 3) {
if (i < (diamondlength - 1 - diamondlength / 3)) {
space--;
star++;
} else {
space++;
star--;
}
}
}
}
Actual running result:
Expected result:
Your formulas for calculating the space is off. It works for me when I change this
space = diamondlength;
to this
space = diamondlength/2+1;
And this
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space; j++) {
to this:
for (k = 0; k < numberOfDiamonds; k++) {
for (j = 0; j < space-1; j++) {
In such situations I recommend hardcoding the variable for different parameters and write down what the variable has to be for what parameter so you can try to find a function that maps the parameter to the value. For instance I saw that as diamondlength increased, the space error also increased, so the relation between parameter and variable can't be one to one.

Continue computation in do while even if no columns exist

What I am trying to do (not very successful) is if my code detects a signal (if(matrix[i][j] ==1)) coming (1 or 0) for the next few steps I want my code to write in a new matrix: newmatrix[i][j]=10 and if not to continue with 0. Here is my code so far:
for (i = 0; i < rows; i++) {
j = 0;
do {
if (matrix[i][j] == 1) {
int m = j;
while (j < m + 3) {
newmatrix[i][j] = 10;
printf("newmatrix[%i][%i] and %f\n", i, j, newmatrix[i][j]);
j++;
continue;
}
}
if (matrix[i][j] == 0) {
newmatrix[i][j] = 0;
printf("newmatrix[%i][%i] and 0 is %f\n", i, j, newmatrix[i][j]);
j++;
continue;
}
j++;
} while (j < MAXTIME);
}
}
The problem is that if there is a signal near the end instead of stopping when to column count reaches the max number the code inserts new columns even though they are only 10:
Where is my mistake can someone point me to the right direction? Is there maybe a way to do this cleaner with goto statement?
Here is a simpler approach with a temporary variable:
for (i = 0; i < rows; i++) {
int spike = 0;
for (j = 0; j < MAXTIME; j++) {
if (matrix[i][j] == 1) {
spike = 3;
}
if (spike) {
newmatrix[i][j] = 10;
spike--;
} else {
newmatrix[i][j] = 0;
}
printf("newmatrix[%i][%i] is %f\n", i, j, newmatrix[i][j]);
}
}
Notes:
I am assuming that matrix[i][j] is either 0 or 1. If other values are possible and newmatrix[i][j] should stay unmodified for these cells, the code should be modified.
It is advisable to only modify a loop index in the for update clause. do / while loops are notoriously error prone, especially with nested loops that also modify the loop index as is the case in your code.

Find the duplicate elements in a two-dimensional array

I need to find the duplicate elements in a two dimensional array.
route_ptr->route[0][1] = 24;
route_ptr->route[0][2] = 18;
route_ptr->route[1][1] = 25;
route_ptr->route[2][1] = 18;
route_ptr->route[3][1] = 26;
route_ptr->route[3][2] = 19;
route_ptr->route[4][1] = 25;
route_ptr->route[4][2] = 84;
Those are my data; the duplicate entries of route[2][1] (duplicate of route[0][2]) and route[4][1] (duplicate of route[1][1]) has to be found.
The solution is the duplicate 'i' value of route[i][j] which is 2 & 4 from this example.
please guide me.
#include <stdio.h>
struct route{
int route[6][6];
int no_routes_found;
int count_each_route[6];
};
int main() {
struct route *route_ptr, route_store;
route_ptr=&route_store;
int i,j,k;
// the data
route_ptr->route[0][1] = 24;
route_ptr->route[0][2] = 18;
route_ptr->route[1][1] = 25;
route_ptr->route[2][1] = 18;
route_ptr->route[3][1] = 26;
route_ptr->route[3][2] = 19;
route_ptr->route[4][1] = 25;
route_ptr->route[4][2] = 84;
route_ptr->count_each_route[0]=3;
route_ptr->count_each_route[1]=2;
route_ptr->count_each_route[2]=2;
route_ptr->count_each_route[3]=3;
route_ptr->count_each_route[4]=3;
route_ptr->no_routes_found=5;
//// process
for (i = 0; i <(route_ptr->no_routes_found) ; i++)
{
for (j = 1; j < route_ptr->count_each_route[i]; j++)
{
printf("\nroute[%d][%d] = ", i, j);
printf("%d",route_ptr->route[i][j]);
}
}
}
The solution expected is:
route[0][1] is compared by route [0][2] i.e [24 !=18]
route[0][1] and route [0][2] is compared by route[1][1] i.e [24 && 18 !=25]
route[0][1] and route[0][2] and route[1][1] is compared by route[2][1] i.e [ 24&&18&&25 is compared by 18, there is a matching element,
save the newcomer 'i' value which matches to the existence and drop it for next checking]
break the 'i' loop
route[0][1], route[0][2], route[1][1] is now compared route[3][1]
route[0][1], route[0][2], route[1][1] ,[3][1] is now compared route[3][2]
route[0][1], route[0][2], route[1][1] ,[3][1] ,[3][2] is now compared to route [4][1] i.e [ now there is a match to route[1][1], so save the newcomer 'i' value and break the 'i' loop
So i values [2 and 4] are duplicate, and that is my expected result of my code.
Got something against index zero, zero?
I also don't see the point of the pointer shenanigans.
It's a general safety thing to initialize all your data. You know, to zero or something.
The algorithm you suggest in your solution is rather hard to be faithful to, but this will find your duplicates. You have to walk through the entire array, in both dimensions, twice.
This will also match all the zeroes in your data, so you could add an exception to ignore routes values of zero.
//Cycling through the array the first time.
for (i = 0; i < 6 ; i++)
{
for (j = 0; j < 6; j++)
{
//Cycling through the array the second time
for (x = 0; x < 6 ; x++)
{
for (y = 0; y < 6; y++)
{
if(i==x && j==y)
continue;
if(routestore.route[i][j] == routestore.route[x][y])
printf("You have a match [%d][%d] = [%d][%d]", i, j, x,y);
}
}
}
}
Ok, so if you only want to see matches once, ie [0][2] == [2][1] but not [2][1] == [0][2], then you can do something like what I have below. This one made me scratch my head. Usually, when it's a simple list of items, you initialize the inner loop to the value of the outer loop, plus one. But you can't quite do that when it's a 2D array. So I gave up and made a super-lame hack-job. I'm a big fan of brute forcing things when possible. I'd normally tell you not to use pointers like this.
Now... this will still have multiple hits if you have three similar values. If that irks you then you need to start building a list and comparing hits against that as you walk through the data.
#include <stdio.h>
#include <string.h>
struct route{
int route[6][6];
int no_routes_found;
int count_each_route[6];
};
int lameAddOneAlternative(int *i, int *j)
{
if((*j)<6)
{
(*j)++;
return 1;
}
else if (*i<6)
{
(*i)++;
(*j) = 0;
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
struct route routeStore;
int i,j,x,y;
memset(routeStore.route,0,sizeof(int)*36);
// the data
routeStore.route[0][1] = 24;
routeStore.route[0][2] = 18;
routeStore.route[1][1] = 25;
routeStore.route[2][1] = 18;
routeStore.route[3][1] = 26;
routeStore.route[3][2] = 19;
routeStore.route[4][1] = 25;
routeStore.route[4][2] = 84;
//Cycling through the array the first time.
for (i = 0; i < 6 ; i++)
{
for (j = 0; j < 6; j++)
{
x=i;
y=j;
//Cycling through the array the second time
while(lameAddOneAlternative(&x,&y))
{
if(routeStore.route[i][j] == 0 )
continue;
if(routeStore.route[i][j] == routeStore.route[x][y])
printf("You have a match [%d][%d], [%d][%d] == %d\n", i, j, x,y, routeStore.route[i][j] );
}
}
}
}
for (i = 0; i <(route_ptr->no_routes_found) ; i++)
{
for (j = 1; j < route_ptr-> count_each_route[i]; j++)
{
for (x = 0; x < (route_ptr->no_routes_found) ; x++)
{
for (y = 0; y < route_ptr-> count_each_route[x]; y++)
{
if(i==x && j==y)
continue;
if(route_ptr->route[i][j] == route_ptr->route[x][y])
printf("You have a match [%d][%d] = [%d][%d]\n", i, j, x,y);
}
}
}

Resources