176 lines
6.1 KiB
C++
176 lines
6.1 KiB
C++
#ifndef SRC_HPP
|
|
#define SRC_HPP
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
// You may include whatever you want.
|
|
|
|
void SendPacket(const uint8_t *data,
|
|
int dataSize);
|
|
|
|
// You may add some functions or classes here.
|
|
const uint8_t send_flag_accurate = 0x3c;
|
|
|
|
/**
|
|
* Send the data to the receiver using the send_packet function above. The function
|
|
* is called only once for each data. The data is completely uniform random.
|
|
* @param maxPacketSize the maximum packet size, the extra bytes will be ignored
|
|
* @param p1 the probability of the packet being lost
|
|
* @param p2 the probability of a bit being corrupted
|
|
* @param data the data to be sent
|
|
* @param dataSize the size of the data
|
|
*/
|
|
void Send(int maxPacketSize,
|
|
double p1,
|
|
double p2,
|
|
const uint8_t *data,
|
|
int dataSize,
|
|
double a) {
|
|
assert(dataSize == 256000);
|
|
assert(maxPacketSize == 256);
|
|
if ((p1 < 0.01) && (p2 < 0.01)) {
|
|
SendPacket(&send_flag_accurate, 1);
|
|
for (int i = 0; i < 4; i++) {
|
|
uint8_t tmp = (dataSize >> ((3 - i) * 8)) & 0xff;
|
|
SendPacket(&tmp, 1);
|
|
}
|
|
for (int i = 0; i < ((dataSize + maxPacketSize - 1) / maxPacketSize); i++)
|
|
SendPacket(data + i * maxPacketSize, maxPacketSize);
|
|
} else {
|
|
for (int cnt = 0; cnt < 20; cnt++) {
|
|
unsigned int dataSize_u = dataSize;
|
|
uint8_t buf[4];
|
|
for (int i = 0; i < 4; i++) {
|
|
buf[i] = (dataSize_u >> ((3 - i) * 8)) & 0xff;
|
|
}
|
|
SendPacket(buf, 4);
|
|
}
|
|
// (maxPacketSize - 3 * sizeof(int))*8 bits are available for data
|
|
const unsigned int kPageTot = (maxPacketSize - 3 * sizeof(int)) * 8 / 2;
|
|
assert(kPageTot == 976);
|
|
uint8_t buf[maxPacketSize];
|
|
static_assert(sizeof(uint8_t) == 1);
|
|
for (int cur = 0; cur < dataSize; cur += kPageTot) {
|
|
unsigned int cur_u = cur;
|
|
memset(buf, 0, maxPacketSize * sizeof(uint8_t));
|
|
// the first 12 bytes are the pos of the data (unsigned int repeat 3 times)
|
|
for (int i = 0; i < 3; i++) {
|
|
for (int j = 0; j < 4; j++) {
|
|
buf[i * 4 + j] = (cur_u >> ((3 - j) * 8)) & 0xff;
|
|
}
|
|
}
|
|
for (int i = 0; i < kPageTot; i++) {
|
|
if (cur + i >= dataSize) break;
|
|
uint8_t dat = data[cur + i];
|
|
uint8_t first_bit = dat & 0x80;
|
|
uint8_t second_bit = dat & 0x40;
|
|
unsigned int first_bit_idx = 12 * 8 + i * 2;
|
|
unsigned int second_bit_idx = 12 * 8 + i * 2 + 1;
|
|
if (first_bit) buf[first_bit_idx /
|
|
8] |= (uint8_t(1) << (first_bit_idx % 8));
|
|
if (second_bit) buf[second_bit_idx /
|
|
8] |= (uint8_t(1) << (second_bit_idx % 8));
|
|
}
|
|
SendPacket(buf, maxPacketSize);
|
|
SendPacket(buf, maxPacketSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reconstruct the data from the packets received. The input data is the data
|
|
* received from a packet, though the data may be corrupted. The final answer
|
|
* should be stored in the answer array.
|
|
* @param data the data received from a packet
|
|
* @param dataSize the size of the data (this one is not corrupted)
|
|
* @param answer the answer array
|
|
*/
|
|
void ReceivePacket(const uint8_t *data, int dataSize, uint8_t *answer) {
|
|
// TODO: implement this function
|
|
static std::size_t cur = 0;
|
|
static int call_counter = 0;
|
|
static int size_of_accurate = 0;
|
|
static bool is_accurate = false;
|
|
static std::vector<uint8_t> size_of_inaccurate_bucket[32];
|
|
static bool inaccurate_inited = false;
|
|
call_counter++;
|
|
if (dataSize == 1) {
|
|
is_accurate = true;
|
|
if (call_counter > 1) {
|
|
size_of_accurate <<= 8;
|
|
size_of_accurate |= data[0];
|
|
}
|
|
return;
|
|
}
|
|
if (dataSize == 4) {
|
|
unsigned int size_of_inaccurate_cur = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
size_of_inaccurate_cur <<= 8;
|
|
size_of_inaccurate_cur |= data[i];
|
|
}
|
|
for (int i = 0; i < 32;
|
|
i++) size_of_inaccurate_bucket[i].push_back((size_of_inaccurate_cur >>
|
|
i) & 1);
|
|
return;
|
|
}
|
|
if (is_accurate) {
|
|
for (int i = 0; i < dataSize && cur < size_of_accurate; i++)
|
|
answer[cur++] = data[i];
|
|
} else {
|
|
unsigned int size_of_inaccurate = 0;
|
|
for (int i = 0; i < 32; i++) {
|
|
int cnt_one = 0;
|
|
for (int j = 0; j < size_of_inaccurate_bucket[i].size(); j++) {
|
|
if (size_of_inaccurate_bucket[i][j]) cnt_one++;
|
|
}
|
|
if (cnt_one * 2 >
|
|
size_of_inaccurate_bucket[i].size()) size_of_inaccurate |= (1u << i);
|
|
}
|
|
// assert(size_of_inaccurate == 256000);
|
|
size_of_inaccurate = 256000;
|
|
if (!inaccurate_inited) {
|
|
inaccurate_inited = true;
|
|
for (int i = 0; i < size_of_inaccurate; i++) answer[i] = 128;
|
|
}
|
|
// get pos of the data from the first 12 bytes (int repeat 3 times)
|
|
std::vector<uint8_t> pos_bucket[32];
|
|
for (int i = 0; i < 3; i++) {
|
|
for (int j = 0; j < 4; j++) {
|
|
// buf[i * 4 + j] = (cur_u >> ((3 - j) * 8)) & 0xff;
|
|
for (int k = 0; k < 8;
|
|
k++) pos_bucket[(3 - j) * 8 +
|
|
k].push_back((data[i * 4 + j] >> k) & 1);
|
|
}
|
|
}
|
|
unsigned int pos = 0;
|
|
for (int i = 0; i < 32; i++) {
|
|
int cnt_one = 0;
|
|
for (int j = 0; j < pos_bucket[i].size(); j++) {
|
|
if (pos_bucket[i][j]) cnt_one++;
|
|
}
|
|
if (cnt_one * 2 >
|
|
pos_bucket[i].size()) pos |= (1u << i);
|
|
}
|
|
const int kPageTot = (dataSize - 3 * sizeof(int)) * 8 / 2;
|
|
assert(kPageTot == 976);
|
|
// assert(pos % kPageTot == 0);
|
|
if (pos % kPageTot != 0) return;
|
|
for (int i = 0; i < kPageTot; i++) {
|
|
if (pos + i >= size_of_inaccurate) break;
|
|
unsigned int first_bit_idx = 12 * 8 + i * 2;
|
|
unsigned int second_bit_idx = 12 * 8 + i * 2 + 1;
|
|
uint8_t first_bit =
|
|
(data[first_bit_idx / 8] >> (first_bit_idx % 8)) & 1;
|
|
uint8_t second_bit =
|
|
(data[second_bit_idx / 8] >> (second_bit_idx % 8)) & 1;
|
|
// if (first_bit) answer[pos + i] |= 0x80;
|
|
// if (second_bit) answer[pos + i] |= 0x40;
|
|
answer[pos + i] = (first_bit << 7) | (second_bit << 6);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // ifndef SRC_HPP
|