-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient_print.h
More file actions
121 lines (103 loc) · 4.01 KB
/
Copy pathclient_print.h
File metadata and controls
121 lines (103 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
// client_print.h
// Covers:
// - status_name() helper to convert status byte to human-readable string
// - print_pawn_row() helper to print the pawn row in a human-readable form
// - try_print_game_state() to parse and print MSG_GAME_STATE responses
// - print_wrong_msg() to parse and print MSG_WRONG_MSG responses
// - print_response() to detect message type and print accordingly
*/
#ifndef CLIENT_PRINT_H
#define CLIENT_PRINT_H
#include "protocol.h"
#include <arpa/inet.h>
#include <cstdio>
#include <cstdint>
#include <cstring>
static const char *status_name(uint8_t s) {
switch (s) {
case 0: return "WAITING_FOR_OPPONENT";
case 1: return "TURN_A";
case 2: return "TURN_B";
case 3: return "WIN_A";
case 4: return "WIN_B";
default: return "(unknown)";
}
}
/// Prints pawn_row in a human-readable form, e.g. [X_X__X].
static void print_pawn_row(const uint8_t *pawn_row, uint8_t max_pawn) {
std::printf(" pawn_row : [");
for (int i = 0; i <= static_cast<int>(max_pawn); ++i) {
const uint8_t byte = pawn_row[i / 8];
const bool present = (byte >> (7 - (i % 8))) & 1u;
std::putchar(present ? 'X' : '_');
}
std::printf("] (pawns 0..%u)\n", static_cast<unsigned>(max_pawn));
}
/// Attempts to parse buf[0..len) as MSG_GAME_STATE and print it.
/// Returns true on success.
static bool try_print_game_state(const uint8_t *buf, size_t len) {
// Minimum: 4 + 4 + 4 + 1 + 1 + 1 = 15 bytes (pawn_row at least 1 byte).
if (len < 15) return false;
size_t off = 0;
uint32_t game_id_net, pa_net, pb_net;
std::memcpy(&game_id_net, buf + off, 4); off += 4;
std::memcpy(&pa_net, buf + off, 4); off += 4;
std::memcpy(&pb_net, buf + off, 4); off += 4;
const uint32_t game_id = ntohl(game_id_net);
const uint32_t player_a = ntohl(pa_net);
const uint32_t player_b = ntohl(pb_net);
const uint8_t status = buf[off++];
const uint8_t max_pawn = buf[off++];
const size_t pr_size = static_cast<size_t>(max_pawn) / 8 + 1;
if (len < off + pr_size) return false; // truncated
// Unexpected extra bytes are silently tolerated (defensive parsing).
const uint8_t *pawn_row = buf + off;
// status 255 means this is actually MSG_WRONG_MSG, not MSG_GAME_STATE.
if (status == 255) return false;
std::printf("=== MSG_GAME_STATE ===\n");
std::printf(" game_id : %u\n", game_id);
std::printf(" player_a : %u\n", player_a);
std::printf(" player_b : %u%s\n", player_b,
player_b == 0 ? " (no player)" : "");
std::printf(" status : %s (%u)\n", status_name(status),
static_cast<unsigned>(status));
std::printf(" max_pawn : %u\n", static_cast<unsigned>(max_pawn));
print_pawn_row(pawn_row, max_pawn);
return true;
}
static void print_wrong_msg(const uint8_t *buf, size_t len) {
// MSG_WRONG_MSG: 12 bytes mirror + status(255) + error_index.
std::printf("=== MSG_WRONG_MSG ===\n");
if (len < WRONG_MSG_SIZE) {
std::printf(" (truncated response, %zu bytes)\n", len);
return;
}
const uint8_t error_index = buf[13];
std::printf(" error at byte index : %u\n",
static_cast<unsigned>(error_index));
std::printf(" first 12 bytes echo : ");
for (size_t i = 0; i < 12; ++i)
std::printf("%02x ", buf[i]);
std::printf("\n");
}
static void print_response(const uint8_t *buf, size_t len) {
if (len < 1) {
std::printf("Received empty response from server.\n");
return;
}
// Peek at byte 12 (if present): if status == 255 -> MSG_WRONG_MSG.
const bool is_wrong = (len >= 13 && buf[12] == 255u);
if (is_wrong) {
print_wrong_msg(buf, len);
return;
}
if (!try_print_game_state(buf, len)) {
std::printf("Received %zu bytes (unrecognised format).\n", len);
std::printf(" hex: ");
for (size_t i = 0; i < len; ++i)
std::printf("%02x ", buf[i]);
std::printf("\n");
}
}
#endif // CLIENT_PRINT_H