#include #include #include #include #include enum { BOARD_SIZE = 10, }; struct state { char board[BOARD_SIZE][BOARD_SIZE]; int game_over; }; struct position { int x; int y; }; enum orientation { O_VERTICAL, O_HORIZONTAL }; struct boat { enum orientation orientation; /** left upper corner */ struct position position; int length; }; struct position read_position(void); struct boat generate_boat(int length); struct state generate_state(void); void display_state(struct state state); int valid_position(struct position p); /** * Simulates one step of battleship. * * Performs the following steps: * * - apply hit to board * - check sunken ships * - check game over */ void update_state(struct state * state, struct position hit); enum target { T_WATER, T_BOAT, T_COMPLETE_BOAT, }; enum target check_hit(struct state state, struct position hit); int main(void) { srand(time(NULL)); struct state state = generate_state(); while (!state.game_over) { display_state(state); struct position hit = read_position(); /* game logic */ update_state(&state, hit); } } struct position read_position(void) { printf("enter coordinate: "); while (1) { char* line = NULL; size_t size = 0; getline(&line, &size, stdin); fflush(stdout); struct position position; char col; sscanf(line, "%c%d", &col, &position.y); free(line); position.x = tolower(col) - 'a'; if (valid_position(position)) { return position; } puts("invalid input!"); } } struct position random_position(void) { struct position p; p.x = rand() % BOARD_SIZE; p.y = rand() % BOARD_SIZE; return p; } enum orientation random_orientation(void) { return (rand() % 2); } struct boat generate_boat(int length) { struct boat b; b.length = length; b.position = random_position(); b.orientation = random_orientation(); return b; } int valid_position(struct position p) { return (p.x >= 0) && (p.x < BOARD_SIZE) && (p.y >= 0) && (p.y < BOARD_SIZE); } int place_boat(struct state * state, struct boat boat, char c) { int dx = (boat.orientation == O_VERTICAL) ? 1 : 0; int dy = (boat.orientation == O_HORIZONTAL) ? 1 : 0; struct position curpos = boat.position; for (int i = 0; i < boat.length; ++i) { if (!valid_position(curpos)) return 0; if (state->board[curpos.y][curpos.x] != 0) return 0; if (c) { state->board[curpos.y][curpos.x] = c; } curpos.x += dx; curpos.y += dy; } return 1; } /* const int BOAT_LENGTHS[] = { 5, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; */ const int BOAT_LENGTHS[] = {1}; struct state generate_state(void) { struct state state; memset(state.board, 0, BOARD_SIZE*BOARD_SIZE); state.game_over = 0; // generate some boats char boat_char = 'A'; for (size_t i = 0; i < sizeof(BOAT_LENGTHS) / sizeof(BOAT_LENGTHS[0]); ++i) { int length = BOAT_LENGTHS[i]; struct boat boat; do { boat = generate_boat(length); } while(!place_boat(&state, boat, '\0')); place_boat(&state, boat, boat_char); boat_char++; } return state; } void display_state(struct state state) { for (int y = 0; y < BOARD_SIZE; ++y) { for (int x = 0; x < BOARD_SIZE; ++x) { if (state.board[y][x]) { printf("%c", state.board[y][x]); } else { printf("~"); } } printf("\n"); } puts("---"); } enum target check_hit(struct state state, struct position pos) { char ship = state.board[pos.y][pos.x]; // check if we hit anything if (ship == 0) return T_WATER; ship = toupper(ship); int count = 0; for (int y = 0; y < BOARD_SIZE; ++y) { for (int x = 0; x < BOARD_SIZE; ++x) { if (state.board[y][x] == ship) { count += 1; } } } return (count > 1) ? T_BOAT : T_COMPLETE_BOAT; } void sink_ship(struct state * state, struct position pos) { char ship = state->board[pos.y][pos.x]; for (int x = 0; x < BOARD_SIZE; ++x) { for (int y = 0; y < BOARD_SIZE; ++y) { if (ship == toupper(state->board[y][x])) { state->board[y][x] = '#'; } } } } void update_state(struct state * state, struct position pos) { enum target target = check_hit(*state, pos); // update board switch (target) { case T_BOAT: state->board[pos.y][pos.x] = tolower(state->board[pos.y][pos.x]); break; case T_COMPLETE_BOAT: { sink_ship(state, pos); break; } default: state->board[pos.y][pos.x] = '*'; break; } // check for game over int letter_count = 0; for (int x = 0; x < BOARD_SIZE; ++x) { for (int y = 0; y < BOARD_SIZE; ++y) { if (isalpha(state->board[pos.y][pos.x])) { letter_count += 1; } } } state->game_over = (letter_count == 0); }