Click here to Skip to main content
15,877,145 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h> // for sleep() function
#include <errno.h>

enum direction { UP, DOWN, LEFT, RIGHT };

struct ant {
    int row;
    int col;
    enum direction dir;
};

void print_map(char **map, int rows, int cols, struct ant langton_ant, struct ant random_ant) {
    system("clear"); // Clear the console

    // Print the borders of the map
    for (int j = 0; j < cols+2; j++) {
        printf("* ");
    }
    printf("\n");

    // Print the map contents
    for (int i = 0; i < rows; i++) {
        printf("* ");
        for (int j = 0; j < cols; j++) {
            if (i == langton_ant.row && j == langton_ant.col) {
                printf("\x1b[41m"); // Red background color for Langton's ant
                if (langton_ant.dir == UP) {
                    printf("^ ");
                } else if (langton_ant.dir == RIGHT) {
                    printf("> ");
                } else if (langton_ant.dir == LEFT) {
                    printf("< ");
                } else if (langton_ant.dir == DOWN) {
                    printf("v ");
                }
                printf("\x1b[0m"); // Reset color to default
            } else if (i == random_ant.row && j == random_ant.col) {
                printf("\x1b[44m"); // Blue background color for random ant
                if (random_ant.dir == UP) {
                    printf("^ ");
                } else if (random_ant.dir == RIGHT) {
                    printf("> ");
                } else if (random_ant.dir == LEFT) {
                    printf("< ");
                } else if (random_ant.dir == DOWN) {
                    printf("v ");
                }
                printf("\x1b[0m"); // Reset color to default
            } else if (i == rows/2 && j == cols/2) {
                printf("\x1b[42m"); // Green background color for center of the map
                printf("  ");
                printf("\x1b[0m"); // Reset color to default
            } else {
                printf("%c ", map[i][j]);
            }
        }
        printf("*\n");
    }

    // Print the borders of the map
    for (int j = 0; j < cols+2; j++) {
        printf("* ");
    }
    printf("\n");
}
int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Error: Invalid number of arguments\n");
        return 1;
    }

    int waiting_time = atof(argv[1]); // get waiting time from command line argument
    int num_steps = atoi(argv[2]); // get number of steps from command line argument
    FILE *input_file = fopen("input.txt", "r");
    if (input_file == NULL) {
        printf("Error: Unable to open input file\n");
        return 1;
    }

    int rows, cols, ant1_row, ant1_col, ant2_row, ant2_col;

    if (fscanf(input_file, "%d %d %d %d %d %d", &rows, &cols, &ant1_row, &ant1_col, &ant2_row, &ant2_col) != 6) {
        printf("Error: Invalid input format\n");
        return 1;
    }

    char **map = (char**)malloc(rows * sizeof(char*));

    for (int i = 0; i < rows; i++) {
        map[i] = (char*)malloc(cols * sizeof(char));
        for (int j = 0; j < cols; j++) {
            if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1) {
                map[i][j] = ' ';
            } else {
                map[i][j] = ' ';
            }
        }
    }

    // Initialize the first ant
    struct ant langton_ant = { ant1_row, ant1_col, UP };

    // Initialize the second ant
    struct ant random_ant = { ant2_row, ant2_col, DOWN };

    srand(time(NULL)); // Seed the random number generator with the current time

    int wait_time = 1; //default wait time between each step is 1 second
    if (argc > 1) {
        wait_time = atof(argv[1]);
    }

    // Run the simulation
    for (int step = 0; step < num_steps; step++) {
        // Update the direction of the Langton ant based on the color of the cell
        int langton_ant_row = langton_ant.row;
        int langton_ant_col = langton_ant.col;

     if (map[langton_ant_row][langton_ant_col] == '*') {
            langton_ant.dir = (langton_ant.dir + 1) % 4;
        } else {
            langton_ant.dir = (langton_ant.dir - 1 + 4) % 4;
        }

     // Update the color of the cell and move the Langton ant
     if (map[langton_ant_row][langton_ant_col] == '*') {
         map[langton_ant_row][langton_ant_col] = ' ';
     } else {
          map[langton_ant_row][langton_ant_col] = '*';
      }
        if (langton_ant.dir == UP) {
            langton_ant.row--;
        } else if (langton_ant.dir == RIGHT) {
            langton_ant.col++;
        } else if (langton_ant.dir == LEFT) {
            langton_ant.col--;
        } else if (langton_ant.dir == DOWN) {
            langton_ant.row++;
        }

        // Update the direction of the random ant based on a random number
        int random_number = rand() % 4;
        if (random_number == 0) {
           random_ant.dir = UP;
        } else if (random_number == 1) {
            random_ant.dir = RIGHT;
        } else if (random_number == 2) {
            random_ant.dir = LEFT;
        } else if (random_number == 3) {
            random_ant.dir = DOWN;
        }

        // Move the random ant
        if (random_ant.dir == UP) {
            random_ant.row--;
        } else if (random_ant.dir == RIGHT) {
            random_ant.col++;
    } else if (random_ant.dir == LEFT) {
            random_ant.col--;
        } else if (random_ant.dir == DOWN) {
            random_ant.row++;
        }

        // Print the current state of the map
        print_map(map, rows, cols, langton_ant, random_ant);

        // Wait for some time
    sleep(wait_time);
    }

    // Free the memory used by the map
    for (int i = 0; i < rows; i++) {
            free(map[i]);
    }
    free(map);

    return 0;
}


