4
\$\begingroup\$

I am creating a KotH (King of the Hill) challenge for Programming Puzzles and Code Golf. Other site users will write programs that play Texplode (a version of this game on a square grid). The program works, but I don't think it's anywhere near perfect; I don't often publish C programs so I rarely get any critique on them.

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

bool move(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum, int movepos);
bool hascounters(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum);
void writegrid(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum, FILE *file);
bool readinput(FILE *file, int *movepos);
void printoutput(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize]);

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Texplode, by wizzwizz4.\n");
        printf("Based on Hexplode.\n");
        printf("The first argument is the board size.\n");
        printf("The second argument is the number of players.\n");
        printf("The 2n+1th argument is the nth player's input file.\n");
        printf("The 2n+2th argument is the nth player's output file.\n");
        printf("Human-readable ANSI art will be printed to STDOUT.\n");
        return 0;
    }

    int boardsize = atoi(argv[1]);
    int playercount = atoi(argv[2]);
    if (argc < (2 * playercount + 3)) {
        printf("You promised more players than you gave me.\n");
    }
    FILE *playerinv[playercount];
    FILE *playeroutv[playercount];
    for (int i = 0; i < playercount; i++) {
        playerinv[i] = fopen(argv[2 * i + 3], "r");
        playeroutv[i] = fopen(argv[2 * i + 4], "w");
    }

    int board[boardsize * boardsize];
    memset(board, 0, sizeof(board));
    int boardown[boardsize * boardsize];

    bool stillplaying[playercount];
    memset(stillplaying, true, sizeof(stillplaying));
    bool playoverride = true;
    int numplaying = playercount;
    while (1) {
        if (numplaying <= 1) {
            break;
        }
        for (int i = 0; i < playercount; i++) {
            if (stillplaying[i] || playoverride) {
                writegrid(boardsize, board, boardown, i, playeroutv[i]);

                int movepos = 0;
                if (!readinput(playerinv[i], &movepos)) {
                    printf("Error! :-S\n");
                }
                move(boardsize, board, boardown, i, movepos);

                numplaying = 0;
                for (int j = 0; j < playercount; j++) {
                    if (hascounters(boardsize, board, boardown, j)) {
                        numplaying += 1;
                        stillplaying[j] = true;
                    } else {
                        stillplaying[j] = false;
                    }
                }
            }
            printoutput(boardsize, board, boardown);
        }
        playoverride = false;
    }
    printf("Game over.\n");
}

bool move(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum, int movepos) {
    if (movepos >= boardsize * boardsize) {
        return false;
    }
    if (board[movepos] == 0) {
        board[movepos] = 1;
        boardown[movepos] = playernum;
        return true;
    }
    if (boardown[movepos] == playernum) {
        board[movepos] += 1;

        /* Cascade */
        bool notdone = true;
        while (notdone) {
            notdone = false;
            for (int i = 0; i < boardsize * boardsize; i++) {
                int neighbourcount = 4;
                unsigned int neighbours = 0xf;
                if (i / boardsize == 0) {
                    neighbourcount -= 1;
                    neighbours &= ~0x1;
                }
                if (i / boardsize == boardsize - 1) {
                    neighbourcount -= 1;
                    neighbours &= ~0x2;
                }
                if (i % boardsize == 0) {
                    neighbourcount -= 1;
                    neighbours &= ~0x4;
                }
                if (i % boardsize == boardsize - 1) {
                    neighbourcount -= 1;
                    neighbours &= ~0x8;
                }
                if (board[i] >= neighbourcount) {
                    notdone = true;
                    board[i] -= neighbourcount;
                    boardown[i] = playernum;
                    if (neighbours & 0x1) {
                        board[i - boardsize] += 1;
                        boardown[i - boardsize] = playernum;
                    }
                    if (neighbours & 0x2) {
                        board[i + boardsize] += 1;
                        boardown[i + boardsize] = playernum;
                    }
                    if (neighbours & 0x4) {
                        board[i - 1] += 1;
                        boardown[i - 1] = playernum;
                    }
                    if (neighbours & 0x8) {
                        board[i + 1] += 1;
                        boardown[i + 1] = playernum;
                    }
                }
            }
        }
        return true;
    }
    return false;
}

bool hascounters(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum) {
    for (int i = 0; i < boardsize * boardsize; i++) {
        if (board[i] && boardown[i] == playernum) {
            return true;
        }
    }
    return false;
}

void writegrid(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize], int playernum, FILE *file) {
    for (int i = 0; i < boardsize * boardsize; i++) {
        if (board[i] == 0) {
            putc('0', file);
            continue;
        }
        if (boardown[i] == playernum) {
            putc('3' + board[i], file);
        } else {
            putc('0' + board[i], file);
        }
    }
    putc(';', file);
    fflush(file);
}

bool readinput(FILE *file, int *movepos) {
    return (fscanf(file, "%d;", movepos) == 1); /* 1 "%d", one match. */
}

void printoutput(int boardsize, int board[boardsize * boardsize], int boardown[boardsize * boardsize]) {
    printf("\x1B[1;1H");
    for (int x = 0, i = 0; x < boardsize; x += 1) {
        for (; i < (x + 1) * boardsize; i++) {
            if (board[i]) {
                printf("\x1B[%dm%d", boardown[i] + 30, board[i]);
            } else {
                printf("\x1B[m ");
            }
        }
        printf("\n");
    }
}

I also have a basic UI program that I used for testing on Windows, where I don't have the luxury of using /dev/ttyn files. I know that this is not well-written, but I am providing it so that people have a way to test any changes that they make.

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>

char * getline(void);

int main(int argc, char* argv[]) {
    /* "\\.\pipe\" pipename */
    HANDLE pipein = CreateNamedPipe(
        argv[1],
        PIPE_ACCESS_INBOUND,
        PIPE_TYPE_BYTE,
        PIPE_UNLIMITED_INSTANCES,
        0, /* Out buffer */
        256, /* In buffer */
        0, /* Default wait timeout */
        NULL
    );
    HANDLE pipeout = CreateNamedPipe(
        argv[2],
        PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_BYTE,
        PIPE_UNLIMITED_INSTANCES,
        256, /* Out buffer */
        0, /* In buffer */
        0, /* Default wait timeout */
        NULL
    );
    while (1) {
        if (_kbhit()) { /* Keyboard hit */
            char* input = getline();
            WriteFile(
                pipeout,
                input,
                strlen(input),
                NULL,
                NULL
            );
            free(input);
        }

        DWORD availbytes = 0;
        PeekNamedPipe(
            pipein,
            NULL,
            0,
            NULL,
            &availbytes,
            NULL
        );
        if (availbytes) {
            char byte;
            ReadFile(
                pipein,
                &byte,
                1,
                NULL,
                NULL
            );
            printf("%c", byte);
        }
    }
}

/* https://stackoverflow.com/a/314422/5223757 */
char * getline(void) {
    char * line = malloc(100), * linep = line;
    size_t lenmax = 100, len = lenmax;
    int c;

    if(line == NULL)
        return NULL;

    for(;;) {
        c = fgetc(stdin);
        if(c == EOF)
            break;

        if(--len == 0) {
            len = lenmax;
            char * linen = realloc(linep, lenmax *= 2);

            if(linen == NULL) {
                free(linep);
                return NULL;
            }
            line = linen + (line - linep);
            linep = linen;
        }

        if((*line++ = c) == '\n')
            break;
    }
    *line = '\0';
    return linep;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You shouldn't assume that people here know what KotH stands for. \$\endgroup\$ – mbomb007 Jul 26 '17 at 18:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.