15 Commits

Author SHA1 Message Date
43df23e1e2 update test cases 3 and 5 2023-09-30 11:36:57 +08:00
3b64053e37 last commit of silly ai 2023-09-30 10:48:06 +08:00
5c03a6b327 last try 2023-09-30 01:26:27 +08:00
ad0f8c92fa finish today's work 2023-09-30 01:22:32 +08:00
9f774000c5 finish modify 2023-09-30 01:20:10 +08:00
dc2c83cb37 adjust 2023-09-30 01:00:53 +08:00
fec72b8e14 adjust 2023-09-30 00:59:56 +08:00
5e150ec020 finish writing 2023-09-30 00:50:40 +08:00
9d390437d5 move all data process function into one file 2023-09-29 23:57:51 +08:00
37eeba23fb merge miniz to one file 2023-09-29 23:48:00 +08:00
acf85ab7d9 remove half unnecessart data 2023-09-29 23:45:04 +08:00
53913a8f44 trying to lessen the space miniz taken 2023-09-29 23:30:14 +08:00
3f60201c55 base64 and zip passed test 2023-09-29 22:53:11 +08:00
4f7d11b41b format generator 2023-09-29 22:22:51 +08:00
a6bb55639e add zip 2023-09-29 22:04:30 +08:00
8 changed files with 9345 additions and 4 deletions

View File

@ -7,4 +7,5 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(server main.cpp) add_executable(server main.cpp)
add_executable(client advanced.cpp) # For advanced task add_executable(client advanced.cpp) # For advanced task
add_executable(tablegenerator tablegenerator.cpp)

View File

@ -72,12 +72,46 @@ X.X.X..X...X..X.....
.X.X...............X .X.X...............X
XXX..X....X.XX..X... XXX..X....X.XX..X...
.X...X.XX........X.X .X...X.XX........X.X
0 10""" 0 10""",
"""10 10
.XX.......
...X...XX.
..........
...X......
.X......X.
..X....X..
XX....X...
..X...X...
..X.X.X.X.
....X.....
3 6""",
"""20 20
X...........X.......
..XX.............X.X
.X......X.........X.
....X.X...X...X.....
....X.X.........X...
X.XX...........X.X..
...X.............XX.
...XX...X..X..X.X...
...X.X...X...X......
.............XX.X...
.X............X.....
.X..X.........X....X
X.X.X..X...X..X.....
.X....X.X......X....
...X.........X..X...
...X.X...X..........
..X.XX.X......XXXX..
.X.X...............X
XXX..X....X.XX..X...
.X...X.XX........X.X
4 12"""
] ]
mine_rate=0.133 mine_rate=0.133
total_round=0 total_round=0
win_round=0 win_round=0
for i in range(0,10): for i in range(0,1):
for data in built_in_test_cases: for data in built_in_test_cases:
fn=open("tmp/test.in","w") fn=open("tmp/test.in","w")
fn.write(data) fn.write(data)

View File

