a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
1#include <iostream>
2#include <vector>
3#include <algorithm>
4#include <numeric>
5#include <cstdlib>
6#include <ctime>
7
8using namespace std;
9
10const int BOARDSIZE = 10;
11
12// Simple coordinate parsing
13pair<int, int> parseMove(const string& move) {
14 int row = move[0] - 'A';
15 int col = stoi(move.substr(1)) - 1;
16 return {row, col};
17}
18
19int runSingleGame() {
20 char board[BOARDSIZE][BOARDSIZE];
21
22 // Initialize board
23 for (int i = 0; i < BOARDSIZE; i++) {
24 for (int j = 0; j < BOARDSIZE; j++) {
25 board[i][j] = '.';
26 }
27 }
28
29 // Place ships randomly
30 int shipSizes[] = {5, 4, 3, 3, 2};
31 for (int s = 0; s < 5; s++) {
32 bool placed = false;
33 while (!placed) {
34 int row = rand() % BOARDSIZE;
35 int col = rand() % BOARDSIZE;
36 int orient = rand() % 2;
37
38 bool canPlace = true;
39 for (int i = 0; i < shipSizes[s]; i++) {
40 int r = row + (orient == 1 ? i : 0);
41 int c = col + (orient == 0 ? i : 0);
42 if (r >= BOARDSIZE || c >= BOARDSIZE || board[r][c] == 'S') {
43 canPlace = false;
44 break;
45 }
46 }
47
48 if (canPlace) {
49 for (int i = 0; i < shipSizes[s]; i++) {
50 int r = row + (orient == 1 ? i : 0);
51 int c = col + (orient == 0 ? i : 0);
52 board[r][c] = 'S';
53 }
54 placed = true;
55 }
56 }
57 }
58
59 // Random shooting
60 vector<pair<int,int>> allCells;
61 for (int i = 0; i < BOARDSIZE; i++) {
62 for (int j = 0; j < BOARDSIZE; j++) {
63 allCells.push_back({i, j});
64 }
65 }
66
67 // Shuffle cells
68 for (int i = allCells.size() - 1; i > 0; i--) {
69 int j = rand() % (i + 1);
70 swap(allCells[i], allCells[j]);
71 }
72
73 // Shoot until all ships found
74 int moves = 0;
75 int shipsRemaining = 17; // 5+4+3+3+2
76
77 for (size_t i = 0; i < allCells.size(); i++) {
78 int row = allCells[i].first;
79 int col = allCells[i].second;
80 moves++;
81 if (board[row][col] == 'S') {
82 shipsRemaining--;
83 if (shipsRemaining == 0) break;
84 }
85 }
86
87 return moves;
88}
89
90int main() {
91 const int numGames = 1000;
92 vector<int> moveCounts;
93
94 srand(time(NULL));
95
96 cout << "Running " << numGames << " games with random AI..." << endl;
97
98 for (int i = 0; i < numGames; i++) {
99 int moves = runSingleGame();
100 moveCounts.push_back(moves);
101 if ((i + 1) % 100 == 0) {
102 cout << "Completed " << (i + 1) << " games..." << endl;
103 }
104 }
105
106 // Calculate statistics
107 sort(moveCounts.begin(), moveCounts.end());
108 int minMoves = moveCounts.front();
109 int maxMoves = moveCounts.back();
110 double avg = accumulate(moveCounts.begin(), moveCounts.end(), 0.0) / moveCounts.size();
111 int median = moveCounts[moveCounts.size() / 2];
112 int p25 = moveCounts[moveCounts.size() / 4];
113 int p75 = moveCounts[3 * moveCounts.size() / 4];
114
115 cout << "\n=== Random AI Statistics (1000 games) ===" << endl;
116 cout << "Min moves: " << minMoves << endl;
117 cout << "25th percentile: " << p25 << endl;
118 cout << "Median moves: " << median << endl;
119 cout << "Average moves: " << avg << endl;
120 cout << "75th percentile: " << p75 << endl;
121 cout << "Max moves: " << maxMoves << endl;
122
123 cout << "\n=== Suggested Stage Thresholds ===" << endl;
124 cout << "Stage 1 (Beginner): >" << p75 << " avg moves (worse than random)" << endl;
125 cout << "Stage 2 (Intermediate): " << static_cast<int>(avg) << "-" << p75 << " avg moves (around random average)" << endl;
126 cout << "Stage 3 (Advanced): " << p25 << "-" << static_cast<int>(avg) << " avg moves (better than random)" << endl;
127 cout << "Stage 4 (Expert): <" << p25 << " avg moves (much better than random)" << endl;
128
129 return 0;
130}