Морской бой

Lictor
Offline
Зарегистрирован: 01.10.2015

Доброго дня.

Я тут недавно пытался написать сапера, в принципе получилось - работает как надо. Теперь решил замахнуться на морской бой. Но вот беда... По поводу кода сапера получил комменты типа КГ/АМ, с коими в принципе согласен. Но вот хочется мне, что бы хоть морской бой было бы не очень стыдно показывать. 

Сейчас я на этапе расстановки кораблей случайным образом. 

 


uint32_t battlefield_computer[10][10];  // Поле компьютера

void setup() {

  Serial.begin(115200); // Открываем последовательное соединение

  randomSeed(analogRead(0));  // Запускаем функцию рандом случайным образом

  for (int i = 0; i < 10; i++) { // заполним поля нулями
    for (int j = 0; j < 10; j++) {
      battlefield_computer[i][j] = 0;
    }
  }

  //////////////////// Расставим корабли
  uint32_t ship_size = 5; // Размер корабля
  uint32_t ship_size_test = ship_size;

  int x = random(0, 10); // Случайные координаты корабля
  int y = random(0, 10);

  // uint8_t Direction = random(1, 3); // Случайное направление корабля
  uint8_t Direction = 1;

  if ( Direction == 1) {  // Если направление по оси Х, то
    if (x + ship_size < 10) { // Проверим, влезет ли корабль в игровое поле
      for (int i = 0; i < ship_size - 1; i++) { //Если влезет, то проверим свободны ли поля - 1 если есть корабль и 2 область вокруг корабля
        if (battlefield_computer[x + i][y] == 0) ship_size_test--;
      }
    }
    if (ship_size_test == 1) {
      for (int i = 0; i < ship_size ; i++) {
        battlefield_computer[x + i][y] = 1;
        if (x + i < 10 && y - 1 >= 0) battlefield_computer[x + i][y - 1] = 2;
        if (x + i < 10 && y + 1 < 10) battlefield_computer[x + i][y + 1] = 2;
      }
      if (x - 1 >= 0)  battlefield_computer[x - 1][y] = 2;
      if (x - 1 >= 0 && y + 1 < 10)  battlefield_computer[x - 1][y + 1] = 2;
      if (x - 1 >= 0 && y - 1 >= 0) battlefield_computer[x - 1][y - 1] = 2;
      battlefield_computer[x + ship_size][y] = 2;
      if (y + 1 < 10) battlefield_computer[x + ship_size][y + 1] = 2;
      if (y - 1 >= 0) battlefield_computer[x + ship_size][y - 1] = 2;
    }
  }

  //////////////////// Закончили расстановку

  for (int i = 0; i < 10; i++) { // Посмотрим, что получилось
    for (int j = 0; j < 10; j++) Serial.print(battlefield_computer[j][i]);  // Поменял j и i местами что бы оси совпадали с декартовыми координатами
    Serial.println();
  }


  for (int i = 0; i < 10; i++) { // Посмотрим, что получилось
    Serial.println();
  }
}

void loop() {
}

 

Это пример кода для расстановки кораблей пока по одной оси в одном направлении. Логика такая: случайным образом генерируем вначале координаты поля х и у, затем число 1 или 2. Если 1, то пытаемся поставить корабль по оси Х, если не влезает (выходит за пределы поля 10*10 или хоть одно поле занято), то пытаемся расположить корабль в другую сторону. Для 2 аналогично по оси Y. Поле проверяется что бы было пустым и корабли не соприкасались, для этого массив заполняется 1, если там стоит корабль или 2 - область вокруг корабля. 

 

Прошу помощи если не в оптимизации, то хоть как написать код похожий на код белого человека по архитектуре и логике. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Это же ваше хобби, а не наше - пишите, учитесь, переписывайте, получайте удовольствие. На пятой итерации поймёте и за архитектуру и за оптимизацию.

А то даже ещё не начали, а уже к папке бежите - одобрит он затею или нет.

rkit
Offline
Зарегистрирован: 23.11.2016

Это довольно распространенная олимпиадная задача. Eсли поискать, то наверняка найдутся подробные разборы.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Пипец- дальше будет спейсквест? Или тетрис?

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Пипец- дальше будет спейсквест? Или тетрис?

 

Думаю все же тетрис)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

В процессе рассмотрения и анализа любой задачи прежде всего стоит выявить её особенности, основываясь на которых, в дальнейшем и будет разрабатываться архитектура и алгоритмы. В случае генерации расположения кораблей на поле (опустим часть архитектуры в виде иерархии классов) - особенностью является тот факт, что располагать корабли следует от бОльшего к меньшему, соблюдая принцип "корабли не соприкасаются друг с другом". Далее приходит понимание, что анализ размещения корабля, начиная со случайно сгенерированной координаты (X,Y) включает в себя:

а) выбор случайного направления размещения корабля (горизонтально или вертикально);

б) выбор стартовой точки и направления генерации корабля (вверх/вниз или влево/вправо);

в) анализ возможности размещения корабля (анализ возможного соприкосновения кораблей).

Исходя из этих вводных - и разрабатывается алгоритм. В общем случае - он довольно тривиален, частности же реализации - зависят от вводных, например: оптимизация алгоритма по объёму используемой памяти, оптимизация алгоритма по быстродействию, и т.п.

Если реально хотите научится, то люто рекомендую к прочтению книгу Роберта Седжвика "Алгоритмы и структуры данных" - читается легко, изложено доступно. Короче, must read.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mykaida пишет:

Пипец- дальше будет спейсквест? Или тетрис?

