Как написать программу пятнашки

Введение в Python

  • Python — Обзор
  • Основы синтаксиса Python
  • Операторы в Python
  • Типы данных в Python
  • Условные конструкторы в Python
  • Циклы в Python
  • Функции в Python
  • Функциональное программирование в Python
  • ООП в Python
  • Модули в Python
  • Работа с файлами в Python
  • Обработка исключительных ситуаций в Python

Сегодня мы напишем на Python свою версию популярной логической игры — пятнашки. Цель игры заключается в том чтобы перемещая блоки в рамке упорядочить их по номерам.
Начнем с импорта нужных библиотек и задания глобальных переменных

from tkinter import Tk, Canvas from random import shuffle # Размер игрового поля (4×4) BOARD_SIZE = 4 # Размер одного блока в пикселях SQUARE_SIZE = 80 # Значение пустого блока. В нашем случае пустым будет последний блок EMPTY_SQUARE = BOARD_SIZE ** 2 # Главное окно root = Tk() root.title(«Pythonicway Fifteen») # Область для рисования c = Canvas(root, width=BOARD_SIZE * SQUARE_SIZE, height=BOARD_SIZE * SQUARE_SIZE, bg=’#808080′) c.pack() root.mainloop()

В качестве пятнашек у нас будет выступать список c целыми числами.

Создание игры Пятнашка на языке C++


board = list(range(1, EMPTY_SQUARE + 1))

Теперь напишем функцию, которая будет отрисовывать пятнашки из списка:

def draw_board(): # убираем все, что нарисовано на холсте c.delete(‘all’) # Наша задача сгруппировать пятнашки из списка в квадрат # со сторонами BOARD_SIZE x BOARD_SIZE # i и j будут координатами для каждой отдельной пятнашки for i in range(BOARD_SIZE): for j in range(BOARD_SIZE): # получаем значение, которое мы должны будем нарисовать # на квадрате index = str(board[BOARD_SIZE * i + j]) # если это не клетка которую мы хотим оставить пустой if index != str(EMPTY_SQUARE): # рисуем квадрат по заданным координатам c.create_rectangle(j * SQUARE_SIZE, i * SQUARE_SIZE, j * SQUARE_SIZE + SQUARE_SIZE, i * SQUARE_SIZE + SQUARE_SIZE, fill=’#43ABC9′, outline=’#FFFFFF’) # пишем число в центре квадрата c.create_text(j * SQUARE_SIZE + SQUARE_SIZE / 2, i * SQUARE_SIZE + SQUARE_SIZE / 2, text=index, font=»Arial <> italic».format(int(SQUARE_SIZE / 4)), fill=’#FFFFFF’)

Не забудьте вызвать функцию отрисовки игрового поля перед вызовом root.mainloop()

игровое поле пятнашек

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

def click(event): # Получаем координаты клика x, y = event.x, event.y # Конвертируем координаты из пикселей в клеточки x = x // SQUARE_SIZE y = y // SQUARE_SIZE # Получаем индекс в списке объекта по которому мы нажали board_index = x + (y * BOARD_SIZE) # Получаем индекс пустой клетки в списке. Эту функцию мы напишем позже empty_index = get_empty_neighbor(board_index) # Меняем местами пустую клетку и клетку, по которой кликнули board[board_index], board[empty_index] = board[empty_index], board[board_index] # Перерисовываем игровое поле draw_board() # Если текущее состояние доски соответствует правильному — рисуем сообщение о победе if board == correct_board: # Эту функцию мы добавим позже show_victory_plate()

Привязываем обработчик событий к холсту

Как собрать Пятнашки? Скоростная сборка 15-Puzzle!


c.bind(», click)

Теперь нужно добавить функцию get_empty_neighbor, которая будет возвращать индекс блока с которым мы хотим поменять местами наш блок. Эта функция может показаться немного сложной, поэтому постараюсь сначала описать основную идею. Мы будем менять клетки местами, только если рядом с клеткой на которую мы нажали будет пустая клетка.