What I have tried:

When I run my program, I want the ants to be able to move at any speed - be it less than one second or more - for the number of steps its given. When I run the program, it works well for any wait time that is one second or more. But when I try and run the program at a wait time of less than a second, the program instantly ends and prints a segmentation fault (core dumped) message.

Edit: I was able to figure out the previous issue I was having. My new question is; how to check for out-of-bounds access when updating the ants' position and direction? Because this is giving me segmentation fault error.
Posted
Updated 17-Apr-23 9:56am
v4
Comments
0x01AA 17-Apr-23 13:24pm    
.

This is your third post of the same question, and you are still making the same mistake that I pointed out in the first one. You have the following code at the beginning:
C++
int waiting_time = atof(argv[1]); // get waiting time from command line argument

Then further down you have:
C++
int wait_time = 1; //default wait time between each step is 1 second
if (argc > 1) {
    wait_time = atof(argv[1]);
}

But ib both cases you declare the variables as int types, so calling atof makes no sense. And since the sleep function only accepts integer values there is no point in trying to capture the value as a float. So change the first line just after main to:
C++
int wait_time = atoi(argv[1]); // get wait_ime from command line argument

And remove the other lines where you try to capture it a second time.
 
Share this answer
 
Comments
0x01AA 17-Apr-23 13:09pm    
Looks like on linux sleep accepts float values: sleep() Function in C - GeeksforGeeks[^]
DosNecro 17-Apr-23 13:41pm    
I tried your method, however, it didn't give me a fix. Instead, I used errno and usleep to help fix the issue, and it worked. Though I have to input the time in as milliseconds instead of seconds.
Richard MacCutchan 18-Apr-23 3:55am    
Seconds multiplied by 1000 equals milliseconds. Howver, as you can see from sleep(3) - Linux manual page[^], the sleep function takes a value in seconds.
DosNecro 17-Apr-23 13:56pm    
Any chance you know how to check for out-of-bounds access when updating the ants' position and direction? Cause this is giving me segmentation fault errors.
Richard MacCutchan 18-Apr-23 3:56am    
Not without more information. Where does the error occur and what variable is causing it?
You might actually use usleep, however it cannot handle waiting times greater than one second (see the relative man page). An alternative could be nanosleep[^], try
C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("Error: Invalid number of arguments\n");
        return 1;
    }

    double waiting_time = atof(argv[1]); // get waiting time from command line argument
    int num_steps = atoi(argv[2]); // get number of steps from command line argument

    if (waiting_time < 0.005)
      waiting_time = 0.005;
    else if (waiting_time > 10.0)
      waiting_time = 10.0;

    struct timespec wt;

    wt.tv_sec = (time_t) waiting_time; // getting the integer part of the waiting time
    wt.tv_nsec = (long) ( (waiting_time - wt.tv_sec) * 1E9); // getting the fractional part of the wating time, converting it to nanoseconds

    for ( int step = 0; step < num_steps; ++step)
    {
      nanosleep(&wt, NULL);
    }
  return 0;
}


Note that sleeping for very small intervals is not accurate on (no-real-time) operative systems.
 
Share this answer
 
v2
Comments
DosNecro 17-Apr-23 14:09pm    
Thanks, but I was able to use errno and usleep to fix the issue. Any chance you know how to check for out-of-bounds access when updating the ants' position and direction? Cause this is giving me segmentation fault errors.
0x01AA 17-Apr-23 14:15pm    
Keep in mind usleep is deprecated
merano99 17-Apr-23 15:27pm    
The usleep() function causes an EINVAL error if usec is greater than or equal to 1000000, and nanosleep() also provides a higher resolution. So it is actually clear which one should be used.
k5054 17-Apr-23 15:37pm    
The usleep() man page states that POSIX.1-2001 declares this function obsolete; use nanosleep(2) instead..
Quote:
My new question is; how to check for out-of-bounds access

I don't think it will help this time because as Richard said this is the third post with almost the same questions. As I told you here
https://www.codeproject.com/Answers/5359105/How-to-get-command-line-and-file-input-to-work-pro
some values are out of range. There are accesses with negative values and probably also too large values. How would it be if you think about whether you should always subtract something:
C
if (langton_ant.dir == UP) {
    langton_ant.row--;
 
Share this answer
 
Seems to work fine for me. What is in your input.txt, and what command line arguments are you using?
But maybe now is a good time to get acquainted with the debugger (gdb). Make sure you've compiled a debug version (gcc flag -g, -g3 or -ggdb. your session will go something like
gcc -Wall -Wextra -ggdb ants.c -o ants
gdb ants
r 2 10
.. program halts on SegFault...
bt
... gdb shows you where your program failed, and you can then inspect various values

You may need to take a look at gdb tutorial such as this one: gdb tutorial[^]
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900