feat: complete human-vs-human gameplay end to end

This commit is contained in:
2026-08-29 21:31:21 +03:00
parent e77d9d62c7
commit 650ade2726
7 changed files with 237 additions and 13 deletions
+30 -2
View File
@@ -45,13 +45,36 @@ static char present_cell(cell_t cell, bool reveal_ships) {
return cell == CELL_SHIP && reveal_ships ? '1' : '0';
}
static bool cell_is_sunk(const board_t *board, uint8_t cell_index) {
const uint8_t x = (uint8_t)(cell_index % kBoardWidth);
const uint8_t y = (uint8_t)(cell_index / kBoardWidth);
for (uint8_t index = 0; index < kFleetShipCount; ++index) {
const ship_t *ship = &board->ships[index];
for (uint8_t offset = 0; offset < ship->length; ++offset) {
const uint8_t ship_x = ship->horizontal ? (uint8_t)(ship->x + offset) : ship->x;
const uint8_t ship_y = ship->horizontal ? ship->y : (uint8_t)(ship->y + offset);
if (ship_x == x && ship_y == y) return ship->hits == ship->length;
}
}
return false;
}
static bool append_board(state_writer_t *writer, const board_t *board, bool reveal_ships) {
for (uint8_t index = 0; index < kBoardCellCount; ++index) {
if (!append_character(writer, present_cell(board->cells[index], reveal_ships))) return false;
const char cell = board->cells[index] == CELL_HIT && cell_is_sunk(board, index) ? '4' :
present_cell(board->cells[index], reveal_ships);
if (!append_character(writer, cell)) return false;
}
return true;
}
static bool append_statistics(state_writer_t *writer, const match_statistics_t *statistics) {
return append_character(writer, '[') && append_u32(writer, statistics->shots) &&
append_character(writer, ',') && append_u32(writer, statistics->hits) &&
append_character(writer, ',') && append_u32(writer, statistics->misses) &&
append_character(writer, ',') && append_u32(writer, statistics->ships_sunk) && append_character(writer, ']');
}
static bool write_state(const game_state_t *state, role_t viewer, const cumulative_statistics_t *cumulative,
char *output, size_t output_size, size_t *written) {
if (written != NULL) *written = 0;
@@ -71,7 +94,12 @@ static bool write_state(const game_state_t *state, role_t viewer, const cumulati
!append_text(&writer, "\",\"boards\":[\"") || !append_board(&writer, &state->boards[0], reveal[0]) ||
!append_text(&writer, "\",\"") || !append_board(&writer, &state->boards[1], reveal[1]) ||
!append_text(&writer, "\"],\"wins\":[") || !append_u32(&writer, wins_0) ||
!append_character(&writer, ',') || !append_u32(&writer, wins_1) || !append_text(&writer, "]}")) return false;
!append_character(&writer, ',') || !append_u32(&writer, wins_1) ||
!append_text(&writer, "],\"winner\":") ||
!(state->winner < kPlayerCapacity ? append_u32(&writer, state->winner) : append_text(&writer, "null")) ||
!append_text(&writer, ",\"statistics\":[") || !append_statistics(&writer, &state->statistics[0]) ||
!append_character(&writer, ',') || !append_statistics(&writer, &state->statistics[1]) ||
!append_text(&writer, "]}")) return false;
if (writer.length + 1U > output_size) return false;
writer.data[writer.length] = '\0';
memcpy(output, writer.data, writer.length + 1U);