Ошибка в симуляции игры Морской бой: анализ и исправление
При реализации симуляции игры Морской бой на C++ разработчики часто сталкиваются с ошибкой, когда программа выводит HIT вместо MISSED. Рассмотрим причины возникновения такой проблемы и способы её устранения.
Типичная ошибка: неверная обработка повторных попаданий
В классическом Морском бое после того, как корабль потоплен, все его клетки становятся недоступными для новых попаданий. Однако в условии задачи есть особенность: усиленные клетки (символ #) требуют двух попаданий. После первого попадания в усиленную клетку она становится обычной (X), но не считается потопленной. Если игрок снова стреляет в ту же клетку, программа должна вернуть MISSED, а не HIT.
Почему возникает ошибка?
В предоставленном коде после попадания в усиленную клетку (#) она заменяется на X. При повторном выстреле в эту же клетку программа видит X и обрабатывает его как новое попадание, возвращая HIT. Это неверно, так как корабль уже был повреждён, и второе попадание в ту же клетку должно считаться промахом.
Как исправить код?
Необходимо добавить проверку: если клетка уже была повреждена (превращена в X из #), то при повторном выстреле она должна игнорироваться. Для этого можно ввести дополнительный символ, обозначающий уничтоженную усиленную клетку, например @. Тогда логика обработки выстрела будет следующей:
- Если клетка
#- первое попадание: заменяем наX, возвращаем HIT. - Если клетка
X- обычная неповреждённая клетка: заменяем на.(или другой символ), уменьшаем счётчик живых клеток, проверяем, потоплен ли корабль. - Если клетка
@- уже уничтоженная усиленная клетка: возвращаем MISSED.
Дополнительные проблемы в коде
Некорректное определение потопления корабля
Метод has_neighbours() проверяет наличие соседних клеток корабля по четырём направлениям. Однако он не учитывает, что корабль может быть повреждён частично. Например, если у двухпалубного корабля одна клетка уже уничтожена (стала .), а вторая ещё цела, то после попадания во вторую клетку метод может не найти соседей и ошибочно вернуть SUNK. Правильнее проверять, остались ли живые клетки у данного корабля, обходя все его палубы.
Проблема с игнорированием ходов после победы
В коде переменная flag сбрасывается после победы, но последующие ходы всё равно читаются из входного потока. Это может привести к смещению данных для следующего тестового набора. Необходимо дочитывать все оставшиеся ходы, не обрабатывая их, или использовать более надёжный механизм пропуска.
Альтернативный подход: моделирование состояния кораблей
Вместо работы с отдельными клетками удобнее хранить для каждого корабля список его палуб и количество попаданий. При выстреле можно быстро определить, к какому кораблю относится клетка, и обновить его состояние. Это упрощает проверку на потопление и обработку усиленных клеток.
Заключение
Ошибка HIT вместо MISSED возникает из-за неверной обработки повторных попаданий в усиленные клетки. Для исправления необходимо ввести дополнительное состояние для уничтоженных усиленных клеток и корректно обрабатывать повторные выстрелы. Также стоит пересмотреть алгоритм определения потопления корабля и обработку ходов после завершения игры.