Схема ходов компьютера определяется программистом. Можно разрабатывать различные схемы. Мы будем использовать схему, которая дает некоторое преимущество игроку. Если создать игру, в которую всегда будет выигрывать компьютер,то вряд ли такая игра будет интересна игроку с компьютером. Если игрок будет выигрывать несколько чаще, чем компьютер –такой вариант порадует игрока. Побеждать всегда приятно! С другой стороны игрок должен понимать, что компьютер также прилагает усилия. И если расслабиться, то можно и проиграть.
1. Первый ход будет всегда принадлежать игроку.
2. Если на поле игрока нет раненых палуб, то компьютер выбирает любую случайную ячейку и делает выстрел в нее.При выстреле компьютер не делает выстрелов в пространство рядом с кораблем. Так как известно, что там не могут располагаться палубы других кораблей.
3. Если на поле игрока есть раненые палубы, то компьютер "смотрит" четыре ячейки вокруг этой палубы и выбирает одну из них, в которую можно сделать выстрел. При ранении корабля компьютер стреляет в него до полного уничтожения. Компьютер не отслеживает направление расположения корабля –тем самым, иногда, делает лишние ходы. Это и есть небольшое "подыгрывание"сопернику.
При выборе случайной ячейки для выстрела мы будем выполнять 100попыток поиска такой ячейки случайным образом. Если за 100 попыток не удается найти, то начинаем пробегать массив от начала до конца и берем первую подходящую ячейку для выстрела. После каждого выстрела мы будем проверять убит корабль или еще нет. Добавим метод, который выполняет выстрел компьютера:
//Выстрел компьютера -
// возвращает истину - если попал
private boolean compHodit()
{
//Признак попадания в цель
boolean rez = false;
//Признак выстрела в раненый
//корабль
boolean flag = false;
_for1:
//Пробегаем все игровое поле игрока
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
// Если находим раненую палубу
if ((masPlay[i][j]>=9)&&(masPlay[i][j]<=11))
{
flag = true;
// ячейка сверху
// Проверяем, что можно сделать выстрел
if (testMasPoz(i-1, j)&&(masPlay[i-1][j]<=4)&&(masPlay[i-1][j] !=-2))
{
//делаем выстрел
masPlay[i-1][j] += 7;
//проверяем, что убит
testUbit(masPlay, i-1, j);
// если произошло попадание
if (masPlay[i-1][j]>=8) rez = true;
//прерываем сразу все циклы
break _for1;
}
// ячейка снизу
// Проверяем, что можно сделать выстрел
else if (testMasPoz(i+1, j)&&(masPlay[i+1][j]<=4)&&(masPlay[i+1][j] !=-2))
{
//делаем выстрел
masPlay[i+1][j] += 7;
//проверяем, что убит
testUbit(masPlay, i+1, j);
// если произошло попадание
if (masPlay[i+1][j]>=8) rez = true;
//прерываем сразу все циклы
break _for1;
}
// ячейка слева
// Проверяем, что можно сделать выстрел
if (testMasPoz(i, j-1)&&(masPlay[i][j-1]<=4)&&(masPlay[i][j-1] !=-2))
{
//делаем выстрел
masPlay[i][j-1] += 7;
//проверяем, что убит
testUbit(masPlay, i, j-1);
// если произошло попадание
if (masPlay[i][j-1]>=8) rez = true;
//прерываем сразу все циклы
break _for1;
}
// ячейка справа
// Проверяем, что можно сделать выстрел
else if (testMasPoz(i, j+1)&&(masPlay[i][j+1]<=4)&&(masPlay[i][j+1] !=-2))
{
//делаем выстрел
masPlay[i][j+1] += 7;
//проверяем, что убит
testUbit(masPlay, i, j+1);
// если произошло попадание
if (masPlay[i][j+1]>=8) rez = true;
//прерываем сразу все циклы
break _for1;
}
}
}
}
// если не было выстрела в раненую палубу
if (flag == false) {
// делаем 100случайных попыток выстрела
// в случайное место
for (int l = 1; l <= 100; l++) {
// Находим случайную позицию на игровом поле
int i = (int) (Math.random() * 10);
int j = (int) (Math.random() * 10);
// Проверяем, что можно сделать выстрел
if ((masPlay[i][j] <= 4) && (masPlay[i][j] != -2)) {
// делаем выстрел
masPlay[i][j] += 7;
// проверяем, что убит
testUbit(masPlay, i, j);
// если произошло попадание
if (masPlay[i][j] >= 8)
rez = true;
// выстрел произошел
flag = true;
// прерываем цикл
break;
}
}
// если выстрела еще не было
if (flag == false) {
//начинаем пробегать весь массив от начала до конца
_for2: for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
// Проверяем, что можно сделать выстрел
if ((masPlay[i][j] <= 4)&& (masPlay[i][j] != -2)) {
// делаем выстрел
masPlay[i][j] += 7;
// проверяем, что убит
testUbit(masPlay, i, j);
// если произошло попадание
if (masPlay[i][j] >= 8)
rez = true;
// прерываем сразу все циклы
break _for2;
}
}
}
}
}
//проверяем конец игры
testEndGame();
//возвращаем результат
return rez;
В классе game имеется метод для выстрела игрока,добавим его программный код:
//Выстрел игрока
public void vistrelPlay(int i, int j)
{
// При выстреле прибавляем число 7
masComp[i][j] += 7;
//Проверяем убит ли корабль
testUbit(masComp, i, j);
//Проверяем конец игры
testEndGame();
// Если был промах - передаем ход компьютеру
if (masComp[i][j]<8)
{
compHod=true; // передаем ход компьютеру
// Ходит компьютер - пока попадает в цель
while (compHod==true) compHod = compHodit();
}
}
В методах для ходов игрока и компьютера был использован метод проверки после выстрела на признак полностью подбитого корабля. Дальше нам необходимо реализовать этот метод:
// Проверка убит ли корабль
private void testUbit(int[][] mas, int i, int j)
{
//Если однопалубный
if (mas[i][j]==8)
{
// делаем выстрел
mas[i][j] += 7;
// окружаем убитый корабль
okrPodbit(mas, i, j);
}
// Если двухпалубный
else if (mas[i][j]==9) analizUbit(mas, i, j, 2);
// Если трехпалубный
else if (mas[i][j]==10) analizUbit(mas, i, j, 3);
// Если четырехпалубный
else if (mas[i][j]==11) analizUbit(mas, i, j, 4);
}
Метод testUbit() вызывает методanalizUbit() для разных видов кораблей.
Осталось добавить код последнего метода analizUbit():
// Анализ убитого корабля
private void analizUbit(int[][] mas, int i, int j, int kolPalub)
{
//Количество раненых палуб
int kolRanen=0;
//Выполняем подсчет раненых палуб
for (int k=i-(kolPalub-1);k<=i+(kolPalub-1);k++)
{
for (int g=j-(kolPalub-1);g<=j+(kolPalub-1);g++)
{
// Если это палуба раненого корабля
if (testMasPoz(k, g)&&(mas[k][g]==kolPalub+7)) kolRanen++;
}
}
// Если количество раненых палуб совпадает с количеством палуб
//корабля, то он убит - прибавляем число7
if (kolRanen==kolPalub)
{
for (int k=i-(kolPalub-1);k<=i+(kolPalub-1);k++)
{
for (int g=j-(kolPalub-1);g<=j+(kolPalub-1);g++)
{
// Если это палуба раненого корабля
if (testMasPoz(k, g)&&(mas[k][g]==kolPalub+7))
{
// помечаем палубой убитого корабля
mas[k][g]+=7;
// окружаем палубу убитого корабля
okrPodbit(mas, k, g);
}
}
}
}
}
Рассмотрим алгоритм тестирования убитого корабля. После того как происходит выстрел в ячейку с попаданием –нам нужно проверять –убит корабль или еще нет. Если убит,то прибавлять число семь 7 ко всем его палубам, чтобы отметить как убитый, а также отметить пространство вокруг него.
Допустим, был сделан успешный выстрел в палубу четырехпалубного корабля (см. рис. 11). Значит, в этой ячейке будет число 11. Мы начинаем просматривать все ячейки вокруг и подсчитывать количество подбитых палуб четырехпалубного корабля. Если мы насчитываем их четыре –это значит, что корабль убит. Если корабль убит, то мы еще раз проходим пространство вокруг и ко всем ячейкам, которые содержат число 11,прибавляем число 7. В результате во всех этих ячейках получится число 18 (см. рис. 12). Если корабль еще не убит, то мы ничего не делаем.
Рис. 11
Рис. 12
После отметки палуб корабля как убитого, мы вычитаем единицу вокруг него (см. рис. 13). Для этих целей был создан специальный метод okrPodbit(). Когда происходит обход области вокруг проверяемой палубы, то она выбирается по следующему принципу. Мы берем отступ вверх,вниз, вправо, влево по три ячейки для четырехпалубного корабля (см. рис. 14). Так как другие палубы одного корабля не могут быть дальше. Такой же подход используется для двухпалубных и трехпалубных кораблей.Может возникнуть вопрос: а не сможем ли мы случайно захватить палубы соседних кораблей? Ответ на этот вопрос – нет, не можем. Потому что компьютер стреляет в корабль до тех пор, пока полностью не подобьет его.Другими словами, на игровом поле всегда один корабль с ранеными палубами.
Рис. 13
Рис. 14
Теперь наша игра для третьего уровня сложности закончена, а значит, завершена полностью. Сохраним проект в JAR-архив. Запустим наше приложение и поиграем! (см. рис. 15).
Внимание!!!JAR-архив игры Морской бой создается стандартным способом. Пример создания JAR-архива был рассмотрен при рассмотрении игры Змейка.