Thread: Multi-Array Problem: Random Walk of Alphabet on 10x10 Matrix (Beginner)

  1. #1
    Registered User
    Join Date
    Jan 2019
    Posts
    15

    Multi-Array Problem: Random Walk of Alphabet on 10x10 Matrix (Beginner)

    Hi All,

    Another beginner question. I am to write a "random walk" program of the English alphabet (A thru Z) on a 10x10 matrix. While I think I have a solution, it could be cleaner.

    Any suggestions on how to tighten this code would be appreciated, as I am still learning about arrays.

    Thanks for your help!

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    
    #define N 10
    #define TRUE 1
    #define FALSE 0
    
    
    int main() {
        char ch = 'A', mat[N][N] = {
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, 
    {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}};    
    
        int direction, zero = 0, one = 0, two = 0, three = 0, row = 0, col = 0;
      
        srand((unsigned) time(NULL));
        
        mat[row][col] = ch;                                                         
    
    
        ch++;
    
    
        while (ch > 'A' && ch <= 'Z'){              
         
            if (zero == TRUE && one == TRUE && two == TRUE && three == TRUE)        
                break;                                                        
    
    
        direction = rand() % 4;                        
        
            switch (direction) {
                case 0:
                    if (zero == TRUE)
                        break;
                    
                    zero = TRUE;                                          
                    
                    if (row < N)
                row = row + 1;                                
                    else
                        break;
                    
                    if(mat[row][col] == '.'){
                        mat[row][col] = ch;
                        ch++;
                        zero = one = two = three = FALSE;          
                   
                        break;
                    }
                    else {
                        row = row -1;
                    
                    break;
                    }
                    
                case 1:
                    if (one == TRUE)
                        break;
    
    
                    one = TRUE;           
                    
                    if (row > 0)
                row = row - 1;                                
                    else
                        break;
                    if(mat[row][col] == '.'){
                        mat[row][col] = ch;
                        ch++;
                        zero = one = two = three = FALSE;                  
                   
                        break;
                    }
                    else {
                        row = row + 1;                                             
                    break;                                                         
                    }
                    
                case 2:
                    if (two == TRUE)
                        break;
    
    
                    two = TRUE;         
                          
                    if (col > 0)
                col = col - 1;                                        
                    else
                        break;
                    if(mat[row][col] == '.'){
                        mat[row][col] = ch;
                        ch++;
                        zero = one = two = three = FALSE;     
                        break;
                    }
                    else{
                        col = col + 1;
                    break;
                    }
               
                case 3:
                    if (three == TRUE)
                        break;
    
    
                    three = TRUE;                                                   
                    
                    if (col < N)
                        col = col + 1;                                            
                    else
                        break;
                    if(mat[row][col] == '.'){
                        mat[row][col] = ch;
                        ch++;
                        zero = one = two = three = FALSE;                          
                       
                        break;
                    }
                    else{
                        col = col - 1;                                             
                        break;                                                      
                    }
    
    
            }
           
            }
        
        printf ("\n\n");
        for (int row = 0; row < N; row++) {
            for (int col = 0; col < N; col++){
                printf("%c ", mat[row][col]);
            }
            printf("\n");                                                         
        }
    
    
        printf("\n\n\n");
        return 0;
    }
    Last edited by Salem; 01-11-2019 at 12:42 AM. Reason: Wrap long line of code

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    I think you need to start learning about writing your own functions.
    100+ lines of code in main, which is the result of lots of ctrl-c / ctrl-v (copy and paste) is a bad place to be.

    Well not that it's necessarily bad, but you need to examine the differences between the two copies after you've done an edit.
    - The original block of code becomes a function.
    - The edits you made become parameters to that function.

    So that where you originally had two near identical copies of the code, you now have one parametrised function, and two function calls with parameters.

    Another problem with copy/paste code is that if you want to make it do something different, aside from the actual time and effort in doing the changes, is making sure you make the change in ALL the copies.

    Anyway, some code.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define N 10
    
    // So you can change N without editing an array initialiser.
    void init(char mat[N][N]) {
        for ( int r = 0 ; r < N ; r++ ) {
            for ( int c = 0 ; c < N ; c++ ) {
                mat[r][c] = '.';
            }
        }
    }
    
    void print(char mat[N][N]) {
        for ( int r = 0 ; r < N ; r++ ) {
            for ( int c = 0 ; c < N ; c++ ) {
                printf("%c ",mat[r][c]);
            }
            printf("\n");
        }
    }
    
    void pickMove(int *dx, int *dy) {
        int direction = rand() % 4;
        switch ( direction ) {
            case 0:
                *dx = 1; *dy = 0;
                break;
            case 1:
                *dx = -1; *dy = 0;
                break;
            case 2:
                *dx = 0; *dy = 1;
                break;
            case 3:
                *dx = 0; *dy = -1;
                break;
        }
    }
    
    int isValidMove(char mat[N][N], int row, int col, int dx, int dy) {
        int r = row + dx, c = col + dy;
        // is out of bounds?
        if ( r < 0 || r >= N ) return 0;
        if ( c < 0 || c >= N ) return 0;
        // is occupied?
        if ( mat[r][c] != '.' ) return 0;
        // is in bounds and unoccupied
        return 1;
    }
    
    int main ( ) {
        char mat[N][N];
        char ch = 'A';
        int row = 0, col = 0;
        init(mat);
        mat[row][col] = ch;
        srand((unsigned) time(NULL));
        int tryagain = 0;
        int maxtries = 5;
        for ( ch = 'B' ; ch <= 'Z' ; ) {
            int dx, dy;
            pickMove(&dx,&dy);
            if ( isValidMove(mat,row,col,dx,dy) ) {
                row += dx;
                col += dy;
                mat[row][col] = ch++;
                tryagain = 0;
            } else if ( tryagain++ == maxtries ) {
                break;
            }
        }
        print(mat);
        return 0;
    }
    Now you can start to play around with various ideas without significantly rewriting the code each time.
    - change the value of N
    - change the persistence of the walker by changing maxtries
    - change pickMove to only pick directions which are usable
    - change isValidMove to perhaps implement pac-man style edge wraparound
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Modern C (C99, which you should be using) has stdbool.h, which defines bool, true, and false.
    When we are testing for true or false, we don't say one == true, we just say one. And to test for false we say !one.
    It looks like zero, one, two, and three would be better named down, up, right, and left, respectively.

    You can use an enum to define symbols for the 0, 1, 2, 3 that you use to represent the directions.

    N is a little short for a global symbol. How about SIZE? And you actually have to check for < SIZE-1 not just < SIZE since the row and col values are allowed to be 0 to SIZE-1. (That's an actual bug in your program.)

    Sticking close to your version, the following is a cleanup.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h> // memset
    #include <time.h>
     
    #define SIZE 10
     
    enum { DOWN, UP, LEFT, RIGHT, NUM_DIRS };
     
    int main() {
        srand(time(NULL));
     
        int row = SIZE / 2, col = SIZE / 2;  // start in the middle
         
        // These are used to tell then we are boxed in.
        // true means we can go in that direction.
        bool down = true, up = true, left = true, right = true;
     
        char mat[SIZE][SIZE];
        memset(mat, '.', SIZE * SIZE);
     
        char ch = 'A';
        mat[row][col] = ch++;
     
        while (ch <= 'Z' && (down || up || left || right)) {
            switch (rand() % NUM_DIRS) {
            case DOWN:
                if (row < SIZE - 1 && mat[row+1][col] == '.') {
                    mat[++row][col] = ch++;
                    down = up = left = right = true;
                }
                else
                    down = false;
                break;
            case UP:
                if (row > 0 && mat[row-1][col] == '.') {
                    mat[--row][col] = ch++;
                    down = up = left = right = true;
                }
                else
                    up = false;
                break;
            case LEFT:
                if (col > 0 && mat[row][col-1] == '.') {
                    mat[row][--col] = ch++;
                    down = up = left = right = true;
                }
                else
                    left = false;
                break;
            case RIGHT:
                if (col < SIZE - 1 && mat[row][col+1] == '.') {
                    mat[row][++col] = ch++;
                    down = up = left = right = true;
                }
                else
                    right = false;
                break;
            }
        }
     
        printf ("\n");
        for (int row = 0; row < SIZE; row++) {
            for (int col = 0; col < SIZE; col++)
                printf("%c ", mat[row][col]);
            printf("\n");
        }
        printf("\n");
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  4. #4
    Registered User Kernelpanic's Avatar
    Join Date
    Sep 2018
    Location
    Berlin
    Posts
    105
    That's another version. But it is always the same arrangement of the alphabet.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define MAT 10
    
    void initMatrix(char matrix[MAT][MAT]);
    
    int main(void)
    {
        system("cls");
        char matrix[MAT][MAT];
        
        initMatrix(matrix);
        
        return(0);
    }
    
    void initMatrix(char matrix[MAT][MAT])
    {
        //Alphabet starts bei 65 decimal.
        int a = 65;  
        for (int i = 1; i <= MAT; i++)
        {
            for (int j = 1; j <= MAT; j++)
            {            
                if (rand() % 4 == 0)
                {                
                    printf("%c ", a++);                
                }
                else
                {
                    printf("%c ", matrix[i][j] = '.');
                }
            }
            printf("\n");
        }
    }
    Multi-Array Problem: Random Walk of Alphabet on 10x10 Matrix (Beginner)-aplhabetmatrix-jpg

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Here's a version that uses four bits in a single unsigned int instead of the four separate boolean variables.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> // memset
    #include <time.h>
     
    #define SIZE 10
    #define EMPTY '.'
     
    enum { DOWN, UP, LEFT, RIGHT, NUM_DIRS };
     
    enum { BLOCK_DOWN=1, BLOCK_UP=2, BLOCK_LEFT=4, BLOCK_RIGHT=8, BLOCKED=15 };
     
    int main() {
        srand(time(NULL));
     
        int row = SIZE / 2, col = SIZE / 2;  // start in the middle
         
        // blocked == BLOCKED when there is no viable direction
        unsigned blocked = 0;
     
        char mat[SIZE][SIZE];
        memset(mat, EMPTY, SIZE * SIZE);
     
        char ch = 'A';
        mat[row][col] = ch++;
     
        while (ch <= 'Z' && blocked != BLOCKED) {
            switch (rand() % NUM_DIRS) {
            case DOWN:
                if (row < SIZE - 1 && mat[row+1][col] == EMPTY) {
                    mat[++row][col] = ch++;
                    blocked = 0;
                }
                else
                    blocked |= BLOCK_DOWN;
                break;
            case UP:
                if (row > 0 && mat[row-1][col] == EMPTY) {
                    mat[--row][col] = ch++;
                    blocked = 0;
                }
                else
                    blocked |= BLOCK_UP;
                break;
            case LEFT:
                if (col > 0 && mat[row][col-1] == EMPTY) {
                    mat[row][--col] = ch++;
                    blocked = 0;
                }
                else
                    blocked |= BLOCK_LEFT;
                break;
            case RIGHT:
                if (col < SIZE - 1 && mat[row][col+1] == EMPTY) {
                    mat[row][++col] = ch++;
                    blocked = 0;
                }
                else
                    blocked |= BLOCK_RIGHT;
                break;
            }
        }
     
        printf ("\n");
        for (int row = 0; row < SIZE; row++) {
            for (int col = 0; col < SIZE; col++)
                printf("%c ", mat[row][col]);
            printf("\n");
        }
        printf("\n");
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User Kernelpanic's Avatar
    Join Date
    Sep 2018
    Location
    Berlin
    Posts
    105
    Now is the arrangement of the alphabet really random. "srand" sets a random starting point for "rand" at every start.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <math.h>
    
    
    #define MAT 10
    
    
    void initMatrix(char matrix[MAT][MAT]);
    
    
    int main(void)
    {
        system("cls");
        char matrix[MAT][MAT];
        
        initMatrix(matrix);
        
        return(0);
    }
    
    
    void initMatrix(char matrix[MAT][MAT])
    {
        //Alphabet starts bei 65 decimal.
        int a = 65;  
        time_t zeit;
        
        //"srand" sets a random starting point for "rand" at every start.
        srand(time(&zeit));
        
        for (int i = 1; i <= MAT; i++)
        {
            for (int j = 1; j <= MAT; j++)
            {            
                if (rand() % 4 == 0)
                {                
                    printf("%c ", a++);                
                }
                else
                {
                    printf("%c ", matrix[i][j] = '.');
                }
            }
            printf("\n");
        }
    }
    Multi-Array Problem: Random Walk of Alphabet on 10x10 Matrix (Beginner)-aplhabetmatrixrandom-jpg

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Quote Originally Posted by Kernelpanic View Post
    Now is the arrangement of the alphabet really random. "srand" sets a random starting point for "rand" at every start.
    The problem you are solving is random too since it's not what the OP is doing.
    And it's kind of dumb to post pictures when a simple copy/paste would do the trick.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  8. #8
    Registered User Kernelpanic's Avatar
    Join Date
    Sep 2018
    Location
    Berlin
    Posts
    105
    Quote Originally Posted by john.c View Post
    The problem you are solving is random too since it's not what the OP is doing.
    And it's kind of dumb to post pictures when a simple copy/paste would do the trick.
    Which trick?

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    The trick of learning English? Forget it.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  10. #10
    Registered User
    Join Date
    Jan 2019
    Posts
    15
    Hi All,
    Thanks so much for your responses! As a self-learner (without any use of videos), your advice has been a godsend. Most importantly, it has motivated me to continue despite some of my struggles with learning C.

    @Salem: Thanks for the suggestions--this will be super useful when I start ploughing through King's "Functions" chapter, which is after "Arrays." Very much appreciate you showing me how to write this differently.

    @john.c: Extremely grateful to you for your style edits and comments (both in this post and my last one)! I've truly learned a lot from your code. As for C99...I've been using King's "C Programming: A Modern Approach." (It's the first edition, and my print copy has a copyright of 1996.) Do you recommend that I get King's latest edition, or will this first edition suffice for simply learning the basics?

    @Kernelpanic: thanks for your suggestions! My random walk is slightly different in scope; namely, each letter is supposed to "walk" to a neighboring cell which means that I cannot skip multiple rows or columns.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 01-09-2019, 02:11 PM
  2. Random Walk
    By hadi0x7c7 in forum C Programming
    Replies: 12
    Last Post: 08-02-2012, 12:32 PM
  3. Program that generates a "random walk" across 10*10 array
    By danieldcc in forum C Programming
    Replies: 37
    Last Post: 07-23-2011, 01:19 AM
  4. Simple Alphabet/Array Problem
    By dolfaniss in forum C Programming
    Replies: 7
    Last Post: 05-06-2011, 04:32 PM
  5. Help with a random walk
    By pxleyes in forum C Programming
    Replies: 11
    Last Post: 02-27-2004, 09:11 PM

Tags for this Thread