Рядом означает сверху, снизу, слева или справа. Структурой данных для представления всех блоков мы выбрали одномерный список. В таком случае, сверху и снизу означает на расстоянии размера доски. Например, 7 клетка на расстоянии 4 от 11, соответственно 11 находится под 7. Слева и справа означает, что клетка на расстоянии 1 от заданной. Например, 8 справа от 7, а 6 — слева.

Единственное, о чем осталось позаботиться — это ситуация, когда клетка на расстоянии 1, но на следующем ряду, например, 8 и 9, в такой ситуации, мы не хотим менять их местами. Если блоки поменять невозможно — просто вернем блок, по которому нажали.

def get_empty_neighbor(index): # получаем индекс пустой клетки в списке empty_index = board.index(EMPTY_SQUARE) # узнаем расстояние от пустой клетки до клетки по которой кликнули abs_value = abs(empty_index — index) # Если пустая клетка над или под клектой на которую кликнули # возвращаем индекс пустой клетки if abs_value == BOARD_SIZE: return empty_index # Если пустая клетка слева или справа elif abs_value == 1: # Проверяем, чтобы блоки были в одном ряду max_index = max(index, empty_index) if max_index % BOARD_SIZE != 0: return empty_index # Рядом с блоком не было пустого поля return index

Теперь добавим функцию show_victory_plate, которая будет выводить сообщение о победе на экран.

def show_victory_plate(): # Рисуем черный квадрат по центру поля c.create_rectangle(SQUARE_SIZE / 5, SQUARE_SIZE * BOARD_SIZE / 2 — 10 * BOARD_SIZE, BOARD_SIZE * SQUARE_SIZE — SQUARE_SIZE / 5, SQUARE_SIZE * BOARD_SIZE / 2 + 10 * BOARD_SIZE, fill=’#000000′, outline=’#FFFFFF’) # Пишем красным текст Победа c.create_text(SQUARE_SIZE * BOARD_SIZE / 2, SQUARE_SIZE * BOARD_SIZE / 1.9, text=»ПОБЕДА!», font=»Helvetica <> bold».format(int(10 * BOARD_SIZE)), fill=’#DC143C’)

Пятнашки победа

Чтобы запустить игру нам нужно добавить несколько последних штрихов.

