Вам предстоит проэмулировать игру в Морской бой. В рамках данной задачи давайте считать, что игроки честные, корректно расставляют корабли на поле, и никогда не обманывают противника.
Игра в Морской бой проходит на клетчатом поле размером n×m (n строк и m столбцов). Строки занумерованы от 1 до n снизу вверх, столбцы — буквами слева направо. Первые 26 столбцов нумеруются от 'A' до 'Z', а если столбцов больше, то следующие 26 нумеруются от 'AA' до 'AZ'.
У каждого из двух игроков есть свое неизвестное противнику поле, на котором он расставляет корабли. Корабли представляют из себя полосы 1×x или x×1, где x от 1 до L, и расставляются на поле так, что никакие два корабля не соприкасаются по стороне, то есть если две занятые клетки имеют общую сторону, они принадлежат одному кораблю. Соприкосновение по углу разрешается. О количестве кораблей каждого типа игроки договариваются заранее, но строгих ограничений нет.
Вам дана изначальная расстановка кораблей на поле, а также последовательность ходов игроков. В течение хода игрок совершает один «выстрел»: игрок называет клетку противника, после чего противник сообщает вердикт: «мимо», если клетка свободная, «попал», если клетка занята, и «убил», если это было попадание в последнюю клетку соответствующего корабля.
В отличие от стандартных правил,
игроки ходят строго по очереди вне зависимости от вердикта их последнего хода;
у каждого игрока есть «бонус» — каждый игрок может в начале игры пометить k клеток кораблей на своем поле как «усиленные» — тогда по ним потребуется попасть дважды, чтобы стоящий на них корабль считался потопленным.
Проанализируйте запись ходов игры и выведите вердикт каждого хода и информацию о победителе, если игра на каком-то ходу завершается (все корабли одного из игроков потоплены).
Формат входных данных
Каждый тест состоит из нескольких наборов входных данных. В первой строке ввода находится одно целое число t — количество наборов входных данных (1≤t≤50). Далее следует описание наборов входных данных.
Первая строка каждого набора входных данных содержит четыре целых числа n, m, L и k — размеры поля, максимальную длину корабля и число бонусов у каждого игрока (4≤n,m≤50; 1≤L≤10; 1≤k≤30).
Следующие n строк содержат по m символов каждая и задают расстановку кораблей первого игрока. Каждый символ — это либо 'X' (клетка корабля), либо '#' (усиленная клетка корабля), либо '.' (пустая клетка). Затем следуют еще n строк, задающие поле второго игрока в том же формате.
Гарантируется, что расстановка корректная и соответствует всем правилам игры.
Следующая строка содержит одно целое число q — количество ходов в игре (1≤q≤2nm). В i-й из следующих q строк задан ход игрока в формате «FIRE ri ci», где ri — номер строки (в нумерации снизу вверх), а ci — номер столбца, записанный одной или двумя буквами от 'A' до 'Z' в соответствии с описанием нумерации из условия (1≤ri≤n; 'A' ≤ci≤ 'AX').
Формат выходных данных
После каждого хода игры выведите на отдельной строке одну из следующих строк:
«MISSED», если ход был сделан мимо (или данная клетка уже потоплена, то есть по ней было одно попадание в случае обычной клетки корабля или два попадания в случае усиленной);
«HIT», если игрок текущим ходом задел корабль противника;
«SUNK», если игрок текущим ходом потопил корабль противника;
«WIN p», если игрок номер p (1≤p≤2) текущим ходом выиграл.
После того, как какой-то игрок выиграл, если во входных данных остались еще какие-то ходы, их следует проигнорировать и не выводить ничего (до следующего набора входных данных).
Пример:
Ввод:
1
4 4 3 1
....
...X
X...
.X#X
XXX.
...X
....
.#..
12
FIRE 3 D
FIRE 2 A
FIRE 3 C
FIRE 1 C
FIRE 4 D
FIRE 1 B
FIRE 4 A
FIRE 1 D
FIRE 2 D
FIRE 1 C
FIRE 4 B
FIRE 3 D
Вывод:
SUNK
SUNK
MISSED
HIT
MISSED
HIT
HIT
HIT
MISSED
SUNK
HIT
WIN 2
#include <exception>
#include <ios>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
struct field_t {
field_t(int n, int m) : alive_cells_count(0), self_(n), m_(m) {
for (auto &i : self_) {
std::cin >> i;
for (const auto j : i)
if (j == 'X' || j == '#')
alive_cells_count++;
}
}
std::string fire(int target_n, std::string_view target_m) {
const auto [norm_n, norm_m] = to_normal_coords(target_n, target_m);
if (self_.at(norm_n).at(norm_m) == '#') {
self_.at(norm_n).at(norm_m) = 'X';
return "HIT";
}
else if (self_.at(norm_n).at(norm_m) == 'X') {
self_.at(norm_n).at(norm_m) = '$';
alive_cells_count--;
if (alive_cells_count == 0)
return "GAMEOVER";
if (has_neighbours(norm_n, norm_m))
return "HIT";
return "SUNK";
}
return "MISSED";
}
private:
std::vector<std::string> self_;
int alive_cells_count;
int m_;
std::pair<int, int> to_normal_coords(int n, std::string_view m) {
const int norm_n = -(n - self_.size());
auto m_last = m.back();
int norm_m = static_cast<int>(m_last - 'A');
if (m.size() == 2)
norm_m += 26;
return {norm_n, norm_m};
}
bool has_neighbours(int norm_n, int norm_m) {
for (int i = 1; norm_n + i < self_.size(); i++) {
const auto neighbour = self_.at(norm_n + i).at(norm_m);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_n - i >= 0; i++) {
const auto neighbour = self_.at(norm_n - i).at(norm_m);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_m + i < m_; i++) {
const auto neighbour = self_.at(norm_n).at(norm_m + i);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_m - i >= 0; i++) {
const auto neighbour = self_.at(norm_n).at(norm_m - i);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
return false;
}
};
int main() {
int t = 0;
std::cin >> t;
for (; t; t--) {
int n = 0, m = 0, unused;
try {
std::cin >> n >> m >> unused >> unused;
field_t players[2]{{n, m},{n,m}};
int curr_player = 1;
int q;
std::cin >> q;
for (; q; q--) {
bool flag = true;
std::cin.ignore(5);
int target_n;
std::string target_m;
std::cin >> target_n >> target_m;
if (flag) {
auto res = players[curr_player].fire(target_n, target_m);
curr_player = curr_player == 1 ? 0 : 1;
if (res == "GAMEOVER") {
std::cout << "WIN " << curr_player + 1 << std::endl;
flag = false;
} else
std::cout << res << std::endl;
}
}
} catch (const std::exception &ex) {
std::cout << ex.what() << ' ' << n;
}
}
}#include <exception>
#include <ios>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
struct field_t {
field_t(int n, int m) : alive_cells_count(0), self_(n), m_(m) {
for (auto &i : self_) {
std::cin >> i;
for (const auto j : i)
if (j == 'X' || j == '#')
alive_cells_count++;
}
}
std::string fire(int target_n, std::string_view target_m) {
const auto [norm_n, norm_m] = to_normal_coords(target_n, target_m);
if (self_.at(norm_n).at(norm_m) == '#') {
self_.at(norm_n).at(norm_m) = 'X';
return "HIT";
}
else if (self_.at(norm_n).at(norm_m) == 'X') {
self_.at(norm_n).at(norm_m) = '$';
alive_cells_count--;
if (alive_cells_count == 0)
return "GAMEOVER";
if (has_neighbours(norm_n, norm_m))
return "HIT";
return "SUNK";
}
return "MISSED";
}
private:
std::vector<std::string> self_;
int alive_cells_count;
int m_;
std::pair<int, int> to_normal_coords(int n, std::string_view m) {
const int norm_n = -(n - self_.size());
auto m_last = m.back();
int norm_m = static_cast<int>(m_last - 'A');
if (m.size() == 2)
norm_m += 26;
return {norm_n, norm_m};
}
bool has_neighbours(int norm_n, int norm_m) {
for (int i = 1; norm_n + i < self_.size(); i++) {
const auto neighbour = self_.at(norm_n + i).at(norm_m);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_n - i >= 0; i++) {
const auto neighbour = self_.at(norm_n - i).at(norm_m);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_m + i < m_; i++) {
const auto neighbour = self_.at(norm_n).at(norm_m + i);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
for (int i = 1; norm_m - i >= 0; i++) {
const auto neighbour = self_.at(norm_n).at(norm_m - i);
if (neighbour == 'X' || neighbour == '#')
return true;
if (neighbour == '.')
break;
}
return false;
}
};
int main() {
int t = 0;
std::cin >> t;
for (; t; t--) {
int n = 0, m = 0, unused;
try {
std::cin >> n >> m >> unused >> unused;
field_t players[2]{{n, m},{n,m}};
int curr_player = 1;
int q;
std::cin >> q;
bool flag = true;
for (; q; q--) {
std::cin.ignore(5);
int target_n;
std::string target_m;
std::cin >> target_n >> target_m;
if (flag) {
auto res = players[curr_player].fire(target_n, target_m);
curr_player = curr_player == 1 ? 0 : 1;
if (res == "GAMEOVER") {
std::cout << "WIN " << curr_player + 1 << std::endl;
flag = false;
} else
std::cout << res << std::endl;
}
}
} catch (const std::exception &ex) {
std::cout << ex.what() << ' ' << n;
}
}
}