А слабо сделать физический Тетрис? Чтобы реальные тетраминошки падали? Я вот давно думаю. Мож систему магнитов какую? Может, чтобы падали в жидкости, чтобы помедленнее? Всякий бред в голову приходит.

sadman41
Offline
Зарегистрирован: 19.10.2016

Нужны будут детали повышенной скользкости, чтобы их не заклинивало на излете...

Lictor
Offline
Зарегистрирован: 01.10.2015

Выстрадал... и даже работает. Как минимум за 40 циклов ошибок не было.


uint32_t battlefield_computer[10][10];  // Поле компьютера

void ship_arrangement();  // Функция расстановки кораблей, передаем размер и кол-во

void setup() {

  Serial.begin(115200); // Открываем последовательное соединение

  randomSeed(analogRead(0));  // Запускаем функцию рандом случайным образом

  for (int i = 0; i < 10; i++) { // заполним поля нулями
    for (int j = 0; j < 10; j++) battlefield_computer[i][j] = 0;
  }

  //////////////////// Расставим корабли
  ship_arrangement(4, 1); // Передаем размер корабля и кол-во
  ship_arrangement(3, 2); // Передаем размер корабля и кол-во
  ship_arrangement(2, 3); // Передаем размер корабля и кол-во
  ship_arrangement(1, 4); // Передаем размер корабля и кол-во
  //////////////////// Закончили расстановку

  for (int i = 0; i < 10; i++) { // Посмотрим, что получилось
    for (int j = 0; j < 10; j++) {
      //Serial.print(" ");
      Serial.print(battlefield_computer[i][j]);
    }
    Serial.println();
  }
  for (int i = 0; i < 1; i++) {
    Serial.println();
  }

} // Конец void setup()

void loop() {

}

void ship_arrangement(uint32_t ship_size, int quantity) {

  for (int t = 0; t < quantity; t++) {
label:
    int x = random(0, 10); // Случайные координаты корабля
    int y = random(0, 10);

    uint8_t Direction = random(0, 2); // Случайное направление корабля

    if (Direction == 1) { // Расположим корабль по оси Х (j)
      for (int j = 0; j < ship_size ; j++) {  // Проверяем свободны ли поля (т.е. равно ли оно 0)
        if (battlefield_computer[y][x + j] == 0 && x + j < 10) { // Если условие не выполняется, то переносимся на начало
        }
        else {
          goto label;
        }
      }

      for (int i = 0; i < ship_size ; i++) battlefield_computer[y][x + i] = 1; // Если проверка прошла успешно, рисуем корабль
      // А когда нарисовали корабль, заполним область вокруг
      for (int i = 0; i < ship_size ; i++) {
        if (y + 1 < 10)  battlefield_computer[y + 1][x + i] = 2;
        if (y - 1 >= 0)  battlefield_computer[y - 1][x + i] = 2;
      }

      if (x - 1 >= 0) {
        battlefield_computer[y][x - 1] = 2;
        if (y - 1 >= 0)  battlefield_computer[y - 1][x - 1] = 2;
        if (y + 1 < 10) battlefield_computer[y + 1][x - 1] = 2;
      }

      if (x + ship_size < 10) {
        battlefield_computer[y][x + ship_size] = 2;
        if (y - 1 >= 0) battlefield_computer[y - 1][x + ship_size] = 2;
        if (y + 1 < 10) battlefield_computer[y + 1][x + ship_size] = 2;
      }
      // Закончили заполнять область вокруг
    } // Конец расположения корабля по оси Х (j)
    else //Если корабль не расположен по оси Х
    { // Расположим корабль по оси Y (i)
      for (int i = 0; i < ship_size ; i++) {  // Проверяем свободны ли поля (т.е. равно ли оно 0)
        if (battlefield_computer[y + i][x] == 0 && y + i < 10) { // Если условие не выполняется, то переносимся на начало
        }
        else {
          goto label;
        }
      }

      for (int i = 0; i < ship_size ; i++) battlefield_computer[y + i][x] = 1; // Если проверка прошла успешно, рисуем корабль

      // А когда нарисовали корабль, заполним область вокруг
      for (int i = 0; i < ship_size ; i++) {
        if (x + 1 < 10)  battlefield_computer[y + i][x + 1] = 2;
        if (x - 1 >= 0)  battlefield_computer[y + i][x - 1] = 2;
      }

      if (y - 1 >= 0) {
        battlefield_computer[y - 1][x] = 2;
        if (x - 1 >= 0)  battlefield_computer[y - 1][x - 1] = 2;
        if (x + 1 < 10)  battlefield_computer[y - 1][x + 1] = 2;
      }

      if (y + ship_size < 10) {
        battlefield_computer[y + ship_size][x] = 2;
        if (x - 1 >= 0)  battlefield_computer[y + ship_size][x - 1] = 2;
        if (x + 1 < 10)  battlefield_computer[y + ship_size][x + 1] = 2;
      }
      // Закончили заполнять область вокруг
    }// Конец расположения корабля по оси Y (i)
  }
}

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А переменные battlefield_computer и ship_size точно должны бить uint32_t?

И предупреждения компилятора Вас ни разу не смущают?

Lictor
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

А переменные battlefield_computer и ship_size точно должны бить uint32_t?

И предупреждения компилятора Вас ни разу не смущают?

Компилятор ничего не пишет по этому поводу. А uint32_t вместо int я использовал т.к. обе переменных всегда больше 0.

А что не так?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Lictor пишет:

Компилятор ничего не пишет по этому поводу.

Он то пишет. Это Вы не читаете.

Откройте-ка в IDE диалог "Настройки". Найдите там "Сообщения компилятора". Что у Вас там выбрано? "Ничего"? Ну, это значит, что Вы зарыли голову в песок, как страус, и не хотите знать, что Вам пишут.

