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
  • 1
    \$\begingroup\$ You shouldn't assume that people here know what KotH stands for. \$\endgroup\$
    – mbomb007
    Jul 26, 2017 at 18:04

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.