I have an assignment where I need to let the user create the height and width of a grid. Then be able to place "ships" onto that grid at any x and y coordinates. Then you can place a storm on a certain section of that grid to then prompt and see if a storm is overlapped with a ship. I have done that successfully but I can't get the storm to wrap around the grid. For example if the grid is 20x20 and I put a storm that starts on the 20th spot over it should shift to the 1 position on the left side of the grid. Here is that code I have a diagram of what it looks like. (Note there is no physical grid getting printed to the terminal)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ship {
// Declaring variables
char shipName[21];
int x, y, w, h;
char direction;
struct ship *next;
} Ship;
//Declaring head of linked list
Ship *head = NULL;
void newShip(int x, int y, char direction, char *shipName) {
//Adding ships to linked list
Ship *new_ship = (Ship *)malloc(sizeof(Ship));
strcpy(new_ship->shipName, shipName);
new_ship->x = x;
new_ship->y = y;
new_ship->direction = direction;
new_ship->next = head;
head = new_ship;
}
void shipMovement(int time, int w, int h) {
//Moving ships
Ship *current = head;
while (current != NULL) {
if (current->direction = 'U') {
current->y = (current->y time) % h;
}
else if (current->direction = 'D') {
current->y = (current->y - time h) % h;
}
else if (current->direction = 'L') {
current->x = (current->x - time w) % w;
}
else if (current->direction = 'R') {
current->x = (current->x time) % w;
}
else {
printf("Invalid Direction!\n");
}
current = current->next;
}
}
void checkAffShips(int x, int y, int w, int h, char **affShips, int *numAffShips) {
//Checking if ships are affected by storm
Ship *current = head;
while (current != NULL) {
if (((current->x >= x) && (current->x < x w)) && ((current->y >= y) && (current->y < y h))) {
// add shipName to list of affected ships
affShips[*numAffShips] = (char *)malloc(sizeof(char) * 21);
strcpy(affShips[(*numAffShips) ], current->shipName);
}
current = current->next;
}
}
//Main Function------------------------------------------------------------------
int main() {
int w, h;
int stormWidth, stormHeight;
scanf("%d %d", &w, &h);
char userInput;
//Looping through commands
while (scanf(" %c", &userInput) != 4) {
if (userInput == '1') {
int x, y;
char direction[21], shipName[21];
scanf("%d %d %s %s", &x, &y, direction, shipName);
newShip(x, y, direction[0], shipName);
} else if (userInput == '2') {
int time;
scanf("%d", &time);
shipMovement(time, w, h);
} else if (userInput == '3') {
int x, y, w, h;
scanf("%d %d %d %d", &x, &y, &w, &h);
char *affShips[1000];
int numAffShips = 0;
checkAffShips(x, y, w, h, affShips, &numAffShips);
printf("%d\n", numAffShips);
for (int i = 0; i < numAffShips; i ) {
printf("%s\n", affShips[i]);
free(affShips[i]);
}
} else if (userInput == '4') {
break;
}
else {
printf("Invalid Input!\n");
}
}
return 0;
}
Here is the documentation: (https://i.stack.imgur.com/K28We.png)
I've tried a bunch of different stuff so maybe I just didn't do something right in my attempts but I'm sure someone can help figure this out.
CodePudding user response:
Your test for the affected ships is wrong. In your example, if you have a storm of size 2 in the bottom right corner (19, 19)
, a ship in the top left corner (0, 0)
isn't caught, because 0
is not in the range [19, 21)
.
One way to fix this is to move the point you want to test into the "extended range" if it lies below the starting point of the storm. (The "extended range" is the range that does not wrap and so extends to two times the width of the board.)
So to test whether a one-dimensional point lies in a cyclic range, you could use a function like this:
int in_cyclic_range(int n, int lower, int width, int wrap)
{
if (n < lower) n = wrap;
return (n < lower width);
}
If you now test n
in the whole range from [0, 20)
on the storm at 19
of width 2
, with in_cyclic_range(n, 19, 2, 20)
, you will get hits at locations 19
and 0
.
CodePudding user response:
In order to test if a ship is affected by a storm, you need the storm position and dimensions, the ship position and the grid dimensions.
In your code, you use w
, and h
for the grid dimensions and a new set of variables w
and h
for the storm dimensions in the local scope of if (userInput == '3') { ... }
. This is confusing and makes the grid dimensions inaccessible from this part of the code. You should use stormWidth
and stormHeight
for the storm dimensions and pass both these and the grid dimensions to the checkAffShips
function.
The test in checkAffShips
for the wrapped coordinate system is more complicated than what you wrote to take into account the wrapped parts of the storm area: as many as 3 extra rectangles.
Also note these issues:
- using explicit names for the grid and storm dimensions would help avoid confusion.
- the
w
andh
fields in theShip
structure are unused. - reading strings with
scanf
should be protected by specifying the maximum number of characters to store into the destination array before the null terminator. newShip
should not usestrcpy
directly as theshipName
argument could be longer than the destination array.- you should check the return value of
scanf()
to detect invalid or missing input. if (current->direction = 'U')
setscurrent->direction
and evaluates to true. You should use==
instead of=
- the array of shipnames
affShips
should be allocated bycheckAffShips
.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ship {
char shipName[21];
int x, y;
char direction;
struct ship *next;
} Ship;
//Declaring head of linked list
Ship *head = NULL;
/* string copy function with size limitation */
void mystrcpy(char *dest, size_t size, const char *src) {
while (size > 1) {
*dest = *src ;
size--;
}
if (size > 0)
*dest = '\0';
}
void newShip(int x, int y, char direction, const char *shipName) {
//Adding ship to linked list
Ship *new_ship = (Ship *)malloc(sizeof(*new_ship));
if (new_ship) {
mystrcpy(new_ship->shipName, sizeof new_ship->shipName, shipName);
new_ship->x = x;
new_ship->y = y;
new_ship->direction = direction;
new_ship->next = head;
head = new_ship;
}
}
void shipMovement(int time, int w, int h) {
//Moving ships
for (Ship *current = head; current != NULL; current = current->next) {
if (current->direction == 'U') {
current->y = (current->y time) % h;
} else
if (current->direction == 'D') {
current->y = (current->y h - time % h) % h;
} else
if (current->direction == 'L') {
current->x = (current->x w - time % w) % w;
} else
if (current->direction == 'R') {
current->x = (current->x time) % w;
} else {
printf("%s: invalid Direction '%c'!\n",
current->shipName, current->direction);
}
}
}
char **checkAffShips(int stormX, int stormY, int stormWidth, int stormHeight,
int gridWidth, int gridHeight,
int *pnumAffShips)
{
char **affShips = NULL;
int numAffShips = 0;
for (Ship *current = head; current != NULL; current = current->next) {
int x = current->x;
int y = current->y;
//Checking if ship is affected by storm
if (((x >= stormX && x < stormX stormWidth) ||
(stormX stormWidth > gridWidth && x < (stormX stormWidth) % gridWidth)) &&
((y >= stormY && y < stormY stormHeight) ||
(stormY stormHeight > gridHeight && y < (stormY stormHeight) % gridHeight)))
{
// add shipName to list of affected ships
affShips = realloc(affShips, sizeof(*affShips) * (numAffShips 1));
affShips[numAffShips ] = strdup(current->shipName);
}
}
*pnumAffShips = numAffShips;
return affShips;
}
//Main Function------------------------------------------------------------------
int main() {
int gridWidth, gridHeight;
if (scanf("%d %d", &gridWidth, &gridHeight) != 2)
return 1;
char userInput;
//Looping through commands
while (scanf(" %c", &userInput) == 1) {
if (userInput == '1') {
int x, y;
char direction[21], shipName[21];
if (scanf("%d %d s s", &x, &y, direction, shipName) != 4)
return 1;
newShip(x, y, direction[0], shipName);
} else
if (userInput == '2') {
int time;
if (scanf("%d", &time) != 1)
return 1;
shipMovement(time, gridWidth, gridHeight);
} else
if (userInput == '3') {
int x, y, stormWidth, stormHeight;
if (scanf("%d %d %d %d", &x, &y, &stormWidth, &stormHeight) != 4)
return 1;
char **affShips;
int numAffShips = 0;
affShips = checkAffShips(x, y, stormWidth, stormHeight,
gridWidth, gridHeight, &numAffShips);
printf("%d\n", numAffShips);
for (int i = 0; i < numAffShips; i ) {
printf("%s\n", affShips[i]);
free(affShips[i]);
}
free(affShips);
} else
if (userInput == '4') {
break;
} else {
printf("Invalid Input!\n");
}
}
return 0;
}