Запомните, если в этой настройке стоит не "Все", а что-то другое, значит хозяин IDE - страус и лох.

Lictor пишет:

т.к. обе переменных всегда больше 0.

И что? А uint8-t бывает меньше?

Lictor пишет:

А что не так?

Абсолютно на ровном месте расходуется в четыре раза больше памяти, чем нужно.

Lictor
Offline
Зарегистрирован: 01.10.2015

Все у меня включено, но нет там никаких предупреждений.

Про память понял.

Bruzzer
Offline
Зарегистрирован: 17.03.2020

Lictor пишет:

как написать код похожий на код белого человека ... 

Так может быть оставить uint32_t. Жить как белый человек - это в том числе ни в чем себе не отказывать, может и писать надо так-же.

Lictor
Offline
Зарегистрирован: 01.10.2015

Bruzzer пишет:

Lictor пишет:

как написать код похожий на код белого человека ... 

Так может быть оставить uint32_t. Жить как белый человек - это в том числе ни в чем себе не отказывать, может и писать надо так-же.

 

Может, но все таки хотелось бы знать как правильно или хотя бы не очень по индусски

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Lictor пишет:

Все у меня включено, но нет там никаких предупреждений.

Значит, Вы один такой. У всех остальных - есть.

Lictor
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

Lictor пишет:

Все у меня включено, но нет там никаких предупреждений.

Значит, Вы один такой. У всех остальных - есть.

 

Я даже скриншот приложил где ничего нет, Может это только в последних версиях IDE добавлено?

Bruzzer
Offline
Зарегистрирован: 17.03.2020

Lictor пишет:

Я даже скриншот приложил где ничего нет, Может это только в последних версиях IDE добавлено?

Про uint32_t (обведенный на вашем скртншоте) действительно предупреждений нет. (По крайней мере у меня)
Есть много предупреждений типа приведенных ниже. В вашей версии IDE тоже должно быть.
C:\Users\rep-gl\Documents\Arduino\sketch_apr22a\sketch_apr22a.ino:49:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

       for (int j = 0; j < ship_size ; j++)

Lictor
Offline
Зарегистрирован: 01.10.2015

Чего-то я застрял. Прошу помощи. 

Суть: игрок делает ход, вводя по очереди координаты Хр и Ур. Поле противника представляет собой двухмерный массив размером 10*10, заполненный цифрами 0, 1, 2, где 0 - пустое поле, 1 - корабль, 2 - клетка корабля, в которую игрок уже попал сейчас или ранее. 

И так проблема: необходимо узнать потопил ли игрок корабль после очередного хода. 