@ -10,9 +10,111 @@
#include <queue> #include <queue>
#include <random> #include <random>
#include <set> #include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "data.h"
#include "zb64.h"
namespace DataLoad {
typedef long long LL;
const int buf_size = 4412555 * 4;
unsigned char buf[buf_size], data[buf_size];
bool already_have[14348907];
// std::unordered_map<LL,unsigned char> visible_to_probability;
int rid[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2};
int cid[15] = {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
class HashTable {
static const int buf_size = 44348907;
struct Node {
LL key;
unsigned char value;
Node *next;
// Node(LL k, unsigned char v) : key(k), value(v), next(nullptr) {}
};
Node *table[buf_size], mem[buf_size], *cur = mem;
public:
HashTable() {
for (int i = 0; i < buf_size; i++) table[i] = nullptr;
}
~HashTable() {}
unsigned char &operator[](LL key) {
int index = key % buf_size;
Node *p = table[index];
while (p) {
if (p->key == key) return p->value;
p = p->next;
}
p = cur++;
p->key = key;
p->next = table[index];
table[index] = p;
return p->value;
}
bool have(LL key) {
int index = key % buf_size;
Node *p = table[index];
while (p) {
if (p->key == key) return true;
p = p->next;
}
return false;
}
} visible_to_probability;
} // namespace DataLoad
void LoadData() {
using namespace DataLoad;
size_t raw_length = base64_decode(pre_calc_prob, buf, buf_size);
size_t data_length = decompressData(buf, raw_length, data, buf_size);
// std::cout<<"decompress finished.\n"<<std::endl;
// already_have.rehash(4412555);
// visible_to_probability.rehash(4412555);
const LL raw_line_base = 243;
const LL vis_line_base = 100000;
int cnt = 0;
for (int status = 0; status < 14348907; status++) {
LL inverse_status =
(status % raw_line_base) * raw_line_base * raw_line_base +
((status / raw_line_base) % raw_line_base) * raw_line_base +
(status / (raw_line_base * raw_line_base));
if (already_have[inverse_status]) continue;
// assert(already_have.find(status) == already_have.end());
already_have[status] = true;
int inner_mp[3][5] = {0}, visible_map[3][5];
LL status_tmp = status;
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
inner_mp[row][col] = (status_tmp % 3); // uncode the inner_status
status_tmp /= 3;
}
for (int row = 0; row < 3; row++)
for (int col = 0; col < 5; col++) {
if (inner_mp[row][col] == 0 || inner_mp[row][col] == 1) {
visible_map[row][col] = 9; // 9 means unshown to player
} else {
int mcnt = 0;
const int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1},
dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
for (int i = 0; i < 8; i++) {
int nr = row + dx[i], nc = col + dy[i];
if (nr < 0 || nr >= 3 || nc < 0 || nc >= 5) continue;
mcnt += (inner_mp[nr][nc] == 0 ? 1 : 0);
}
visible_map[row][col] = mcnt;
}
}
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
visible_status = visible_status * 10 + visible_map[row][col];
}
visible_to_probability[visible_status] = data[cnt++];
}
// std::cout<<"Load data finished.\n"<<std::endl;
}
extern int rows; // The count of rows of the game map extern int rows; // The count of rows of the game map
extern int columns; // The count of columns of the game map extern int columns; // The count of columns of the game map
@ -38,6 +140,7 @@ void Execute(int row, int column);
* map and the first step taken by the server (see README). * map and the first step taken by the server (see README).
*/ */
void InitGame() { void InitGame() {
LoadData();
int first_row, first_column; int first_row, first_column;
std::cin >> first_row >> first_column; std::cin >> first_row >> first_column;
Execute(first_row, first_column); Execute(first_row, first_column);
@ -493,6 +596,135 @@ std::pair<int, int> SimpleGuess() {
} }
return best_guess; return best_guess;
} }
double EstimateProb(std::pair<int, int> pos, double default_p = 0.06) {
if (pos.first == 0 || pos.first == rows - 1 || pos.second == 0 ||
pos.second == columns - 1)
return default_p;
std::vector<double> ps;
double res = 0;
typedef long long LL;
const LL raw_line_base = 243;
const LL vis_line_base = 100000;
int rid[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2};
int cid[15] = {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
if (pos.second + 3 <= columns - 1) {
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int x = pos.first + rid[i] - 1, y = pos.second + cid[i] - 1;
if (map_status[x][y] != 2)
visible_status = (visible_status * 10) + 9;
else if (map_status[x][y] == 2)
visible_status = (visible_status * 10) + game_map[x][y] - '0';
}
LL invers_vis_status =
(visible_status % vis_line_base) * vis_line_base * vis_line_base +
((visible_status / vis_line_base) % vis_line_base) * vis_line_base +
visible_status / (vis_line_base * vis_line_base);
if (DataLoad::visible_to_probability.have(visible_status))
ps.push_back(DataLoad::visible_to_probability[visible_status] / 255.0);
if (DataLoad::visible_to_probability.have(invers_vis_status))
ps.push_back(DataLoad::visible_to_probability[invers_vis_status] / 255.0);
}
if (pos.second - 3 >= 0) {
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int x = pos.first + rid[i] - 1, y = pos.second - (cid[i] - 1);
if (map_status[x][y] != 2)
visible_status = (visible_status * 10) + 9;
else if (map_status[x][y] == 2)
visible_status = (visible_status * 10) + game_map[x][y] - '0';
}
LL invers_vis_status =
(visible_status % vis_line_base) * vis_line_base * vis_line_base +
((visible_status / vis_line_base) % vis_line_base) * vis_line_base +
visible_status / (vis_line_base * vis_line_base);
if (DataLoad::visible_to_probability.have(visible_status))
ps.push_back(DataLoad::visible_to_probability[visible_status] / 255.0);
if (DataLoad::visible_to_probability.have(invers_vis_status))
ps.push_back(DataLoad::visible_to_probability[invers_vis_status] / 255.0);
}
if (pos.first + 3 <= rows - 1) {
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int x = pos.first + cid[i] - 1, y = pos.second + rid[i] - 1;
if (map_status[x][y] != 2)
visible_status = (visible_status * 10) + 9;
else if (map_status[x][y] == 2)
visible_status = (visible_status * 10) + game_map[x][y] - '0';
}
LL invers_vis_status =
(visible_status % vis_line_base) * vis_line_base * vis_line_base +
((visible_status / vis_line_base) % vis_line_base) * vis_line_base +
visible_status / (vis_line_base * vis_line_base);
if (DataLoad::visible_to_probability.have(visible_status))
ps.push_back(DataLoad::visible_to_probability[visible_status] / 255.0);
if (DataLoad::visible_to_probability.have(invers_vis_status))
ps.push_back(DataLoad::visible_to_probability[invers_vis_status] / 255.0);
}
if (pos.first - 3 >= 0) {
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int x = pos.first - (cid[i] - 1), y = pos.second + rid[i] - 1;
if (map_status[x][y] != 2)
visible_status = (visible_status * 10) + 9;
else if (map_status[x][y] == 2)
visible_status = (visible_status * 10) + game_map[x][y] - '0';
}
LL invers_vis_status =
(visible_status % vis_line_base) * vis_line_base * vis_line_base +
((visible_status / vis_line_base) % vis_line_base) * vis_line_base +
visible_status / (vis_line_base * vis_line_base);
if (DataLoad::visible_to_probability.have(visible_status))
ps.push_back(DataLoad::visible_to_probability[visible_status] / 255.0);
if (DataLoad::visible_to_probability.have(invers_vis_status))
ps.push_back(DataLoad::visible_to_probability[invers_vis_status] / 255.0);
}
// assert(ps.size() > 0);
if(ps.size()==0)
{
;
return default_p;
}
for (int i = 0; i < ps.size(); i++) res += ps[i];
return res / ps.size();
}
/**
* @brief The definition of function GreedyGuess()
*
* @details This function is designed to make a guess when there is no definite
*/
std::pair<int, int> GreedyGuess() {
double default_probability = 0.06;
int total_known = 0, total_known_with_mine = 0;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
if (map_status[i][j] != 0) {
total_known++;
if (map_status[i][j] == -1) total_known_with_mine++;
}
if (total_known > 5)
default_probability = (double)(total_known_with_mine) / (total_known);
std::pair<int, int> res;
bool is_first = true;
double res_prob = 1;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
if (map_status[i][j] == 0) {
if (is_first) {
is_first = false;
res = std::make_pair(i, j);
double res_prob = EstimateProb(res, default_probability);
continue;
}
double this_prob =
EstimateProb(std::make_pair(i, j), default_probability);
if (this_prob < res_prob) {
res = std::make_pair(i, j);
res_prob = this_prob;
}
}
return res;
}
/** /**
* @brief The definition of function MakeBestGuess() * @brief The definition of function MakeBestGuess()
* *
@ -503,7 +735,8 @@ std::pair<int, int> MakeBestGuess() {
using namespace Client; using namespace Client;
// just make a total random guess before a better algorithm is designed // just make a total random guess before a better algorithm is designed
// return TotalRandomGuess(); // return TotalRandomGuess();
return SimpleGuess(); // return SimpleGuess();
return GreedyGuess();
return std::make_pair(0, 0); return std::make_pair(0, 0);
} }
/** /**

1
src/include/data.h Normal file

File diff suppressed because one or more lines are too long

8885
src/include/zb64.h Normal file

File diff suppressed because it is too large Load Diff

153
src/tablegenerator.cpp Normal file
View File

@ -0,0 +1,153 @@
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "zb64.h"
using namespace std;
typedef long long LL;
int rid[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2};
int cid[15] = {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4};
// unordered_map<LL,LL> visible_to_inner;
unordered_map<LL, vector<LL>> visible_to_inner;
unordered_map<LL, LL> inner_to_visible;
vector<LL> valid_visible_status;
unordered_map<LL, double> visible_to_probability;
unordered_set<LL> already_have;
void FindStatus() {
const LL raw_line_base = 243;
const LL vis_line_base = 100000;
for (int status = 0; status < 14348907; status++) {
int inner_mp[3][5] = {0}, visible_map[3][5];
LL status_tmp = status;
LL inverse_status =
(status % raw_line_base) * raw_line_base * raw_line_base +
((status / raw_line_base) % raw_line_base) * raw_line_base +
(status / (raw_line_base * raw_line_base));
if (already_have.find(inverse_status) != already_have.end()) continue;
assert(already_have.find(status) == already_have.end());
already_have.insert(status);
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
inner_mp[row][col] = (status_tmp % 3); // uncode the inner_status
status_tmp /= 3;
}
for (int row = 0; row < 3; row++)
for (int col = 0; col < 5; col++) {
if (inner_mp[row][col] == 0 || inner_mp[row][col] == 1) {
visible_map[row][col] = 9; // 9 means unshown to player
} else {
int mcnt = 0;
const int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1},
dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
for (int i = 0; i < 8; i++) {
int nr = row + dx[i], nc = col + dy[i];
if (nr < 0 || nr >= 3 || nc < 0 || nc >= 5) continue;
mcnt += (inner_mp[nr][nc] == 0 ? 1 : 0);
}
visible_map[row][col] = mcnt;
}
}
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
visible_status = visible_status * 10 + visible_map[row][col];
}
inner_to_visible[status] = visible_status;
visible_to_inner[visible_status].push_back(status);
}
}
const int buf_size = 4412555 * 4;
unsigned char buf[buf_size], buf2[buf_size], buf3[buf_size], buf4[buf_size];
int bcnt = 0;
void CalculateProbability() {
const LL raw_line_base = 243;
const LL vis_line_base = 100000;
already_have.clear();
for (int status = 0; status < 14348907; status++) {
int inner_mp[3][5] = {0}, visible_map[3][5];
LL status_tmp = status;
LL inverse_status =
(status % raw_line_base) * raw_line_base * raw_line_base +
((status / raw_line_base) % raw_line_base) * raw_line_base +
(status / (raw_line_base * raw_line_base));
if (already_have.find(inverse_status) != already_have.end()) continue;
// assert(already_have.find(status) == already_have.end());
already_have.insert(status);
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
inner_mp[row][col] = (status_tmp % 3); // uncode the inner_status
status_tmp /= 3;
}
for (int row = 0; row < 3; row++)
for (int col = 0; col < 5; col++) {
if (inner_mp[row][col] == 0 || inner_mp[row][col] == 1) {
visible_map[row][col] = 9; // 9 means unshown to player
} else {
int mcnt = 0;
const int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1},
dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
for (int i = 0; i < 8; i++) {
int nr = row + dx[i], nc = col + dy[i];
if (nr < 0 || nr >= 3 || nc < 0 || nc >= 5) continue;
mcnt += (inner_mp[nr][nc] == 0 ? 1 : 0);
}
visible_map[row][col] = mcnt;
}
}
LL visible_status = 0;
for (int i = 0; i < 15; i++) {
int row = rid[i], col = cid[i];
visible_status = visible_status * 10 + visible_map[row][col];
}
int mine_cnt = 0;
for(int i=0;i<visible_to_inner[visible_status].size();i++){
mine_cnt += ((visible_to_inner[visible_status][i] / 729) % 3 == 0 ? 1 : 0);
}
visible_to_probability[visible_status] = double(mine_cnt) / visible_to_inner[visible_status].size();
buf[bcnt++] = int((double(mine_cnt) / visible_to_inner[visible_status].size()) * 255);
}
// for (auto it = visible_to_inner.begin(); it != visible_to_inner.end(); ++it) {
// assert(it->second.size() > 0);
// int mine_cnt = 0;
// for (int i = 0; i < it->second.size(); i++) {
// mine_cnt += ((it->second[i] / 729) % 3 == 0 ? 1 : 0);
// }
// visible_to_probability[it->first] = double(mine_cnt) / it->second.size();
// buf[bcnt++] = int((double(mine_cnt) / it->second.size()) * 255);
// }
}
int main() {
FindStatus();
cout << visible_to_inner.size() << endl;
CalculateProbability();
freopen("tmp/data.txt", "w", stdout);
string raw = base64_encode(buf, bcnt, false);
cout << raw << endl;
freopen("tmp/compressed.txt", "w", stdout);
// buf is the raw data;
// buf2 is the compressed data;
// compressed is the base64-encoded form of buf2;
// buf3 is the base64_decoded form of compressed,it should be the same as
// buf2; buf4 is the decompressed data, it should be the same as buf;
size_t real_size = compressData(buf, bcnt, buf2, buf_size);
string compressed = base64_encode(buf2, real_size, false);
cout << compressed << endl;
// check the correctness of the compression and base64 encoding
// freopen("tmp/decompressed.txt", "w", stdout);
size_t real_size3 = base64_decode(compressed, buf3, buf_size, false);
for (int i = 0; i < real_size3; i++) assert(buf3[i] == buf2[i]);
size_t real_size4 = decompressData(buf3, real_size3, buf4, buf_size);
for (int i = 0; i < real_size4; i++) assert(buf4[i] == buf[i]);
return 0;
}

View File

@ -0,0 +1,12 @@
10 10
.XX.......
...X...XX.
..........
...X......
.X......X.
..X....X..
XX....X...
..X...X...
..X.X.X.X.
....X.....
3 6

View File

@ -0,0 +1,22 @@
20 20
X...........X.......
..XX.............X.X
.X......X.........X.
....X.X...X...X.....
....X.X.........X...
X.XX...........X.X..
...X.............XX.
...XX...X..X..X.X...
...X.X...X...X......
.............XX.X...
.X............X.....
.X..X.........X....X
X.X.X..X...X..X.....
.X....X.X......X....
...X.........X..X...
...X.X...X..........
..X.XX.X......XXXX..
.X.X...............X
XXX..X....X.XX..X...
.X...X.XX........X.X
4 12