Морской бой
- Войдите на сайт для отправки комментариев
Доброго дня.
Я тут недавно пытался написать сапера, в принципе получилось - работает как надо. Теперь решил замахнуться на морской бой. Но вот беда... По поводу кода сапера получил комменты типа КГ/АМ, с коими в принципе согласен. Но вот хочется мне, что бы хоть морской бой было бы не очень стыдно показывать.
Сейчас я на этапе расстановки кораблей случайным образом.
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 - область вокруг корабля.
Прошу помощи если не в оптимизации, то хоть как написать код похожий на код белого человека по архитектуре и логике.
Это же ваше хобби, а не наше - пишите, учитесь, переписывайте, получайте удовольствие. На пятой итерации поймёте и за архитектуру и за оптимизацию.
А то даже ещё не начали, а уже к папке бежите - одобрит он затею или нет.
Это довольно распространенная олимпиадная задача. Eсли поискать, то наверняка найдутся подробные разборы.
Пипец- дальше будет спейсквест? Или тетрис?
Пипец- дальше будет спейсквест? Или тетрис?
Думаю все же тетрис)
В процессе рассмотрения и анализа любой задачи прежде всего стоит выявить её особенности, основываясь на которых, в дальнейшем и будет разрабатываться архитектура и алгоритмы. В случае генерации расположения кораблей на поле (опустим часть архитектуры в виде иерархии классов) - особенностью является тот факт, что располагать корабли следует от бОльшего к меньшему, соблюдая принцип "корабли не соприкасаются друг с другом". Далее приходит понимание, что анализ размещения корабля, начиная со случайно сгенерированной координаты (X,Y) включает в себя:
а) выбор случайного направления размещения корабля (горизонтально или вертикально);
б) выбор стартовой точки и направления генерации корабля (вверх/вниз или влево/вправо);
в) анализ возможности размещения корабля (анализ возможного соприкосновения кораблей).
Исходя из этих вводных - и разрабатывается алгоритм. В общем случае - он довольно тривиален, частности же реализации - зависят от вводных, например: оптимизация алгоритма по объёму используемой памяти, оптимизация алгоритма по быстродействию, и т.п.
Если реально хотите научится, то люто рекомендую к прочтению книгу Роберта Седжвика "Алгоритмы и структуры данных" - читается легко, изложено доступно. Короче, must read.
Пипец- дальше будет спейсквест? Или тетрис?
А слабо сделать физический Тетрис? Чтобы реальные тетраминошки падали? Я вот давно думаю. Мож систему магнитов какую? Может, чтобы падали в жидкости, чтобы помедленнее? Всякий бред в голову приходит.
Нужны будут детали повышенной скользкости, чтобы их не заклинивало на излете...
Выстрадал... и даже работает. Как минимум за 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) } }А переменные battlefield_computer и ship_size точно должны бить uint32_t?
И предупреждения компилятора Вас ни разу не смущают?
А переменные battlefield_computer и ship_size точно должны бить uint32_t?
И предупреждения компилятора Вас ни разу не смущают?
Компилятор ничего не пишет по этому поводу. А uint32_t вместо int я использовал т.к. обе переменных всегда больше 0.
А что не так?
Компилятор ничего не пишет по этому поводу.
Он то пишет. Это Вы не читаете.
Откройте-ка в IDE диалог "Настройки". Найдите там "Сообщения компилятора". Что у Вас там выбрано? "Ничего"? Ну, это значит, что Вы зарыли голову в песок, как страус, и не хотите знать, что Вам пишут.
Запомните, если в этой настройке стоит не "Все", а что-то другое, значит хозяин IDE - страус и лох.
т.к. обе переменных всегда больше 0.
И что? А uint8-t бывает меньше?
А что не так?
Абсолютно на ровном месте расходуется в четыре раза больше памяти, чем нужно.
Все у меня включено, но нет там никаких предупреждений.
Про память понял.
как написать код похожий на код белого человека ...
Так может быть оставить uint32_t. Жить как белый человек - это в том числе ни в чем себе не отказывать, может и писать надо так-же.
как написать код похожий на код белого человека ...
Так может быть оставить uint32_t. Жить как белый человек - это в том числе ни в чем себе не отказывать, может и писать надо так-же.
Может, но все таки хотелось бы знать как правильно или хотя бы не очень по индусски
Все у меня включено, но нет там никаких предупреждений.
Значит, Вы один такой. У всех остальных - есть.
Все у меня включено, но нет там никаких предупреждений.
Значит, Вы один такой. У всех остальных - есть.
Я даже скриншот приложил где ничего нет, Может это только в последних версиях IDE добавлено?
Я даже скриншот приложил где ничего нет, Может это только в последних версиях 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++)
Чего-то я застрял. Прошу помощи.
Суть: игрок делает ход, вводя по очереди координаты Хр и Ур. Поле противника представляет собой двухмерный массив размером 10*10, заполненный цифрами 0, 1, 2, где 0 - пустое поле, 1 - корабль, 2 - клетка корабля, в которую игрок уже попал сейчас или ранее.
И так проблема: необходимо узнать потопил ли игрок корабль после очередного хода.
Я пытался сделать так: Если игрок попал в клетку со значением 1 или 2 (ну хочет человек два раза выстрелить в одно место...) то с помощью if проверяется есть ли по горизонтали или вертикали от места попадания клетки со значением 1 или 2, если нет, то выводится "потопил" (корабль получается одноклеточный и окружен нолями), если есть 2, то принимаем эту клетку за новый отсчет и проверяем ее так же вокруг... Если вокруг клетки попадания есть клетка со значением 1, то выводим "ранил", если только 2 и вокруг 2 только клетки с 2 и т.д., то выводим "убит". Но при попытке написать это я попросту тону в if... Причем там еще нужно учитывать размер поля, что бы не выйти за его пределы(
Как это можно сделать проще???
Как это можно сделать проще???
Сейчас попытался раскидать алгоритм - с одним массивом не получается. Надо 2, а лучше 3. Третий - для результатов. Ведь и на бумажках в морской бой играют на двух матрицах.
Как это можно сделать проще???
Сейчас попытался раскидать алгоритм - с одним массивом не получается. Надо 2, а лучше 3. Третий - для результатов. Ведь и на бумажках в морской бой играют на двух матрицах.
У меня была мысль сделать вторую матрицу для сохранения ходов игрока, но реализовать я это тоже не смог (в плане сравнения с первой, что бы узнать потоплен ли корабль)
Тогда делаем матрицы 0-11, при этом 0 и 11 недоступны для записи и в них всегда ноль. matrica[12][12]
Далее, я думаю, будет попроще.
Тогда делаем матрицы 0-11, при этом 0 и 11 недоступны для записи и в них всегда ноль. matrica[12][12]
Далее, я думаю, будет попроще.
Что бы не проверять граничные условия? Становится проще, но в if-ах я все равно путаюсь, как лучше организовать проверку последующих ячеек?
Отслеживать потопление корабля можно множеством способов.
Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.
...
Отслеживать потопление корабля можно множеством способов.
Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.
ИМХО - все много проще. Всегда играли на 2-х бумажках. И не должна быть куча кораблей с именем, а просто двумерные массивы с цифрами.
Отслеживать потопление корабля можно множеством способов.
Например, для меня привычно, что каждый корабль - это индивидуальность со своим именем. Можно создать массив в котором по индексу корабля хранится его состояние - например сколько клеток осталось убить. В начале там хранится размер корабля, с каждым попаданием уменьшаем пока не 0. А на игровом поле в клетках корабля храним его индекс в массиве. По мере попадания тоже меняем.
ИМХО - все много проще. Всегда играли на 2-х бумажках. И не должна быть куча кораблей с именем, а просто двумерные массивы с цифрами.
Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...
Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...
Ну если только набросок...
Давайте рассуждать - а как мы сами понимаем, что корабль потоплен? Мы смотрим сначала по горизонтали - первая клетка - корабль! далее смотрим сверху-снизу, если ничего нет - то считаем раз, если что-то есть - пропускаем, иначе от этого раз начинаем считать. Если все клетки корабля побиты - значит потоплен. После последней клетки корабля будет ноль.
То же самое делаем по вертикали.
И так после каждого хода, считая палубы кораблей и их (кораблей) количество.
Можно заморочится на написание программы, но Вы автор - дерзайте!
Можно хотя бы набросок как сделать? Дублирующий массив с копией поля компьютера и "каемкой" из 0 вокруг я создал...
Ну если только набросок...
Давайте рассуждать - а как мы сами понимаем, что корабль потоплен? Мы смотрим сначала по горизонтали - первая клетка - корабль! далее смотрим сверху-снизу, если ничего нет - то считаем раз, если что-то есть - пропускаем, иначе от этого раз начинаем считать. Если все клетки корабля побиты - значит потоплен. После последней клетки корабля будет ноль.
То же самое делаем по вертикали.
И так после каждого хода, считая палубы кораблей и их (кораблей) количество.
Можно заморочится на написание программы, но Вы автор - дерзайте!
И вот мы вернулись к посту 18 и дереву if...
Мысль такая: к каждому "убил" прикручиваем счетчик, если сумма счетчиков по осям составит 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 клетки.
И да, вывод "убил" я уберу, оставлю только по счетчику, здесь он для отладки
И вот мы вернулись к посту 18 и дереву if...
Да нет - у Вас новый массив. Без если, конечно не обойтись, но мы и сами его постоянно применяем. Сократить их количество можно только циклическими операциями.
Хорошее предложение было #23. Сделайте класс корабль который содержит количество палуб, размещение на поле, проверку на целостность после попадания. Расставьте корабли на поле по их номерам. При попадании в клетку с номером корабля, вызывайте соответствующую проверку корабля. На поле ничего делать не придётся. Корабль сам проверится. В любой момент можно опросить корабли и узнать сколько целых палуб. Даже если поле сделать байтовым массивом а не uint32_t, то битов хватит на признак прострелянной клетки и номера корабля.
Хорошее предложение было #23. Сделайте класс корабль который содержит количество палуб, размещение на поле, проверку на целостность после попадания. Расставьте корабли на поле по их номерам. При попадании в клетку с номером корабля, вызывайте соответствующую проверку корабля. На поле ничего делать не придётся. Корабль сам проверится. В любой момент можно опросить корабли и узнать сколько целых палуб. Даже если поле сделать байтовым массивом а не uint32_t, то битов хватит на признак прострелянной клетки и номера корабля.
Данунах - простейшую задачу начинаем извращать. Не нужны тут классы! Можно решить одним массивом (сложнее), можно двумя (проще), можно тремя (нагляднее), но приплетать классы - это бред.
Пока так, но работает только для однопалубных... буду искать ошибку... Пока даже если подбил весь корабль больше одной палубы пишет, что корабль ранен
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; } } // Конец функции стрельбы игрокаИдея была в том, что играем в корабли. Их и надо использовать в качестве базового элемента. Поле это вспомогательная сущность. Плодить два - три массива это лишнее.
А что не бред? Вам знакомо т.н. «Откровение Старджона»? В оригинале оно звучит так: «Ninety percent of everything is crap». Вот так и живём.
Спасибо, гуру. Буду на это медитировать.
Идея была в том, что играем в корабли. Их и надо использовать в качестве базового элемента. Поле это вспомогательная сущность. Плодить два - три массива это лишнее.
Возможно это моё старопердунское мнение, но есть 2 матрицы с числами, которые могут пересекаться и каждый ход изменяет их состояние. Вот где здесь корабли, как базовый элемент?
Есть правила - количество палуб, количество кораблей, возможность касания кораблей при расстановке на поле. Где всё это в двух матрицах? Вы неявно используете понятие корабль, а пользуетесь последствиями использования этой сущности. А потом возникают вопросы как отследить положение корабля, которого его нет в матрицах, а есть только тень отражения, полученная в момент расстановки. Как только примите идею корабля, как главной сущности игры, то сразу исчезнут ограничения на размер поля и количество кораблей. Можно и через матрицы. Каждый выбирает свой путь. Классы это не бред, а удобный инструмент. Позволяет и проверять состояние и отрисовывать на поле и многое другое написав один раз правила.
Есть правила - количество палуб, количество кораблей, возможность касания кораблей при расстановке на поле. Где всё это в двух матрицах? Вы неявно используете понятие корабль, а пользуетесь последствиями использования этой сущности. А потом возникают вопросы как отследить положение корабля, которого его нет в матрицах, а есть только тень отражения, полученная в момент расстановки. Как только примите идею корабля, как главной сущности игры, то сразу исчезнут ограничения на размер поля и количество кораблей. Можно и через матрицы. Каждый выбирает свой путь. Классы это не бред, а удобный инструмент. Позволяет и проверять состояние и отрисовывать на поле и многое другое написав один раз правила.
Ну по Вашей идеалогии каждый корабль - объект, который имеет положение в пространстве и отвечает на определенные запросы. Расставьте эти объекты по матрице 10х10.
Господа, я вас чуть чуть прерву... Можете посмотреть, что неправильно? Должно бы работать, но что-то явно не так...
Ошибка в последней функции 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) } // Закончили проверку потоплен ли корабль } // Конец функции стрельбы игрокаСами мы не местные... но каким боком тут вообще МК ???
Пост 40 отменяется, там дурацкая ошибка, вместо присваивания я поставил знак == Теперь вроде работает, тестировать окончательно буду завтра.
Сами мы не местные... но каким боком тут вообще МК ???
А чего? Я игру на ардуино делаю с помощью ее IDE. Раздел форума - программирование, так что пока все сходится.
Ошибка в последней функции player_move() Неправильно определяет потоплен ли корабль...
Да там даже "защиты от дурака" нет. А если введут сивол, а не число?
Ардуинку не жалко ? Там конечное число перезаписей flash !
Ошибка в последней функции player_move() Неправильно определяет потоплен ли корабль...
Да там даже "защиты от дурака" нет. А если введут сивол, а не число?
Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом
Ардуинку не жалко ? Там конечное число перезаписей flash !
200т - нормуль. Если не каждую секунду писать.
Ардуинку не жалко ? Там конечное число перезаписей flash !
Не, не жалко. У меня россыпь контроллеров atmega из Китая по рублю за кулек, да и сама плата самодельная. Да и прошло пять лет с момента установки первого контроллера на плату на которой я отрабатываю скетчи, а он все еще живой, так что я считаю, что проблема порчи контроллера записью программ несколько преувеличена.
Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом
Тогда давайте так - откручивайте проверку подбития кораблей в отдельную подпрограмму и будем её рассматривать. Иначе, даже с комментариями, у меня мозги заворачиваются. Тут Евгений нужен.
Проверки будут, но потом. Вначале я пытаюсь сделать так, что бы оно просто работало. Проверки корректности данных прикручу потом
Тогда давайте так - откручивайте проверку подбития кораблей в отдельную подпрограмму и будем её рассматривать. Иначе, даже с комментариями, у меня мозги заворачиваются. Тут Евгений нужен.
А оно заработало))
Сейчас буду писать ход компьютера