Я пытался сделать так: Если игрок попал в клетку со значением 1 или 2 (ну хочет человек два раза выстрелить в одно место...) то с помощью if проверяется есть ли по горизонтали или вертикали от места попадания клетки со значением 1 или 2, если нет, то выводится "потопил" (корабль получается одноклеточный и окружен нолями), если есть 2, то принимаем эту клетку за новый отсчет и проверяем ее так же вокруг... Если вокруг клетки попадания есть клетка со значением 1, то выводим "ранил", если только 2 и вокруг 2 только клетки с 2 и т.д., то выводим "убит". Но при попытке написать это я попросту тону в if... Причем там еще нужно учитывать размер поля, что бы не выйти за его пределы(

Как это можно сделать проще???

 

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Lictor пишет:

Как это можно сделать проще???

Сейчас попытался раскидать алгоритм - с одним массивом не получается. Надо 2, а лучше 3. Третий - для результатов. Ведь и на бумажках в морской бой играют на двух матрицах.

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Lictor пишет:

Как это можно сделать проще???

Сейчас попытался раскидать алгоритм - с одним массивом не получается. Надо 2, а лучше 3. Третий - для результатов. Ведь и на бумажках в морской бой играют на двух матрицах.

 

У меня была мысль сделать вторую матрицу для сохранения ходов игрока, но реализовать я это тоже не смог (в плане сравнения с первой, что бы узнать потоплен ли корабль)

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Тогда делаем матрицы 0-11, при этом 0 и 11 недоступны для записи и в них всегда ноль. matrica[12][12]

Далее, я думаю, будет попроще.

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Тогда делаем матрицы 0-11, при этом 0 и 11 недоступны для записи и в них всегда ноль. matrica[12][12]

Далее, я думаю, будет попроще.

Что бы не проверять граничные условия? Становится проще, но в if-ах я все равно путаюсь, как лучше организовать проверку последующих ячеек?

Bruzzer
Offline
Зарегистрирован: 17.03.2020

Отслеживать потопление корабля можно множеством способов.

Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.

Lictor
Offline
Зарегистрирован: 01.10.2015

...

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Bruzzer пишет:

Отслеживать потопление корабля можно множеством способов.

Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.

ИМХО - все много проще. Всегда играли на 2-х бумажках. И не должна быть куча кораблей с именем, а просто двумерные массивы с цифрами.

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Bruzzer пишет:

Отслеживать потопление корабля можно множеством способов.

Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.

ИМХО - все много проще. Всегда играли на 2-х бумажках. И не должна быть куча кораблей с именем, а просто двумерные массивы с цифрами.

 

Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Lictor пишет:

Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...

Ну если только набросок...

Давайте рассуждать - а как мы сами понимаем, что корабль потоплен? Мы смотрим сначала по горизонтали - первая клетка - корабль! далее смотрим сверху-снизу, если ничего нет - то считаем раз, если что-то есть - пропускаем, иначе от этого раз начинаем считать. Если все клетки корабля побиты - значит потоплен. После последней клетки корабля будет ноль.

То же самое делаем по вертикали.

И так после каждого хода, считая палубы кораблей и их (кораблей) количество.

Можно заморочится на написание программы, но Вы автор - дерзайте!

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Lictor пишет:

Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...

Ну если только набросок...

Давайте рассуждать - а как мы сами понимаем, что корабль потоплен? Мы смотрим сначала по горизонтали - первая клетка - корабль! далее смотрим сверху-снизу, если ничего нет - то считаем раз, если что-то есть - пропускаем, иначе от этого раз начинаем считать. Если все клетки корабля побиты - значит потоплен. После последней клетки корабля будет ноль.

То же самое делаем по вертикали.

И так после каждого хода, считая палубы кораблей и их (кораблей) количество.

Можно заморочится на написание программы, но Вы автор - дерзайте!

 

И вот мы вернулись к посту 18 и дереву if...

Lictor
Offline
Зарегистрирован: 01.10.2015

Мысль такая: к каждому "убил" прикручиваем счетчик, если сумма счетчиков по осям составит 4, то значит корабль таки потоплен. 

С каждого ранил будет goto на конец проверки (т.е. мы не будем проверять другие оси, если хоть на одной оси есть живая клетка корабля...)

  if (battlefield_computer[Yp][Xp] == 1 || battlefield_computer[Yp][Xp] == 2) { // Если есть попадание или стреляем второй раз в раненый кораблик
    battlefield_computer[Yp][Xp] == 2;  // Заменяем 1 на 2, что бы показать что корабль ранен

    // проверяем потоплен ли корабль

    if (Xp + 1 < 10 && battlefield_computer[Yp][Xp + 1] == 2) {
// Начинаем проверять следующую клетку 2
    if (Xp + 2 < 10 && battlefield_computer[Yp][Xp + 2] == 2) {
// Начинаем проверять следующую клетку 3
    if (Xp + 3 < 10 && battlefield_computer[Yp][Xp + 3] == 2) {
// Начинаем проверять следующую клетку
     Serial.println("Убил");  
// закончили проверять следующую клетку
    }
    else {
      if (Xp + 3 < 10 && battlefield_computer[Yp][Xp + 3] == 1) {
Serial.println("Ранил");
      }
      else {  // Тут battlefield_computer[Yp][Xp + 3] == 0 в любом случае
      Serial.println("Убил");  
      }
    }
// закончили проверять следующую клетку 3
    }
    else {
      if (Xp + 2 < 10 && battlefield_computer[Yp][Xp + 2] == 1) {
Serial.println("Ранил");
      }
      else {  // Тут battlefield_computer[Yp][Xp + 2] == 0 в любом случае
      Serial.println("Убил");  
      }
    }
// закончили проверять следующую клетку 2
    }
    else {
      if (Xp + 1 < 10 && battlefield_computer[Yp][Xp + 1] == 1) {
Serial.println("Ранил");
      }
      else {  // Тут battlefield_computer[Yp][Xp + 1] == 0 в любом случае
      Serial.println("Убил");  
      }
    }
    // закончили проверять потоплен ли корабль
  }

 

Как вариант?

Дополню, проверяем только три клетки по оси, т.к. максимальный размер корабля 4 клетки. 

И да, вывод "убил" я уберу, оставлю только по счетчику, здесь он для отладки

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Lictor пишет:

И вот мы вернулись к посту 18 и дереву if...

Да нет - у Вас новый массив. Без если, конечно не обойтись, но мы и сами его постоянно применяем. Сократить их количество можно только циклическими операциями.

nik182
Offline
Зарегистрирован: 04.05.2015

Хорошее предложение было #23. Сделайте класс корабль который содержит количество палуб, размещение на поле, проверку на целостность после попадания. Расставьте корабли на поле по их номерам. При попадании в клетку с номером корабля, вызывайте соответствующую проверку корабля. На поле ничего делать не придётся. Корабль сам проверится. В любой момент можно опросить корабли и узнать сколько целых палуб. Даже если поле сделать байтовым массивом а не uint32_t, то битов хватит на признак прострелянной клетки и номера корабля.      

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Хорошее предложение было #23. Сделайте класс корабль который содержит количество палуб, размещение на поле, проверку на целостность после попадания. Расставьте корабли на поле по их номерам. При попадании в клетку с номером корабля, вызывайте соответствующую проверку корабля. На поле ничего делать не придётся. Корабль сам проверится. В любой момент можно опросить корабли и узнать сколько целых палуб. Даже если поле сделать байтовым массивом а не uint32_t, то битов хватит на признак прострелянной клетки и номера корабля.      

Данунах - простейшую задачу начинаем извращать. Не нужны тут классы! Можно решить одним массивом (сложнее), можно двумя (проще), можно тремя (нагляднее), но приплетать классы - это бред.

Lictor
Offline
Зарегистрирован: 01.10.2015

Пока так, но  работает только для однопалубных... буду искать ошибку... Пока даже если подбил весь корабль больше одной палубы пишет, что корабль ранен

void player_move() {
fire:
wound:
  int Xp, Yp; // Координаты хода игрока

  while (1) { // Ждем координату по Х
    if (Serial.available() > 0) {
      Xp = Serial.parseInt();
      if (Xp < 0) Xp = 0;
      if (Xp > 9) Xp = 9;
      break;
    }
  }

  while (1) { // Ждем координату по Y
    if (Serial.available() > 0) {
      Yp = Serial.parseInt();
      if (Yp < 0) Yp = 0;
      if (Yp > 9) Yp = 9;
      Serial.print("Ход сделан ");
      Serial.print(Xp);
      Serial.print(" ");
      Serial.print(Yp);
      Serial.println();
      break;
    }
  }

  if (battlefield_computer[Yp][Xp] == 0) {
    Serial.println("Промах, ход переходит компьютеру ");
    order_of_progress = !order_of_progress;
  }


  int kill = 0; // Вспомогательный счетчик
  if (battlefield_computer[Yp][Xp] == 1 || battlefield_computer[Yp][Xp] == 2) { // Если есть попадание или стреляем второй раз в раненый кораблик
    battlefield_computer[Yp][Xp] == 2;  // Заменяем 1 на 2, что бы показать что корабль ранен

    // проверяем потоплен ли корабль по оси X++
    if (Xp + 1 < 10 && battlefield_computer[Yp][Xp + 1] == 2 ) {
      // Начинаем проверять следующую клетку 2
      if (Xp + 2 < 10 && battlefield_computer[Yp][Xp + 2] == 2 ) {
        // Начинаем проверять следующую клетку 3
        if (Xp + 3 < 10 && battlefield_computer[Yp][Xp + 3] == 2 ) {
          // Начинаем проверять следующую клетку
          // Serial.println("Убил");
          kill++;
          // закончили проверять следующую клетку
        }
        else {
          if (Xp + 3 < 10 && battlefield_computer[Yp][Xp + 3] == 1) {
            Serial.println("Ранил");
            goto wound;
          }
          else {  // Тут battlefield_computer[Yp][Xp + 3] == 0 в любом случае
            //  Serial.println("Убил");
            kill++;
          }
        }
        // закончили проверять следующую клетку 3
      }
      else {
        if (Xp + 2 < 10 && battlefield_computer[Yp][Xp + 2] == 1) {
          Serial.println("Ранил");
          goto wound;
        }
        else {  // Тут battlefield_computer[Yp][Xp + 2] == 0 в любом случае
          // Serial.println("Убил");
          kill++;
        }
      }
      // закончили проверять следующую клетку 2
    }
    else {
      if (Xp + 1 < 10 && battlefield_computer[Yp][Xp + 1] == 1) {
        Serial.println("Ранил");
        goto wound;
      }
      else {  // Тут battlefield_computer[Yp][Xp + 1] == 0 в любом случае
        // Serial.println("Убил");
        kill++;
      }
    }
    // закончили проверять потоплен ли корабль по оси Х++

    // проверяем потоплен ли корабль по оси X--
    if (Xp - 1 >= 0 && battlefield_computer[Yp][Xp - 1] == 2 ) {
      // Начинаем проверять следующую клетку 2
      if (Xp - 2 >= 0 && battlefield_computer[Yp][Xp - 2] == 2 ) {
        // Начинаем проверять следующую клетку 3
        if (Xp - 3 >= 0 && battlefield_computer[Yp][Xp - 3] == 2 ) {
          // Начинаем проверять следующую клетку
          // Serial.println("Убил");
          kill++;
          // закончили проверять следующую клетку
        }
        else {
          if (Xp - 3 >= 0 && battlefield_computer[Yp][Xp - 3] == 1) {
            Serial.println("Ранил");
            goto wound;
          }
          else {  // Тут battlefield_computer[Yp][Xp - 3] == 0 в любом случае
            //  Serial.println("Убил");
            kill++;
          }
        }
        // закончили проверять следующую клетку 3
      }
      else {
        if (Xp - 2 >= 0 && battlefield_computer[Yp][Xp - 2] == 1) {
          Serial.println("Ранил");
          goto wound;
        }
        else {  // Тут battlefield_computer[Yp][Xp - 2] == 0 в любом случае
          // Serial.println("Убил");
          kill++;
        }
      }
      // закончили проверять следующую клетку 2
    }
    else {
      if (Xp - 1 >= 0 && battlefield_computer[Yp][Xp - 1] == 1) {
        Serial.println("Ранил");
        goto wound;
      }
      else {  // Тут battlefield_computer[Yp][Xp - 1] == 0 в любом случае
        // Serial.println("Убил");
        kill++;
      }
    }
    // закончили проверять потоплен ли корабль по оси Х--

    // проверяем потоплен ли корабль по оси Y--
    if (Yp - 1 >= 0 && battlefield_computer[Yp - 1][Xp] == 2) {
      // Начинаем проверять следующую клетку 2
      if (Yp - 2 >= 0 && battlefield_computer[Yp - 2][Xp] == 2 ) {
        // Начинаем проверять следующую клетку 3
        if (Yp - 3 >= 0 && battlefield_computer[Yp - 3][Xp] == 2 ) {
          // Начинаем проверять следующую клетку
          // Serial.println("Убил");
          kill++;
          // закончили проверять следующую клетку
        }
        else {
          if (Yp - 3 >= 0 && battlefield_computer[Yp - 3][Xp] == 1) {
            Serial.println("Ранил");
            goto wound;
          }
          else {  // Тут battlefield_computer[Yp-3][Xp] == 0 в любом случае
            //  Serial.println("Убил");
            kill++;
          }
        }
        // закончили проверять следующую клетку 3
      }
      else {
        if (Yp - 2 >= 0 && battlefield_computer[Yp - 2][Xp] == 1) {
          Serial.println("Ранил");
          goto wound;
        }
        else {  // Тут battlefield_computer[Yp-2][Xp] == 0 в любом случае
          // Serial.println("Убил");
          kill++;
        }
      }
      // закончили проверять следующую клетку 2
    }
    else {
      if (Yp - 1 >= 0 && battlefield_computer[Yp - 1][Xp] == 1) {
        Serial.println("Ранил");
        goto wound;
      }
      else {  // Тут battlefield_computer[Yp -1][Xp] == 0 в любом случае
        // Serial.println("Убил");
        kill++;
      }
    }
    // закончили проверять потоплен ли корабль по оси Y--

    // проверяем потоплен ли корабль по оси Н++
    if (Yp + 1 < 10 && battlefield_computer[Yp + 1][Xp] == 2 ) {
      // Начинаем проверять следующую клетку 2
      if (Yp + 2 < 10 && battlefield_computer[Yp + 2][Xp] == 2 ) {
        // Начинаем проверять следующую клетку 3
        if (Yp + 3 < 10 && battlefield_computer[Yp + 3][Xp] == 2 ) {
          // Начинаем проверять следующую клетку
          // Serial.println("Убил");
          kill++;
          // закончили проверять следующую клетку
        }
        else {
          if (Yp + 3 < 10 && battlefield_computer[Yp + 3][Xp] == 1) {
            Serial.println("Ранил");
            goto wound;
          }
          else {  // Тут battlefield_computer[Yp + 3][Xp] == 0 в любом случае
            //  Serial.println("Убил");
            kill++;
          }
        }
        // закончили проверять следующую клетку 3
      }
      else {
        if (Yp + 2 < 10 && battlefield_computer[Yp + 2][Xp] == 1) {
          Serial.println("Ранил");
          goto wound;
        }
        else {  // Тут battlefield_computer[Yp + 2][Xp] == 0 в любом случае
          // Serial.println("Убил");
          kill++;
        }
      }
      // закончили проверять следующую клетку 2
    }
    else {
      if (Yp + 1 < 10 && battlefield_computer[Yp + 1][Xp] == 1) {
        Serial.println("Ранил");
        goto wound;
      }
      else {  // Тут battlefield_computer[Yp + 1][Xp] == 0 в любом случае
        // Serial.println("Убил");
        kill++;
      }
    }
    // закончили проверять потоплен ли корабль по оси Y++
    Serial.println(kill);
  }



  if (kill == 4) {
    Serial.println("Убил");
    goto fire;
  }

}  // Конец функции стрельбы игрока

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mykaida пишет:
это бред
А что не бред? Вам знакомо т.н. «Откровение Старджона»? В оригинале оно звучит так: «Ninety percent of everything is crap». Вот так и живём.

nik182
Offline
Зарегистрирован: 04.05.2015

Идея была в том, что играем в корабли. Их и надо использовать в качестве базового элемента. Поле это вспомогательная сущность. Плодить два - три массива это лишнее.   

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

ЕвгенийП пишет:

А что не бред? Вам знакомо т.н. «Откровение Старджона»? В оригинале оно звучит так: «Ninety percent of everything is crap». Вот так и живём.

Спасибо, гуру. Буду на это медитировать.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Идея была в том, что играем в корабли. Их и надо использовать в качестве базового элемента. Поле это вспомогательная сущность. Плодить два - три массива это лишнее.   

Возможно это моё старопердунское мнение, но есть 2 матрицы с числами, которые могут пересекаться и каждый ход изменяет их состояние. Вот где здесь корабли, как базовый элемент?

nik182
Offline
Зарегистрирован: 04.05.2015

Есть правила - количество палуб, количество кораблей, возможность касания кораблей при расстановке на поле. Где всё это в двух матрицах? Вы неявно используете понятие корабль, а пользуетесь последствиями использования этой сущности. А потом возникают вопросы как отследить положение корабля, которого его нет в матрицах, а есть только тень отражения, полученная в момент расстановки. Как только примите идею корабля, как главной сущности игры, то сразу исчезнут ограничения на размер поля и количество кораблей. Можно и через матрицы. Каждый выбирает свой путь. Классы это не бред, а удобный инструмент. Позволяет и проверять состояние и отрисовывать на поле и многое другое написав один раз правила.      

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Есть правила - количество палуб, количество кораблей, возможность касания кораблей при расстановке на поле. Где всё это в двух матрицах? Вы неявно используете понятие корабль, а пользуетесь последствиями использования этой сущности. А потом возникают вопросы как отследить положение корабля, которого его нет в матрицах, а есть только тень отражения, полученная в момент расстановки. Как только примите идею корабля, как главной сущности игры, то сразу исчезнут ограничения на размер поля и количество кораблей. Можно и через матрицы. Каждый выбирает свой путь. Классы это не бред, а удобный инструмент. Позволяет и проверять состояние и отрисовывать на поле и многое другое написав один раз правила.      

Ну по Вашей идеалогии каждый корабль - объект, который имеет положение в пространстве и отвечает на определенные запросы. Расставьте эти объекты по матрице 10х10.

Lictor
Offline
Зарегистрирован: 01.10.2015

Господа, я вас чуть чуть прерву... Можете посмотреть, что неправильно? Должно бы работать, но что-то явно не так...

Ошибка в последней функции player_move() Неправильно определяет потоплен ли корабль...

 

int battlefield_computer[10][10];  // Поле компьютера
int battlefield_computer_test[12][12];  // Поле компьютера, вспомогательное
int battlefield_player[10][10];  // Поле игрока
byte order_of_progress = 1;  // Флаг очередности хода, 1 - игрок, 0 - компьютер
int total_tonnage;  // Общее кол-во клеток-кораблей

void ship_arrangement();  // Функция расстановки кораблей, передаем размер и кол-во
void player_move();  // Функция хода игрока

void setup() {

  Serial.begin(115200); // Открываем последовательное соединение
  randomSeed(analogRead(0));  // Запускаем функцию рандом случайным образом

  for (int i = 0; i < 10; i++) { // заполним поле нулями
    for (int j = 0; j < 10; j++) {
      battlefield_computer[i][j] = 0;
      battlefield_player[i][j] = 0;
    }
  }

  for (int i = 0; i < 12; i++) { // заполним поле нулями
    for (int j = 0; j < 12; j++) {
      battlefield_computer_test[i][j] = 0;
    }
  }

  //////////////////// Расставим корабли
  ship_arrangement(4, 1); // Передаем размер корабля и кол-во
  ship_arrangement(3, 2); // Передаем размер корабля и кол-во
  ship_arrangement(2, 3); // Передаем размер корабля и кол-во
  ship_arrangement(1, 4); // Передаем размер корабля и кол-во

  for (int i = 0; i < 10; i++) { // Заменим 2 в полях вокруг корабля на 0
    for (int j = 0; j < 10; j++) {
      if (battlefield_computer[j][i] == 2) battlefield_computer[j][i] = 0;
    }
  }

  /* for (int i = 0; i < 10; i++) { // скопируем поле компьютера во вспомогательное поле
     for (int j = 0; j < 10; j++) {
       battlefield_computer_test[i + 1][j + 1] = battlefield_computer[i][j];
     }
    }*/

  //////////////////// Закончили расстановку

  for (int i = 0; i < 10; i++) { // Посмотрим, что получилось
    for (int j = 0; j < 10; j++) {
      //Serial.print(" ");
      Serial.print(battlefield_computer[j][i]);
    }
    Serial.println();
  }
  Serial.println();
  Serial.print("Общий тоннаж ");
  Serial.println(total_tonnage);

  /* Serial.println();
    for (int i = 0; i < 12; i++) { // Посмотрим, что получилось
     for (int j = 0; j < 12; j++) {
       //Serial.print(" ");
       Serial.print(battlefield_computer_test[j][i]);
     }
     Serial.println();
    }*/
} // Конец void setup()

void loop() {
  /////// Ход игрока
  if (order_of_progress == 1) {
    player_move();
  }
  else order_of_progress = !order_of_progress;
} // Конец void loop()

void ship_arrangement(int ship_size, int quantity) {  // Функция расстановки кораблей

  total_tonnage = total_tonnage + ship_size * quantity; // Кол-во клеток занятых кораблями

  for (int t = 0; t < quantity; t++) {  // Кол-во повторов равно кол-ву кораблей
label:
    int x = random(0, 10); // Случайные координаты корабля
    int y = random(0, 10);

    uint8_t Direction = random(0, 2); // Случайное направление корабля

    if (Direction == 1) { // Расположим корабль по оси Х (j)
      for (int j = 0; j < ship_size ; j++) {  // Проверяем свободны ли поля (т.е. равно ли оно 0)
        if (battlefield_computer[y][x + j] == 0 && x + j < 10) { // Если условие не выполняется, то переносимся на начало
        }
        else {
          goto label;
        }
      }

      for (int i = 0; i < ship_size ; i++) battlefield_computer[y][x + i] = 1; // Если проверка прошла успешно, рисуем корабль
      // А когда нарисовали корабль, заполним область вокруг
      for (int i = 0; i < ship_size ; i++) {
        if (y + 1 < 10)  battlefield_computer[y + 1][x + i] = 2;
        if (y - 1 >= 0)  battlefield_computer[y - 1][x + i] = 2;
      }

      if (x - 1 >= 0) {
        battlefield_computer[y][x - 1] = 2;
        if (y - 1 >= 0)  battlefield_computer[y - 1][x - 1] = 2;
        if (y + 1 < 10) battlefield_computer[y + 1][x - 1] = 2;
      }

      if (x + ship_size < 10) {
        battlefield_computer[y][x + ship_size] = 2;
        if (y - 1 >= 0) battlefield_computer[y - 1][x + ship_size] = 2;
        if (y + 1 < 10) battlefield_computer[y + 1][x + ship_size] = 2;
      }
      // Закончили заполнять область вокруг
    } // Конец расположения корабля по оси Х (j)
    else //Если корабль не расположен по оси Х
    { // Расположим корабль по оси Y (i)
      for (int i = 0; i < ship_size ; i++) {  // Проверяем свободны ли поля (т.е. равно ли оно 0)
        if (battlefield_computer[y + i][x] == 0 && y + i < 10) { // Если условие не выполняется, то переносимся на начало
        }
        else {
          goto label;
        }
      }

      for (int i = 0; i < ship_size ; i++) battlefield_computer[y + i][x] = 1; // Если проверка прошла успешно, рисуем корабль

      // А когда нарисовали корабль, заполним область вокруг
      for (int i = 0; i < ship_size ; i++) {
        if (x + 1 < 10)  battlefield_computer[y + i][x + 1] = 2;
        if (x - 1 >= 0)  battlefield_computer[y + i][x - 1] = 2;
      }

      if (y - 1 >= 0) {
        battlefield_computer[y - 1][x] = 2;
        if (x - 1 >= 0)  battlefield_computer[y - 1][x - 1] = 2;
        if (x + 1 < 10)  battlefield_computer[y - 1][x + 1] = 2;
      }

      if (y + ship_size < 10) {
        battlefield_computer[y + ship_size][x] = 2;
        if (x - 1 >= 0)  battlefield_computer[y + ship_size][x - 1] = 2;
        if (x + 1 < 10)  battlefield_computer[y + ship_size][x + 1] = 2;
      }
      // Закончили заполнять область вокруг
    }// Конец расположения корабля по оси Y (i)
  }
}

void player_move() {
  //fire:
  //wound:
  int Xp, Yp; // Координаты хода игрока

  while (1) { // Ждем координату по Х
    if (Serial.available() > 0) {
      Xp = Serial.parseInt();
      if (Xp < 0) Xp = 0;
      if (Xp > 9) Xp = 9;
      break;
    }
  }

  while (1) { // Ждем координату по Y
    if (Serial.available() > 0) {
      Yp = Serial.parseInt();
      if (Yp < 0) Yp = 0;
      if (Yp > 9) Yp = 9;
      Serial.print("Ход сделан ");
      Serial.print(Xp);
      Serial.print(" ");
      Serial.print(Yp);
      Serial.println();
      break;
    }
  }

  if (battlefield_computer[Yp][Xp] == 0) {
    Serial.println("Промах, ход переходит компьютеру ");
    order_of_progress = !order_of_progress;
  }


  int kill; // Вспомогательный счетчик
  kill = 0;

  if (battlefield_computer[Yp][Xp] == 1 || battlefield_computer[Yp][Xp] == 2) { // Если есть попадание или стреляем второй раз в раненый корабль
    battlefield_computer[Yp][Xp] == 2;  // Заменяем 1 на 2, что бы показать что корабль ранен

    for (int i = 1; i < 10; i++) { // Пройдемся по полям в поисках 0 или 1 по оси Х++
      if (Xp + i < 10) {
        if (battlefield_computer[Yp][Xp + i] == 1) {
          goto label;
          Serial.println("Ранен");
        }
        if (battlefield_computer[Yp][Xp + i] == 0) {
          kill++;
          break;
        }
      }
      else {  // Конец поля, корабль потоплен
        kill++;
        break;
      }
    } // Закончили хождения по оси Х++

    for (int i = 1; i < 10; i++) { // Пройдемся по полям в поисках 0 или 1 по оси Х--
      if (Xp - i >= 0) {
        if (battlefield_computer[Yp][Xp - i] == 1) {
          goto label;
          Serial.println("Ранен");
        }
        if (battlefield_computer[Yp][Xp - i] == 0) {
          kill++;
          break;
        }
      }
      else {  // Конец поля, корабль потоплен
        kill++;
        break;
      }
    } // Закончили хождения по оси Х--

    for (int i = 1; i < 10; i++) { // Пройдемся по полям в поисках 0 или 1 по оси Y++
      if (Yp + i < 10) {
        if (battlefield_computer[Yp + i][Xp] == 1) {
          goto label;
          Serial.println("Ранен");
        }
        if (battlefield_computer[Yp + i][Xp] == 0) {
          kill++;
          break;
        }
      }
      else {  // Конец поля, корабль потоплен
        kill++;
        break;
      }
    } // Закончили хождения по оси Y++

    for (int i = 1; i < 10; i++) { // Пройдемся по полям в поисках 0 или 1 по оси Y--
      if (Yp - i >= 0) {
        if (battlefield_computer[Yp - i][Xp] == 1) {
          goto label;
          Serial.println("Ранен");
        }
        if (battlefield_computer[Yp - i][Xp] == 0) {
          kill++;
          break;
        }
      }
      else {  // Конец поля, корабль потоплен
        kill++;
        break;
      }
    } // Закончили хождения по оси Y--

    if (5 > 10) {
label:
      Serial.println("Ранен");
    }

    Serial.println(kill);
    if (kill == 4) Serial.println("Убил");  // Если вокруг одни нули (через 2 перескакиваем и ищем о или 1)
  } // Закончили проверку потоплен ли корабль

}  // Конец функции стрельбы игрока

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Сами мы не местные... но каким боком тут вообще МК ???

Lictor
Offline
Зарегистрирован: 01.10.2015

Пост 40 отменяется, там дурацкая ошибка, вместо присваивания я поставил знак == Теперь вроде работает, тестировать окончательно буду завтра. 

Lictor
Offline
Зарегистрирован: 01.10.2015

Komandir пишет:

Сами мы не местные... но каким боком тут вообще МК ???

 

А чего? Я игру на ардуино делаю с помощью ее IDE. Раздел форума - программирование, так что пока все сходится.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Lictor пишет:

Ошибка в последней функции player_move() Неправильно определяет потоплен ли корабль...

Да там даже "защиты от дурака" нет. А если введут сивол, а не число?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Ардуинку не жалко ? Там конечное число перезаписей flash ! 

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Lictor пишет:

Ошибка в последней функции player_move() Неправильно определяет потоплен ли корабль...

Да там даже "защиты от дурака" нет. А если введут сивол, а не число?

 

Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Komandir пишет:

Ардуинку не жалко ? Там конечное число перезаписей flash ! 

200т - нормуль. Если не каждую секунду писать.

Lictor
Offline
Зарегистрирован: 01.10.2015

Komandir пишет:

Ардуинку не жалко ? Там конечное число перезаписей flash ! 

 

Не, не жалко. У меня россыпь контроллеров atmega из Китая по рублю за кулек, да и сама плата самодельная. Да и прошло пять лет с момента установки первого контроллера на плату на которой я отрабатываю скетчи, а он все еще живой, так что я считаю, что проблема порчи контроллера записью программ несколько преувеличена. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Lictor пишет:

Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом

Тогда давайте так - откручивайте проверку подбития кораблей в отдельную подпрограмму и будем её рассматривать. Иначе, даже с комментариями, у меня мозги заворачиваются. Тут Евгений нужен.

Lictor
Offline
Зарегистрирован: 01.10.2015

mykaida пишет:

Lictor пишет:

Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом

Тогда давайте так - откручивайте проверку подбития кораблей в отдельную подпрограмму и будем её рассматривать. Иначе, даже с комментариями, у меня мозги заворачиваются. Тут Евгений нужен.

А оно заработало))
Сейчас буду писать ход компьютера