# Создаем список блоков board = list(range(1, EMPTY_SQUARE + 1)) # Список с которым мы будем сравнивать результат. В данном случае это # просто отсортированный список, но при желании можно придумать что-то другое correct_board = board[:] # перемешиваем блоки shuffle(board) # рисуем доску draw_board()

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

  1. Для нечетного размера поля, головоломка решаема, если количество необходимых перемещений парно.
  2. Для четного размера поля, головоломка решаема если
    • Пустой блок находится на парном (втором, четвертом, шестом. ) ряду снизу и количество перемещений непарно.
    • Пустой блок на непарном (первый, третий, пятый. ) ряду снизу и количество перемещений парно.
    • Во всех остальных случаях головоломка не имеет решения.
    Читайте также:
    Как пользоваться программой дребеденьги

    def get_inv_count(): «»» Функция считающая количество перемещений «»» inversions = 0 inversion_board = board[:] inversion_board.remove(EMPTY_SQUARE) for i in range(len(inversion_board)): first_item = inversion_board[i] for j in range(i+1, len(inversion_board)): second_item = inversion_board[j] if first_item > second_item: inversions += 1 return inversions def is_solvable(): «»» Функция определяющая имеет ли головоломка рещение «»» num_inversions = get_inv_count() if BOARD_SIZE % 2 != 0: return num_inversions % 2 == 0 else: empty_square_row = BOARD_SIZE — (board.index(EMPTY_SQUARE) // BOARD_SIZE) if empty_square_row % 2 == 0: return num_inversions % 2 != 0 else: return num_inversions % 2 == 0

    Теперь добавим только код перемешивания блоков и игра готова

    while not is_solvable(): shuffle(board)

    Игра пятнашки в процессе

    Исходный код игры на гитхаб

    • Пятнашки на Python
    • Паттерны проектирования в Python
    • Множествeнное наследование в Python
    • Абстрактные классы в Python
    • Сапер на Python

    Источник: www.pythonicway.com

    Игра «Пятнашки» и PyGame

    Здравствуйте народ. Давненько я не выкладывал ничего нового в блоге и тому есть две причины. Первая, это работа. Отвлекает, знаете ли. Второе — осознал что Python, со всеми его возможностями мало подходит для разработки небольших проектов, если только не требуется кроссплатформенность. Мелкомягкие захватили мой разум, да. Но не суть.

    Когда-то давно хотел я написать пятнашки с графическим интерфейсом. Но вот как работать с изображениями тогда я так и не понял. Но, спустя какое-то количество времени я все же решил исправить этот недостаток и вот вам готовая программка. Как всегда, советую перебивать код вручную, ибо полезно.

    Но все равно вам придется скачать архив со страницы «Загрузки», ибо все картинки (а заодно и готовая программа) находятся в нем. Если хотите, рисунки можете перерисовать самостоятельно. Все же Paint мало подходит для создания красивых изображений.

    И еще. В связи с очередным обновлением редактора WordPress и невозможностью получить старый редактор без перехода на новый домен третьего уровня (к этому я привык а на вашу щедрость для покупки домена второго уровня не надеюсь) выделить ключевые слова Python больше не представляется возможным. Так что теперь только так.

    Касательно отрисовки своих фишек — размер 99*99 точек, иначе правьте программу. Какого-то сообщения по завершению игры не будет — программа молча закроется, ибо лень мне уже придумывать было. Ну и напоследок, хотя Python я и подзабросил. но это не значит, что периодически не будут появляться новые проекты. Так что сайт живет, хотя и не так динамично как раньше. Спасибо за внимание. Все вопросы задавайте в комментариях .

    import pygame, random, sys pygame.init() # Комбинация выигрыша win=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0] def get_images(): ImageList = [«»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»,»»] ImageList[1]=pygame.image.load(«.imagesi1.jpg») ImageList[2]=pygame.image.load(«.imagesi2.jpg») ImageList[3]=pygame.image.load(«.imagesi3.jpg») ImageList[4]=pygame.image.load(«.imagesi4.jpg») ImageList[5]=pygame.image.load(«.imagesi5.jpg») ImageList[6]=pygame.image.load(«.imagesi6.jpg») ImageList[7]=pygame.image.load(«.imagesi7.jpg») ImageList[8]=pygame.image.load(«.imagesi8.jpg») ImageList[9]=pygame.image.load(«.imagesi9.jpg») ImageList[10]=pygame.image.load(«.imagesi10.jpg») ImageList[11]=pygame.image.load(«.imagesi11.jpg») ImageList[12]=pygame.image.load(«.imagesi12.jpg») ImageList[13]=pygame.image.load(«.imagesi13.jpg») ImageList[14]=pygame.image.load(«.imagesi14.jpg») ImageList[15]=pygame.image.load(«.imagesi15.jpg») return ImageList def print_blocks(): # Печатаем фишки на поле x=0 y=0 for i in range (16): if deck[i]>0: screen.blit(ImageList[deck[i]], (x, y)) else: None x=x+100 if (i==3 or i==7 or i==11): x=0 y=y+100 def possible_moves(new_game): # Получаем список доступных ходов moves = [] ind = new_game.index(0) if ind == 0: moves.append(new_game[1]) moves.append(new_game[4]) elif ind == 1: moves.append(new_game[0]) moves.append(new_game[2]) moves.append(new_game[5]) elif ind == 2: moves.append(new_game[1]) moves.append(new_game[3]) moves.append(new_game[6]) elif ind == 3: moves.append(new_game[2]) moves.append(new_game[7]) elif ind == 4: moves.append(new_game[0]) moves.append(new_game[5]) moves.append(new_game[8]) elif ind == 5: moves.append(new_game[1]) moves.append(new_game[4]) moves.append(new_game[6]) moves.append(new_game[9]) elif ind == 6: moves.append(new_game[2]) moves.append(new_game[5]) moves.append(new_game[7]) moves.append(new_game[10]) elif ind == 7: moves.append(new_game[3]) moves.append(new_game[6]) moves.append(new_game[11]) elif ind == 8: moves.append(new_game[4]) moves.append(new_game[9]) moves.append(new_game[12]) elif ind == 9: moves.append(new_game[5]) moves.append(new_game[8]) moves.append(new_game[10]) moves.append(new_game[13]) elif ind == 10: moves.append(new_game[6]) moves.append(new_game[9]) moves.append(new_game[11]) moves.append(new_game[14]) elif ind == 11: moves.append(new_game[7]) moves.append(new_game[10]) moves.append(new_game[15]) elif ind == 12: moves.append(new_game[8]) moves.append(new_game[13]) elif ind == 13: moves.append(new_game[9]) moves.append(new_game[12]) moves.append(new_game[14]) elif ind == 14: moves.append(new_game[10]) moves.append(new_game[13]) moves.append(new_game[15]) else: moves.append(new_game[11]) moves.append(new_game[14]) return moves def get_new_random(): line = list(range(16)) random.shuffle(line) return line #Основной код игры # Получаем список изображений ImageList=get_images() # Новый расклад deck= get_new_random() # Подготавливаем экран black=0,0,0 size= width,height=399,399 screen=pygame.display.set_mode(size) pygame.display.set_caption(«Пятнашки») while 1: for event in pygame.event.get(): if event.type==pygame.QUIT: sys.exit() movies = possible_moves(deck) # Ждем щелчок мыши на поле if event.type == pygame.MOUSEBUTTONDOWN: pos=(event.pos) ansver=int(pos[0]/100)+(int(pos[1]/100))*4 if deck[ansver] in movies: nul=deck.index(0) deck[nul]=deck[ansver] deck[ansver]=0 if deck==win: sys.exit() screen.fill(black) print_blocks() pygame.display.flip()

    Источник: writegamepython.wordpress.com

    Простая игра на SFML

    Будем делать игру «пятнашки» на языке C++ с использованием библиотеки SFML. Пятнашки — это широко известная головоломка, которая выглядит следующим образом:

    На игровом поле размером 4х4 случайным образом расположены 15 плашек с номерами от 1 до 15 и одно свободное место. Передвигать плашки можно только по одной и только на свободное место. Целью игры является выстроение плашек на игровом поле в порядке, соответствующем их номерам.

    Итак, начнем.

    Запускаем Visual Studio и создаем новый пустой проект. Можете назвать его как хотите, я назвал «15». В этом проекте создаем новый файл main.cpp и пустую функцию main:

    // main.cpp int main()

    Далее скачиваем библиотеку SFML с сайта sfml-dev.org и распаковываем ее. В распакованной библиотеке есть нужные нам папки: include, lib и bin. В свойствах проекта в разделе C/C++ в Additional Include Directories добавляем путь к папке include:

    Там же в разделе Linker в Additional Library Directories добавляем путь к папке lib:

    А из каталога bin нужно скопировать DLL-файлы и сложить их в каталог с exe-файлом нашего проекта:

    Кроме того, в разделе Linker, в подразделе Input, нужно в Additional Dependencies добавить используемые файлы библиотеки. В нашем случае достаточно добавить три файла: sfml-system-d.lib, sfml-window-d.lib и sfml-graphics-d.lib:

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

    Читайте также:
    Лучшие программы родительского контроля для Андроид на русском языке

    Хорошая инструкция по подключению библиотеки SFML к проекту Visual Studio находится на сайте библиотеки.

    Попробуем теперь задействовать библиотеку в нашем проекте. Создадим окно и запустим цикл обработки событий:

    main.cpp

    // main.cpp #include int main() < // Создаем окно размером 600 на 600 и частотой обновления 60 кадров в секунду sf::RenderWindow window(sf::VideoMode(600, 600), «15»); window.setFramerateLimit(60); sf::Event event; while (window.isOpen()) < while (window.pollEvent(event)) < if (event.type == sf::Event::Closed) window.close(); if (event.type == sf::Event::KeyPressed) < // Получаем нажатую клавишу — выполняем соответствующее действие if (event.key.code == sf::Keyboard::Escape) window.close(); >> // Выполняем необходимые действия по отрисовке window.clear(); window.display(); > return 0; >

    Результатом будет квадратное окно размером 600 на 600 пикселей с черным фоном:

    Окно можно закрыть обычным способом мышью, либо через клавишу Esc. Обработчик нажатий клавиш клавиатуры также включен в цикл обработки сообщений.

    Прежде чем приступить к делу, нам понадобится какой-нибудь шрифт для вывода текста на экран. Я для примера взял шрифт TrueType Calibri.

    Теперь можем начинать делать свою игру.

    Создаем новый класс Game:

    Класс будет отвечать за работу игры и за отрисовку игрового поля. Для этого будем наследовать наш класс от классов Drawable и Transformable библиотеки SFML.

    Итак, начинаем описывать наш класс

    #pragma once #include const int SIZE = 4; // Размер игрового поля в плашках const int ARRAY_SIZE = SIZE * SIZE; // Размер массива const int FIELD_SIZE = 500; // Размер игрового поля в пикселях const int CELL_SIZE = 120; // Размер плашки в пикселях enum class Direction < Left = 0, Right = 1, Up = 2, Down = 3 >; class Game : public sf::Drawable, public sf::Transformable < protected: int elements[ARRAY_SIZE]; int empty_index; bool solved; sf::Font font; public: Game(); void Init(); bool Check(); void Move(Direction direction); public: virtual void draw(sf::RenderTarget >;

    Первым делом подключаем библиотеку Graphics:

    #include

    Тут же объявляем некоторые константы, требуемые для игры:

    const int SIZE = 4; // Размер игрового поля в плашках const int ARRAY_SIZE = SIZE * SIZE; // Размер массива плашек const int FIELD_SIZE = 500; // Размер игрового поля в пикселях const int CELL_SIZE = 120; // Размер плашки в пикселях

    Также объявляем свой тип enum, определяющий направление перемещения плашки:

    enum class Direction < Left = 0, Right = 1, Up = 2, Down = 3 >;

    Ну и наконец сам класс:

    class Game : public sf::Drawable, public sf::Transformable < protected: int elements[ARRAY_SIZE]; int empty_index; bool solved; sf::Font font; public: Game(); void Init(); bool Check(); void Move(Direction direction); public: virtual void draw(sf::RenderTarget >;

    Самое главное что у нас в нем есть — это массив elements, содержащий целочисленные значения, соответствующие состоянию игрового поля. Элементы в массиве соответствуют элементам игрового поля слева направо, сверху вниз, то есть первые 4 элемента массива соответствуют первой строке поля, вторые 4 элемента — второй строке и т.д.

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

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

    Теперь напишем реализацию методов нашего класса.

    Game.cpp

    #include «Game.h» Game::Game() < // Подгружаем шрифт для отрисовки элементов font.loadFromFile(«calibri.ttf»); Init(); >void Game::Init() < // Заполняем массив плашек for (int i = 0; i < ARRAY_SIZE — 1; i++) elements[i] = i + 1; // Ставим пустую плашку в правую нижнюю позицию empty_index = ARRAY_SIZE — 1; elements[empty_index] = 0; // Пустая плашка имеет значение = 0 solved = true; >bool Game::Check() < // Проверка собранности головоломки for (unsigned int i = 0; i < ARRAY_SIZE; i++) < if (elements[i] >0 elements[i] != i + 1) return false; > return true; > void Game::Move(Direction direction) < // Вычисляем строку и колонку пустой плашки int col = empty_index % SIZE; int row = empty_index / SIZE; // Проверка на возможность перемещения и вычисление индекса перемещаемой плашки int move_index = -1; if (direction == Direction::Left col < (SIZE — 1)) move_index = empty_index + 1; if (direction == Direction::Right col >0) move_index = empty_index — 1; if (direction == Direction::Up row < (SIZE — 1)) move_index = empty_index + SIZE; if (direction == Direction::Down row >0) move_index = empty_index — SIZE; // Перемещение плашки на место пустой if (empty_index >= 0 move_index >= 0) < int tmp = elements[empty_index]; elements[empty_index] = elements[move_index]; elements[move_index] = tmp; empty_index = move_index; >solved = Check(); > void Game::draw(sf::RenderTarget states.transform *= getTransform(); sf::Color color = sf::Color(200, 100, 200); // Рисуем рамку игрового поля sf::RectangleShape shape(sf::Vector2f(FIELD_SIZE, FIELD_SIZE)); shape.setOutlineThickness(2.f); shape.setOutlineColor(color); shape.setFillColor(sf::Color::Transparent); target.draw(shape, states); // Подготавливаем рамку для отрисовки всех плашек shape.setSize(sf::Vector2f(CELL_SIZE — 2, CELL_SIZE — 2)); shape.setOutlineThickness(2.f); shape.setOutlineColor(color); shape.setFillColor(sf::Color::Transparent); // Подготавливаем текстовую заготовку для отрисовки номеров плашек sf::Text text(«», font, 52); for (unsigned int i = 0; i < ARRAY_SIZE; i++) < shape.setOutlineColor(color); text.setFillColor(color); text.setString(std::to_string(elements[i])); if (solved) < // Решенную головоломку выделяем другим цветом shape.setOutlineColor(sf::Color::Cyan); text.setFillColor(sf::Color::Cyan); >else if (elements[i] == i + 1) < // Номера плашек на своих местах выделяем цветом text.setFillColor(sf::Color::Green); >// Рисуем все плашки, кроме пустой if (elements[i] > 0) < // Вычисление позиции плашки для отрисовки sf::Vector2f position(i % SIZE * CELL_SIZE + 10.f, i / SIZE * CELL_SIZE + 10.f); shape.setPosition(position); // Позицию текста подбирал вручную text.setPosition(position.x + 30.f + (elements[i] < 10 ? 15.f : 0.f), position.y + 25.f); target.draw(shape, states); target.draw(text, states); >> >

    Читайте также:
    Что такое программа comrade

    Конструктор класса загружает шрифт из внешнего файла и вызывает метод инициализации игры:

    Game::Game() < // Подгружаем шрифт для отрисовки элементов font.loadFromFile(«calibri.ttf»); Init(); >

    Метод инициализации игры заполняет массив элементами в правильном порядке и устанавливает признак решенной головоломки:

    void Game::Init() < // Заполняем массив плашек for (int i = 0; i < ARRAY_SIZE — 1; i++) elements[i] = i + 1; // Пустая ячейка — в последнем элементе массива empty_index = ARRAY_SIZE — 1; elements[empty_index] = 0; // Пустая плашка имеет значение = 0 solved = true; >

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

    Следующий метод проверяет, решена ли головоломка и возвращает результат проверки:

    bool Game::Check() < // Проверка собранности головоломки for (unsigned int i = 0; i < ARRAY_SIZE; i++) < if (elements[i] >0 elements[i] != i + 1) return false; > return true; >

    И наконец, метод, реализующий перемещение плашки в игре:

    void Game::Move(Direction direction) < // Вычисляем строку и колонку пустой плашки int col = empty_index % SIZE; int row = empty_index / SIZE; // Проверка на возможность перемещения и вычисление индекса перемещаемой плашки int move_index = -1; if (direction == Direction::Left col < (SIZE — 1)) move_index = empty_index + 1; if (direction == Direction::Right col >0) move_index = empty_index — 1; if (direction == Direction::Up row < (SIZE — 1)) move_index = empty_index + SIZE; if (direction == Direction::Down row >0) move_index = empty_index — SIZE; // Перемещение плашки на место пустой if (empty_index >= 0 move_index >= 0) < int tmp = elements[empty_index]; elements[empty_index] = elements[move_index]; elements[move_index] = tmp; empty_index = move_index; >solved = Check(); >

    Последний метод класса — это метод, который отрисовывает игровое поле:

    void Game::draw(sf::RenderTarget states.transform *= getTransform(); sf::Color color = sf::Color(200, 100, 200); // Рисуем рамку игрового поля sf::RectangleShape shape(sf::Vector2f(FIELD_SIZE, FIELD_SIZE)); shape.setOutlineThickness(2.f); shape.setOutlineColor(color); shape.setFillColor(sf::Color::Transparent); target.draw(shape, states); // Подготавливаем рамку для отрисовки всех плашек shape.setSize(sf::Vector2f(CELL_SIZE — 2, CELL_SIZE — 2)); shape.setOutlineThickness(2.f); shape.setOutlineColor(color); shape.setFillColor(sf::Color::Transparent); // Подготавливаем текстовую заготовку для отрисовки номеров плашек sf::Text text(«», font, 52); for (unsigned int i = 0; i < ARRAY_SIZE; i++) < shape.setOutlineColor(color); text.setFillColor(color); text.setString(std::to_string(elements[i])); if (solved) < // Решенную головоломку выделяем другим цветом shape.setOutlineColor(sf::Color::Cyan); text.setFillColor(sf::Color::Cyan); >else if (elements[i] == i + 1) < // Номера плашек на своих местах выделяем цветом text.setFillColor(sf::Color::Green); >// Рисуем все плашки, кроме пустой if (elements[i] > 0) < // Вычисление позиции плашки для отрисовки sf::Vector2f position(i % SIZE * CELL_SIZE + 10.f, i / SIZE * CELL_SIZE + 10.f); shape.setPosition(position); // Позицию текста подбирал вручную text.setPosition(position.x + 30.f + (elements[i] < 10 ? 15.f : 0.f), position.y + 25.f); // Отрисовываем рамку плашки target.draw(shape, states); // Отрисовываем номер плашки target.draw(text, states); >> >

    В методе отрисовки первым делом применяем трансформацию координат, путем умножения на матрицу трансформирования.

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

    Настало время вернуться к функции main:

    main.cpp

    // main.cpp #include #include «Game.h» int main() < // Создаем окно размером 600 на 600 и частотой обновления 60 кадров в секунду sf::RenderWindow window(sf::VideoMode(600, 600), «15»); window.setFramerateLimit(60); sf::Font font; font.loadFromFile(«calibri.ttf»); // Текст с обозначением клавиш sf::Text text(«F2 — New Game / Esc — Exit / Arrow Keys — Move Tile», font, 20); text.setFillColor(sf::Color::Cyan); text.setPosition(5.f, 5.f); // Создаем объект игры Game game; game.setPosition(50.f, 50.f); sf::Event event; int move_counter = 0; // Счетчик случайных ходов для перемешивания головоломки while (window.isOpen()) < while (window.pollEvent(event)) < if (event.type == sf::Event::Closed) window.close(); if (event.type == sf::Event::KeyPressed) < // Получаем нажатую клавишу — выполняем соответствующее действие if (event.key.code == sf::Keyboard::Escape) window.close(); if (event.key.code == sf::Keyboard::Left) game.Move(Direction::Left); if (event.key.code == sf::Keyboard::Right) game.Move(Direction::Right); if (event.key.code == sf::Keyboard::Up) game.Move(Direction::Up); if (event.key.code == sf::Keyboard::Down) game.Move(Direction::Down); // Новая игра if (event.key.code == sf::Keyboard::F2) < game.Init(); move_counter = 100; >> > // Если счетчик ходов больше нуля, продолжаем перемешивать головоломку if (move_counter— > 0) game.Move((Direction)(rand() % 4)); // Выполняем необходимые действия по отрисовке window.clear(); window.draw(game); window.draw(text); window.display(); > return 0; >

    Вначале подгружаем шрифт и создаем объект Text для вывода на экран строки текста с назначенем клавиш. Далее создаем наш объект игры и устанавливаем позицию поля в точку с координатами (50,50) — так мы делаем отступ от края окна.

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

    Нажатие клавиши F2 — это начало новой игры, так что в обработчике этого события заново инициализируем игру (что приведет к расстановке плашек по своим местам), а также выставляем значение счетчика ходов равным 100. Этот счетчик используется дальше для выполнения ходов в случайных направлениях, пока не обнулится, а плашки не перемешаются. Таким образом мы точно получим решаемое состояние головоломки.

    Вот в общем-то и все, компилируем, собираем, запускаем:

    В этой статье я показал, как можно быстро создать простую игру на C++ с использованием библиотеки SFML. Однако архитектура самой программы далека от идеала. В следующей статье мы попробуем с этим что-нибудь сделать.

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

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