Как написать программу для игры в сапера

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

Я хочу в этом цикле сделать знакомство с самим языком C, но тогда получится, что я пишу не про разработку игры. Поэтому я решил сделать так: начало материала посвящается разбору языка, а конец – разработке игры. Если что – напишите, как лучше.

Рассмотрим, из чего состоит программа на языке C, и чем она отличается от других языков, таких как Python, Java, Javascript, PHP.

В проекте есть один файл – minesweeper.c , который является скелетом программы. Его мы и рассмотрим.

(К сожалению, #Дзен-идиот превращает знак «решётка» в тэг, поэтому придётся напрячь воображение.)

Самой первой мы видим инструкцию #define

С её помощью можно объявлять константы. Примерно то же можно делать в PHP и JavaScript с помощью const , но define умеет гораздо больше. С ней можно писать целые макросы, вплоть до изменения операторов самого языка.

Как играть в Сапера

В нашем простейшем случае мы объявляем константу SDL_MAIN_HANDLED , у которой даже нет значения. Она просто есть, как логический флаг. Она никак не участвует в самой программе и предназначена для управления компиляцией. В данном случае она сообщает, что компиляция должна вестись под Windows определённым способом. Детали нам пока совсем не важны, лишь бы работало.

Подчеркну – это чисто заморочка SDL, она нужна только для SDL, только один раз в жизни, поэтому на ней задерживаться не будем.

Далее идут инструкции #include

Это аналог import в Python и Java, или include в PHP.

С помощью include мы включаем в свою программу описания функций из внешних библиотек, которые будем в ней использовать. Эти описания находятся в т.н. заголовочных файлах с расширением .h (header).

В данном случае мы включили в программу описания функций библиотеки SDL2 , что вполне естественно, и описания из библиотеки stdio (стандартный ввод-вывод).

Имена .h-файлов написаны в угловых скобках <> . Это значит, что компилятор будет искать их в стандартном каталоге include , путь к которому мы настроили в предыдущей части . Если же мы хотим указать файл .h из нестандартного каталога, то путь к нему надо записывать в кавычках.

Наконец, начинается функция:

int main(int argc, char* argv[])

В Python, JavaScript и PHP программу можно начать писать сразу же, но в C (и отдалённо похоже в Java) программа начинается с функции main .

Это нужно потому, что скомпилированная программа в машинных кодах загружается непосредственно операционной системой непосредственно в оперативную память, и ОС после того, как загрузила программу, должна её собственно запустить, то есть передать в процессор адрес памяти, с которого нужно начать работать. Так вот main() – это и есть точка запуска, где начинает работать именно наш код.

Далее, в C и переменные, и функции имеют тип.

Игра «Сапер» на Python, создаем игровое поле. Minesweeper in Python Tkinter

int main() – это значит, что функция должна возвращать результат в виде целого числа (int). Так как эта функция вызывается операционной системой, то результат вернётся в операционную систему и может быть обработан уже после того, как программа завершится (например, в bat-файле).

Кроме возвращаемого результата, main() имеет и входные параметры.

Это int argc (argument count) – целочисленный параметр, который сообщает число аргументов, и – сейчас будет сложновато, но разберёмся потом – массив символьных указателей char* argv[] (argument values).

Что это за аргументы?

Программу из командной строки можно запустить с различными настроечными ключами, например так (от балды совершенно):

minesweeper.exe -timer=no -sound=no -level=pro

Всё это и попадает из командной строки в массив argv[] функции main() . Первый аргумент это всегда сама программа, т.е. minesweeper.exe . Второй аргумент это -timer=no , третий это -sound=no , и т.д. Мы можем их записать и так: /timer , /sound , это вообще всем по барабану, кроме нас самих. Аргументы попадут в main() в таком виде, в каком мы их написали, а дальше мы разбираем их самостоятельно и как хотим.

К счастью, нам это не нужно, так что argc и argv можно полностью игнорировать.

Далее, создаются две переменные:

SDL_Window *window;
SDL_Event event;

Переменная-указатель (*) window имеет тип SDL_Window , а переменная event имеет тип SDL_Event .

Что это за типы, откуда они берутся?

В C нет классов и объектов, но есть структуры. Структура это просто кусок памяти, логически поделённый на поля разной (или одинаковой, как угодно) длины, и каждому полю назначено своё имя. То есть это нечто вроде объекта . А имя всей структуры и является типом.

Структура с именем SDL_Window описывает группу полей графического окна. Структура с именем SDL_Event описывает группу полей события. Эти структуры описаны в файле SDL.h , который мы ранее включили в программу.

Таком образом, переменная window будет хранить (ссылку на) информацию об окне, а переменная event – информацию о событиях. Они уже созданы, под них выделена память, но они пока бездействуют.

Далее по тексту вы можете заметить, что многие имена начинаются с SDL_ . Это делается для того, чтобы при включении разных библиотек названия их функций случайно не пересеклись. Приставка SDL_ делает имена типов и функций из библиотеки SDL уникальными.

На этом поверхностном описании я закончу, более подробно будем смотреть в следующих частях. А пока займёмся проектированием игры.

Представление данных

Поле Сапёра очевидно представлено целочисленной матрицей (двумерным массивом), с которой мы уже хорошо знакомы по таким проектам, как Robots и Питон на Питоне .

Каждый элемент матрицы может находиться в следующих состояниях:

  1. Есть бомба / Нет бомбы
  2. Закрыт / Открыт
  3. Нет флажка / Стоит флажок / Стоит вопрос / Неправильный флажок

Эти состояния могут существовать одновременно. Например: клетка с бомбой, закрыта, и на ней стоит флажок.

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

  1. 0: пусто, 1: бомба
  2. 0: открыто, 2: закрыто
  3. 0: нет флажка, 4: стоит флажок, 8: стоит вопрос, 16: неправильный флажок

Посмотрим на примере, что получается:

  • Клетка с бомбой: 1
  • Закрыта: 2
  • Стоит флажок: 4
Читайте также:
Программа неро не записывает диск

1 + 2 + 4 = 7. Это будет значение клетки.

Если посмотреть в двоичном виде, увидим, что каждый бит отвечает за своё состояние:

Источник: dzen.ru

Как написать своего сапёра на Java за 15 минут

Обложка: Как написать своего сапёра на Java за 15 минут

Для работы с графикой создадим отдельный класс — GUI. От него нам потребуется хранение всех графических элементов управления (т.е. полей клеток), определение элемента, по которому пришёлся клик и передача ему управления, вывод графических элементов на экран и управление основными функциями OpenGL.

Благо класс GUI будет взаимодействовать с графическими элементами, нам нужно создать интерфейс (писать классы сетки, клеток и прочую механику пока рано), который определит, что это такое. Логика подсказывает, что у графического элемента должны быть:

  • Внешний вид (текстура);
  • Координаты;
  • Размеры (ширина и высота);
  • Метод, который по переданным координатам клика определит, попал ли клик по элементу;
  • Метод, который обработает нажатие на элемент.

Таким образом, пишем:

public interface GUIElement < int getWidth(); int getHeight(); int getY(); int getX(); Sprite getSprite(); ///Создадим enum с таким именем, заполним позже int receiveClick(int x, int y, int button); /// Возвращаем результат клика ///Параметр button определяет кнопку мыши, которой был сделан щелчок. /// Здесь используется фишка Java 8 — default методы в интерфейсах. /// Если у вас более ранняя версия, вы можете использовать абстрактный класс /// вместо интерфейса. default boolean isHit(int xclick, int yclick)< return ( (xclick >getX()) (xclick < getX()+this.getWidth()) ) ( (yclick >getY()) (yclick < getY()+this.getHeight()) ); >>

В GUI должны храниться ячейки поля. Создадим для этих целей двумерный массив:

///CELLS_COUNT_X и CELLS_COUNT_Y — константы //Cell — класс, который реализует GUIElement; им займёмся немного позже private static Cell[][] cells;

GUI должен передавать клики элементам, которые он содержит. Вычислить адрес клетки, по которой кликнули, нетрудно:

public static int receiveClick(int x, int y, int button)< int cell_x = x/CELL_SIZE; int cell_y = y/CELL_SIZE; return cells[cell_x][cell_y].receiveClick(x,y,button); >

Теперь разберёмся с основными функциями OpenGL. Во-первых, нам нужна инициализация.

///Class GUI private static void initializeOpenGL() < try < //Задаём размер будущего окна Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT)); //Задаём имя будущего окна Display.setTitle(NAME); //Создаём окно Display.create(); >catch (LWJGLException e) < e.printStackTrace(); >glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,SCREEN_WIDTH,0,SCREEN_HEIGHT,1,-1); glMatrixMode(GL_MODELVIEW); /* * Для поддержки текстур */ glEnable(GL_TEXTURE_2D); /* * Для поддержки прозрачности */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* * Белый фоновый цвет */ glClearColor(1,1,1,1); >

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

///Этот метод будет вызываться извне public static void update() < updateOpenGL(); >///А этот метод будет использоваться только локально, /// т.к. базовым другие классы должны работать на более высоком уровне private static void updateOpenGL()

И, наконец, нам нужно это изображение вообще рисовать. Для этого пора закончить enum Sprite. Его элементы будут представлять из себя обёртку для текстуры с удобочитаемыми именами.

///enum Sprite ///Файлы со всеми этими именами должны лежать по адресу /// *папка проекта*/res/*имя текстуры*.png ZERO(«0»), ONE(«1»), TWO(«2»), THREE(«3»), FOUR(«4»), FIVE(«5»), SIX(«6»), SEVEN(«7»), EIGHT(«8»), HIDEN(«space»), BOMB(«bomb»), EXPLOSION(«explosion»), FLAG(«flag»), BROKEN_FLAG(«broken_flag»); private Texture texture; private Sprite(String texturename) < try < this.texture = TextureLoader.getTexture(«PNG», new FileInputStream(new File(«res/»+texturename+».png»))); >catch (IOException e) < e.printStackTrace(); >> public Texture getTexture()

Теперь мы можем написать метод для GUI, который будет рисовать элементы:

///Рисует все клетки public static void draw() < ///Очищает экран от старого изображения glClear(GL_COLOR_BUFFER_BIT); for(GUIElement[] line:cells)< for(GUIElement cell:line)< drawElement(cell); >> > ///Рисует элемент, переданный в аргументе private static void drawElement(GUIElement elem)

Нам осталось только сделать единый метод для инициализации графики, и остальное мы будем писать в основном управляющем классе, возвращаясь сюда, только чтобы внести незначительные изменения.

public static void init()< initializeOpenGL(); ///Классом генератора мы займёмся чуть позже. Пока можно просто ///создать его, вместе с пустым методом generate this.cells = Generator.generate(); >

Ячейки

Создадим класс Cell, реализующий интерфейс GUIElement. В методах getWidth() и getHeight() вернём константу, для координат придётся создать поля, которые будут инициализироваться конструктором.

Так же конструктором будем передавать состояние клетки: «-1», если это мина, «-2», если это взорванная мина, число мин поблизости в остальных случаях. Для этой цели можно было бы использовать enum, но число мин удобнее передавать как integer, имхо. Итак, конструктор:

private int x; private int y; private int state; public Cell (int x, int y, int state)

Ещё два поля — boolean isMarked и boolean isHidden будут отвечать за то, отметили ли клетку флажком, и открыли ли её. По умолчанию оба флага выставлены на false .

Разберёмся с методом getSprite() .

public Sprite getSprite() < if(this.isMarked)< if(!this.isHidden this.state!=-1)< ///Если эта клетка не скрыта, и на ней ///ошибочно стоит флажок. return Sprite.BROKEN_FLAG; >///В другом случае — return Sprite.FLAG; >else if(this.isHidden)< ///Если клетка не помечена, притом скрыта. return Sprite.HIDEN; >else< ///Если не помечена и не скрыта, выводим как есть: switch (state)< case -2: return Sprite.EXPLOSION; case -1: return Sprite.BOMB; default: assert (state>=0 state <=8): «Some crap :c»; ///Сделал массив для удобства. Можете, конечно, ///Писать 9 кейсов — ваш выбор 😉 return skin_by_number[state]; >> >

В случае, если на кнопку нажали, нам снова необходимо рассмотреть несколько простейших случаев:

Чтобы при поражении клетки можно было вскрыть, добавим метод:

public void show()

Для более удобной реализации генератора добавьте ещё и этот метод:

public void incNearMines() < if(state<0)< //ignore >else < state++; >>

Обработка ответов от клеток

Вернёмся к методу GUI.receiveClick() . Теперь мы не можем просто вернуть результат назад, т.к. если результат выполнения — единица, то нам нужно открыть соседние ячейки, а в главный управляющий класс вернуть уже ноль, в знак того, что всё прошло корректно.

public static int receiveClick(int x, int y, int button)< int cell_x = x/CELL_SIZE; int cell_y = y/CELL_SIZE; int result = cells[cell_x][cell_y].receiveClick(x,y,button); if(result==1)< ///Делаем вид, что тыкнули в клетки ///Сверху, снизу, справа и слева ///Игнорируем выхождение за границы поля try< receiveClick(x+CELL_SIZE,y,button); >catch(java.lang.ArrayIndexOutOfBoundsException e) < //ignore >try< receiveClick(x-CELL_SIZE,y,button); >catch(java.lang.ArrayIndexOutOfBoundsException e) < //ignore >try< receiveClick(x,y+CELL_SIZE,button); >catch(java.lang.ArrayIndexOutOfBoundsException e) < //ignore >try< receiveClick(x,y-CELL_SIZE,button); >catch(java.lang.ArrayIndexOutOfBoundsException e) < //ignore >return 0; > return result; >

Пишем генератор

Задачка эта не сложнее, чем создать массив случайных boolean-величин. Идея следующая — для каждой ячейки матрицы мы генерируем случайное число от 0 до 100. Если это число меньше 15, то в этом месте записываем в матрицу мину (таким образом, шанс встретить мину — 15%). Записав мину, мы вызываем у всех клеток вокруг метод incNearMines() , а для тех ячеек, где клетка ещё не создана храним значение в специальном массиве.

Читайте также:
Программа чтобы посмотреть на себя со стороны

public static Cell[][] generate() < < Random rnd = new Random(); ///Карта, которую мы вернём Cell[][] map = new Cell[CELLS_COUNT_X][CELLS_COUNT_Y]; ///Матрица с пометками, указывается кол-во мин рядом с каждой клеткой int[][] counts = new int[CELLS_COUNT_X][CELLS_COUNT_Y]; for(int x=0; xelse < ///Если есть, говорим ей о появлении мины map[x+i][y+j].incNearMines(); >>catch(java.lang.ArrayIndexOutOfBoundsException e) < //ignore >> > >else < ///Если была сгенерирована обычная клетка, создаём её, со ///state равным значению из матрицы map[x][y] = new Cell(x*CELL_SIZE, y*CELL_SIZE, counts[x][y]); >> > return map; > >

Главный управляющий класс и ввод

Создадим класс Main, в нём входной метод — public static void main(String[] args) . Этот метод должен будет делать всего две вещи: вызывать инициализацию GUI и циклически вызывать рабочие методы ( input() , GUI.draw() и GUI.update() ), пока не получит сигнал закрытия.

private static boolean end_of_game=false; public static void main(String[] args) < GUI.init(); while(!end_of_game)< input(); GUI.draw(); GUI.update(); >>

Здесь нам не хватает метода input() , займёмся им.

///Если за последний такт произошли какие-то события с мышью, ///перебираем их по очереди while(Mouse.next())< ///Если это было нажатие кнопки мыши, а не ///перемещение. if(Mouse.getEventButton()>=0 Mouse.getEventButtonState()) < int result; ///Отсылаем это на обработку в GUI result = GUI.receiveClick(Mouse.getEventX(), Mouse.getEventY(), Mouse.getEventButton()); switch(result)< case 0: //отлично! break; case -1: //не очень :c GUI.gameover(); break; >> > ///То же самое с клавиатурой while(Keyboard.next()) < if(Keyboard.getEventKeyState())< if(Keyboard.getEventKey()==Keyboard.KEY_ESCAPE)< isExitRequested = true; >> > ///Обрабатываем клик по кнопке «закрыть» окна isExitRequested=isExitRequested || Display.isCloseRequested();

Метод GUI.gameover() будет просто вызывать метод show() у каждой клетки, показывая таким образом всё поле:

public static void gameover() < for(Cell[] line:cells)< for(Cell cell:line)< cell.show(); >> >

gameplay

Запускаем:

UPD: исходники выложены на GitHub

Источник: tproger.ru

Русские Блоги

Пользователи, которые использовали Windows XP, никогда не забудут эту интересную, возможно, умопомрачительную игру. (Я все равно в нее не играл). Здесь я воспользуюсь консольной программой на C ++, чтобы просто реализовать эту игру про сапера.
Сапер под Win7 имеет следующий стиль:

Сначала разберем следующую игру:

  • Карта представляет собой прямоугольник, состоящий из квадратных квадратов, и на каждом квадрате есть либо гром, либо нет грома.
  • Нажмите квадрат по желанию, чтобы начать, если будет гром, он взорвется, затем игра закончится, если нет взрыва, продолжайте
  • Квадрат без взрыва покажет количество мин в сетке из девяти квадратов с его центром, а пустой означает, что нет
  • После одного щелчка, если нет взрыва и вокруг есть гром, дополнительные квадраты отображаться не будут. Если вокруг нет грома, будут отображаться все квадраты без грома вокруг, а квадраты с числами будут границей
  • Почему должно быть так? Поскольку он пуст, вы можете напрямую щелкнуть оставшиеся 8 квадратов вокруг (нет грома), поэтому компьютер помог нам сделать этот шаг, позвольте нам провести следующий анализ

Видно, что самое важное в описанном выше процессе: когда вокруг блока, по которому щелкнули мышью, нет грома, отображается вся область и граница, которые могут быть определены как свободные от грома. Очевидно, это необходимо использоватьПоиск в ширину, используйтеочередьРеализация несложная.

my-mine-sweeper

Схема эффекта реализации:

Поскольку это чистая консольная игра на C ++, введите координаты в мои.
Логика игры такова: каждый раз, когда вы принимаете ввод, затем мой, обновляете состояние, очищаете экран, выводите и мой, пока не закончится шахта.
Количество громов используется в качестве входных данных, установленных вами. Затем программа случайным образом генерирует местоположение шахты.

достичь

IDE:VS 2017 Community

| |—-block.h // Объявление класса блока и класса карты |—-stdafx.h // VS должен иметь этот файл заголовка, вы можете объявить некоторые файлы заголовков, которые все исходные файлы могут использовать в нем |—-block.cpp // Реализация метода класса Map |____game-MineSweeper.cpp // Основная функция, логическое тело

  • block.h —— block с Map Определение класса

// 2018.4.5 In XDU // block class and Map class definition // IDE: VS 2017 Community #pragma once #include #include #include #include using std::cout; using std::cin; using std::endl; using std::queue; using std::pair; const int max_X = 20; // Вы также можете преобразовать блок в класс шаблона и передать эти два параметра в интерфейс как параметры шаблона const int max_Y = 20; // Если вы хотите понять размер карты управления вводом, вы можете выделить массив в куче и передать его в конструктор в качестве параметра.Одномерный массив может имитировать двумерный массив. const int offset_X = 5; // Относительное смещение вертикальной оси при печати карты, горизонтальная ось ниже const int offset_Y = 3; templatetypename T> T max(T a, T b) < return a > b ? a : b; > templatetypename T> T min(T a, T b) < return a < b ? a : b; >struct block < bool has_mine; // Есть ли гром? int mine_around_num; // Количество мин вокруг bool digged; // Был ли он раскопан, если раскопан гром, он вернется напрямую, если нет, будет отображаться количество мин вокруг >; class Map < private: block Cube[max_X][max_Y]; public: // Передаем количество мин и инициализируем куб Map(int n); // Должен использовать поиск в ширину, отображать все позиции и возвращать false при копании шахты bool dig(int x, int y); // Распечатываем карту. Если произойдет взрыв грома, следующая функция очистит экран и напечатает окончательный результат void print(); // После того, как шахта взорвалась, распечатываем все локации void print_end(); >;

  • block.cpp —— Map Реализация функции-члена

Среди них Guangsou легко реализовать. print Многие функции имеют дело с содержимым выходного формата.

#include «stdafx.h» #include «block.h» //// Передаем количество мин и инициализируем их Map::Map(int n) < memset(Cube, 0, sizeof(Cube)); srand(time(0)); // Начальное число случайных чисел for (int i = 0; i < n; i++) // Закопано n мин случайным образом < int x = rand() % max_X; int y = rand() % max_Y; Cube[x][y].has_mine = true; //cout > for (int i = 0; i < max_X; i++) // Инициализируем карту for (int j = 0; j < max_Y; j++) for (int x = max(i — 1, 0); x 1, max_X — 1); x++) for (int y = max(j — 1, 0); y 1, max_Y — 1); y++) if (Cube[x][y].has_mine) Cube[i][j].mine_around_num++; > // Должен использовать поиск в ширину, отображать все позиции и возвращать false при копании шахты bool Map::dig(int x, int y) < Cube[x][y].digged = true; if (Cube[x][y].has_mine) return false; else < if (Cube[x][y].mine_around_num != 0) return true; else < queueint, int>> Q; // Используем очереди для поиска в ширину Q.push(< x,y >); while (!Q.empty()) < int curx = Q.front().first; // Выкопанная позиция присоединяется к команде int cury = Q.front().second; Q.pop(); for (int i = 1; i 4; i++) // Указывает направление, 1 ~ 4 вверх, вниз, влево и вправо < int tmpx = curx; int tmpy = cury; switch (i) // По умолчанию не будет < case 1: tmpx = max(curx — 1, 0); break; case 2: tmpx = min(curx + 1, max_X — 1); break; case 3: tmpy = max(cury — 1, 0); break; case 4: tmpy = min(cury + 1, max_Y — 1); break; > if (!Cube[tmpx][tmpy].digged !Cube[tmpx][tmpy].has_mine) // Если нет раскопок и нет грома и нет грома, то присоединяйтесь к команде < if (Cube[tmpx][tmpy].mine_around_num == 0) // Среднее положение выкопанной территории, то есть положение, где вокруг нет грома < Q.push(< tmpx,tmpy >); Cube[tmpx][tmpy].digged = true; > else Cube[tmpx][tmpy].digged = true; // Граница выкопанной территории, вокруг грохочет, приведи в состояние но не входи в команду > > > > cout return true; > > // Распечатать карту, вот и все void Map::print() < for (int oy = 0; oy < offset_Y; oy++) cout for (int ox = 0; ox < offset_X + 2 + max_X / 2; ox++) cout » «; cout «Y» cout » «; for (int oy = 0; oy < offset_X + 1; oy++) cout » «; for (int ox = 0; ox < max_Y; ox++) < cout if (ox < 10) cout » «; > cout // Все вышеперечисленное предназначено для контроля бокового смещения for (int i = 0; i < max_X; i++) < for (int ox = 0; ox < offset_X; ox++) cout » «; if (i == (max_Y) / 2) cout «X»; else cout » «; if (i < 10) cout » «; cout // Это элемент управления вертикальным смещением for (int j = 0; j < max_Y; j++) < if (!Cube[i][j].digged) // Не копали cout «■»; else if (Cube[i][j].has_mine) // Копать и гром cout «×»; else if (Cube[i][j].mine_around_num != 0) // Копали без грома и грома вокруг cout » » else cout » «; > cout > // После того, как шахта взорвалась, распечатайте все позиции, или вы можете просто распечатать позицию протектора с помощью print () void Map::print_end() < for (int oy = 0; oy < offset_Y; oy++) cout for (int ox = 0; ox < offset_X + 2 + max_X / 2; ox++) cout » «; cout «Y» cout » «; for (int oy = 0; oy < offset_X + 1; oy++) cout » «; for (int ox = 0; ox < max_Y; ox++) < cout if (ox < 10) cout » «; > cout // Все вышеперечисленное предназначено для контроля бокового смещения for (int i = 0; i < max_X; i++) < for (int ox = 0; ox < offset_X; ox++) cout » «; if (i == (max_Y) / 2) cout «X»; else cout » «; if (i < 10) cout » «; cout // Это элемент управления вертикальным смещением for (int j = 0; j < max_Y; j++) < if (Cube[i][j].has_mine) // Гром cout «×»; else if (Cube[i][j].mine_around_num != 0) // Без грома и грома вокруг cout » » else cout » «; > cout >

  • game-MIneSweeper.cpp —Основная функция
Читайте также:
Как установить на Андроид программу для чтения книг всех форматов

// 2018.4.5 In XDU // MineSwepper, classic game in Windows XP, a simple implementation with WIN32 console. // IDE: VS 2017 Community // author : Tiko // Github : aojueliuyun // I’m a student , happy to study annd sahre, welcome to communicate with me ! #include «stdafx.h» #include «block.h» int main(void) < int n; cout «Простая игра про сапера, отдающая дань уважения саперу из Windows XP!» cout «Основной алгоритм: поиск в ширину» cout «Размер карты по умолчанию: 20 * 20, который можно изменить в заголовочном файле block.h». cout «Кроме того, смещение по горизонтали и вертикали также можно изменить в block.h». cout «правило:» << endl «Используйте ■, чтобы указать место, где не проводились раскопки, и ×, чтобы указать взорванную шахту», cout «Число указывает количество громов в сетке из девяти квадратов с центром в точке сетки. Пробел означает, что грома нет!» cout «Как играть:» << endl «Поскольку это чистая консоль, мины добываются путем маркировки ввода». cout «Введите количество мин (подходит около 20):»; cin >> n; Map mymap(n); int x, y; system(«cls»); while (true) < mymap.print(); cout » t Введите координаты (x, y), разделенные пробелами! ps: x — по вертикали, y — по горизонтали» cout «ttt»; cin >> x >> y; while (cin.fail() || x0 || x >= 20 || x >= max_X || y >= max_Y) // Не удалось прочитать ввод или ввод не в указанном диапазоне < system(«cls»); mymap.print(); cout » t Введите координаты (x, y), разделенные пробелами! ps: x — по вертикали, y — по горизонтали» cout » t tВведены неверные данные, попробуйте еще раз!» cin.clear(); // Меняем индикатор статуса cin cin.ignore(); // Очистить входной буфер cout «ttt»; cin >> x >> y; > if (!mymap.dig(x, y)) < system(«cls»); mymap.print(); // Вы также можете выбрать функцию print_end (), чтобы распечатать все позиции cout » t tВы наступили на (» << x «,» << y «)» cout » t tПоздравления приглашенному офицеру Чжунлею, я больше не буду его отдавать, ты!» break; > system(«cls»); // Очистить экран, им легко пользоваться > cout » t tПросмотреть расположение всех мин г / п?»; char c; cin.get(); // Чтение возврата каретки if (cin.get(c) c == ‘y’) < system(«cls»); mymap.print_end(); > cout «tt»; return 0; >

Также в VS stdafx.h Пожалуйста, добавьте другие файлы самостоятельно.

Вывод

Изначально я хотел написать консольную RPG-игру: воины с уровнями, опытом, картами, реквизитом, материалами, оборудованием, NPC и другими элементами убивают драконов, а затем становятся ролевыми играми с драконами. Но спустя много часов я обнаружил, что было много проблем с дизайном.

А пока отложите это в сторону и подождите, пока не прочтете «Язык программирования C ++» Бьярна Страуструпа. Итак, сегодня я написал тральщика. На это ушло около двух часов, два часа на исправление ошибки, а затем еще два часа на управление логикой форматирования. Прошел один день, но в конечном итоге это всего лишь поиск в ширину. Для повышения эффективности в будущем.

Источник: russianblogs.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru