Init commit
This commit is contained in:
commit
83e6c9e1f0
41 changed files with 1455 additions and 0 deletions
69
.gitattributes
vendored
Normal file
69
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
* text=auto
|
||||
|
||||
# Packaging
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
*.iso filter=lfs diff=lfs merge=lfs -text
|
||||
*.sketch filter=lfs diff=lfs merge=lfs -text
|
||||
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Audio formats
|
||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||
*.aiff filter=lfs diff=lfs merge=lfs -text
|
||||
*.aif filter=lfs diff=lfs merge=lfs -text
|
||||
*.mod filter=lfs diff=lfs merge=lfs -text
|
||||
*.it filter=lfs diff=lfs merge=lfs -text
|
||||
*.s3m filter=lfs diff=lfs merge=lfs -text
|
||||
*.xm filter=lfs diff=lfs merge=lfs -text
|
||||
*.wma filter=lfs diff=lfs merge=lfs -text
|
||||
*.wmv filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Video formats
|
||||
*.mov filter=lfs diff=lfs merge=lfs -text
|
||||
*.avi filter=lfs diff=lfs merge=lfs -text
|
||||
*.asf filter=lfs diff=lfs merge=lfs -text
|
||||
*.mpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.mpeg filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
*.webp filter=lfs diff=lfs merge=lfs -text
|
||||
*.webm filter=lfs diff=lfs merge=lfs -text
|
||||
*.mkv filter=lfs diff=lfs merge=lfs -text
|
||||
*.mka filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Documents
|
||||
*.csv filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.doc filter=lfs diff=lfs merge=lfs -text
|
||||
*.docx filter=lfs diff=lfs merge=lfs -text
|
||||
*.xls filter=lfs diff=lfs merge=lfs -text
|
||||
*.xlsx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ppt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pptx filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.ods filter=lfs diff=lfs merge=lfs -text
|
||||
*.odp filter=lfs diff=lfs merge=lfs -text
|
||||
*.pds filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Fonts
|
||||
*.woff filter=lfs diff=lfs merge=lfs -text
|
||||
*.woff2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.eof filter=lfs diff=lfs merge=lfs -text
|
||||
*.otf filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Images
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||
*.bmp filter=lfs diff=lfs merge=lfs -text
|
||||
*.svg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# Metrics
|
||||
*.jmx filter=lfs diff=lfs merge=lfs -text
|
||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
0
CHANGELOG
Normal file
0
CHANGELOG
Normal file
1
LICENSE
Normal file
1
LICENSE
Normal file
|
|
@ -0,0 +1 @@
|
|||
# School 21 License
|
||||
162
README.md
Normal file
162
README.md
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# BrickGame Тетрис
|
||||
Резюме: в данном проекте тебе предстоит реализовать игру «Тетрис» на языке программирования С с использованием структурного подхода.
|
||||
|
||||
## Содержание
|
||||
|
||||
- [BrickGame Тетрис](#brickgame-тетрис)
|
||||
- [Содержание](#содержание)
|
||||
- [Введение](#введение)
|
||||
- [Chapter I](#chapter-i)
|
||||
- [Общая информация](#общая-информация)
|
||||
- [BrickGame](#brickgame)
|
||||
- [История тетриса](#история-тетриса)
|
||||
- [Конечные автоматы](#конечные-автоматы)
|
||||
- [Фроггер](#фроггер)
|
||||
- [Тетрис](#тетрис)
|
||||
- [Chapter II](#chapter-ii)
|
||||
- [Требования к проекту](#требования-к-проекту)
|
||||
- [Часть 1. Основное задание](#часть-1-основное-задание)
|
||||
- [Часть 2. Дополнительно. Подсчет очков и рекорд в игре](#часть-2-дополнительно-подсчет-очков-и-рекорд-в-игре)
|
||||
- [Часть 3. Дополнительно. Механика уровней](#часть-3-дополнительно-механика-уровней)
|
||||
|
||||
## Введение
|
||||
|
||||
Для реализации игры "Тетрис" проект должен состоять из двух частей: библиотеки, реализующей логику работы игры, которую можно подключать к различным GUI в будущем, и терминального интерфейса, разработанного с использованием библиотеки `ncurses`. Логика работы библиотеки должна быть реализована с использованием конечных автоматов, одно из возможных описаний которого будет дано ниже.
|
||||
|
||||
## Chapter I <div id="chapter-i"></div>
|
||||
## Общая информация
|
||||
### BrickGame
|
||||
|
||||
BrickGame - популярная портативная консоль 90-ых годов с несколькими ~~тысячами~~ встроенными играми, разработанная в Китае. Изначально была копией разработанной в СССР и выпущенной Nintendo в рамках платформы GameBoy игры «Тетрис», но включала в себя также и множество других игр, которые добавлялись с течением времени. Консоль имела небольшой экранчик с игровым полем размера 10х20, представляющим из себя матрицу «пикселей». Справа от поля находилось табло с цифровой индикацией состояния текущей игры, рекордами и прочей дополнительной информацией. Самыми распространенными играми на BrickGame были: тетрис, танки, гонки, фроггер и змейка.
|
||||
|
||||

|
||||
|
||||
### История тетриса
|
||||
|
||||
«Тетрис» был написан Алексеем Пажитновым 6 июня 1984 года на компьютере Электроника-60. Игра представляла собой головоломку, построенную на использовании геометрических фигур «тетрамино», состоящих из четырех квадратов. Первая коммерческая версия игры была выпущена в Америке в 1987 году. В последующие годы «Тетрис» был портирован на множество различных устройств, в том числе мобильные телефоны, калькуляторы и карманные персональные компьютеры.
|
||||
|
||||
Наибольшую популярность приобрела реализация «Тетриса» для игровой консоли Game Boy и видеоприставки NES. Но кроме нее существуют различные версии игры. Например, есть версия с трехмерными фигурами или дуэльная версия, в которой два игрока получают одинаковые фигуры и пытаются обойти друг друга по очкам.
|
||||
|
||||
### Конечные автоматы
|
||||
|
||||
Конечный автомат (КА) в теории алгоритмов — математическая абстракция, модель дискретного устройства, имеющего один вход, один выход и в каждый момент времени находящегося в одном состоянии из множества возможных.
|
||||
|
||||
При работе на вход КА последовательно поступают входные воздействия, а на выходе КА формирует выходные сигналы. Переход из одного внутреннего состояния КА в другое может происходить не только от внешнего воздействия, но и самопроизвольно.
|
||||
|
||||
КА можно использовать для описания алгоритмов, позволяющих решать те или иные задачи, а также для моделирования практически любого процесса. Несколько примеров:
|
||||
|
||||
- Логика искусственного интеллекта для игр;
|
||||
- Синтаксический и лексический анализ;
|
||||
- Сложные прикладные сетевые протоколы;
|
||||
- Потоковая обработка данных.
|
||||
|
||||
Ниже представлены примеры использования КА для формализации игровой логики нескольких игр из BrickGame.
|
||||
|
||||
### Фроггер
|
||||
|
||||

|
||||
|
||||
«Фроггер» - одна из поздних игр, выходящих на консолях Brickgame. Игра представляет собой игровое поле, по которому движутся бревна, и, перепрыгивая по ним, игроку необходимо перевести лягушку с одного берега на другой. Если игрок попадает в воду или лягушка уходит за пределы игрового поля, то лягушка погибает. Игра завершается, когда игрок доводит лягушку до другого берега или погибает последняя лягушка.
|
||||
|
||||
Для формализации логики данной игры можно представить следующий вариант конечного автомата:
|
||||
|
||||

|
||||
|
||||
Данный КА имеет следующие состояния:
|
||||
|
||||
- Старт - состояние, в котором игра ждет, пока игрок нажмет кнопку готовности к игре.
|
||||
- Спавн - состояние, в котором создается очередная лягушка.
|
||||
- Перемещение - основное игровое состояние с обработкой ввода от пользователя - движение лягушки по полосе влево/право или прыжки вперед/назад.
|
||||
- Сдвиг - состояние, которое наступает после истечения таймера, при котором сдвигаются все объекты на полосах вправо, вместе с лягушкой.
|
||||
- Столкновение - состояние, которое наступает, если после прыжка лягушка попадает в воду или после смещения бревен лягушка оказывается за пределами игрового поля.
|
||||
- Достигнут другой берег - состояние, которое наступает при достижении лягушкой верхней другого берега.
|
||||
- Игра окончена - состояние, которое наступает после достижения другого берега или смерти последней лягушки.
|
||||
|
||||
Пример реализации фроггера с использованием КА вы можете найти в папке `code-samples`.
|
||||
|
||||
### Тетрис
|
||||
|
||||

|
||||
|
||||
«Тетрис», наверное, одна из самых популярных игр для консоли Brickgame. Нередко и саму консоль называют тетрисом. Цель игры - в наборе очков за построение линий из генерируемых игрой блоков. Очередной блок, сгенерированный игрой, начинает опускаться вниз по игровому полю, пока не достигнет нижней границы или не столкнется с другим блоком. Пользовать может поворачивать фигуры и перемещать их по горизонтали, стараясь составлять ряды. После заполнения ряд уничтожается, игрок получает очки, а блоки, находящиеся выше заполненного ряда опускаются вниз. Игра заканчивается, когда очередная фигура останавливается в самом верхнем ряду.
|
||||
|
||||
Для формализации логики данной игры можно представить следующий вариант конечного автомата:
|
||||
|
||||

|
||||
|
||||
Данный КА состоит из следующих состояний:
|
||||
|
||||
- Старт - состояние, в котором игра ждет, пока игрок нажмет кнопку готовности к игре.
|
||||
- Спавн - состояние, в которое переходит игра при создании очередного блока и выбора следующего блока для спавна.
|
||||
- Перемещение - основное игровое состояние с обработкой ввода от пользователя - поворот блоков/перемещение блоков по горизонтали.
|
||||
- Сдвиг - состояние, в которое переходит игра после истечения таймера. В нем текущий блок перемещается вниз на один уровень.
|
||||
- Соединение - состояние, в которое преходит игра после «соприкосновения» текущего блока с уже упавшими или с землей. Если образуются заполненные линии, то она уничтожается и остальные блоки смещаются вниз. Если блок остановился в самом верхнем ряду, то игра переходит в состояние «игра окончена».
|
||||
- Игра окончена - игра окончена.
|
||||
|
||||
## Chapter II <div id="chapter-ii"></div>
|
||||
## Требования к проекту
|
||||
|
||||
### Часть 1. Основное задание
|
||||
|
||||
Тебе необходимо реализовать программу BrickGame v1.0 aka Tetris:
|
||||
|
||||
- Программа должна быть разработана на языке Си стандарта C11 с использованием компилятора gcc.
|
||||
- Программа должна состоять из двух частей: библиотеки, реализующей логику игры тетрис, и терминального интерфейса с использованием библиотеки `ncurses`.
|
||||
- Для формализации логики игры должен быть использован конечный автомат.
|
||||
- Библиотека должна иметь функцию, принимающая на вход ввод пользователя, и функцию, выдающую матрицу, которая описывает текущее состояние игрового поля, при каждом ее изменении.
|
||||
- Код библиотеки программы должен находиться в папке `src/brick_game/tetris`.
|
||||
- Код с интерфейсом программы должен находиться в папке `src/gui/cli`.
|
||||
- Сборка программы должна быть настроена с помощью Makefile со стандартным набором целей для GNU-программ: all, install, uninstall, clean, dvi, dist, test, gcov_report. Установка должна вестись в любой другой произвольный каталог.
|
||||
- Программа должна быть разработана в соответствии с принципами структурного программирования.
|
||||
- При написании кода придерживайся Google Style.
|
||||
- Должно быть обеспечено покрытие библиотеки unit-тестами, с помощью библиотеки `check` (тесты должны проходить на ОС Darwin/Ubuntu). Покрытие библиотеки с логикой игры тестами должно составлять не меньше 80 процентов.
|
||||
- В игре должны присутствовать следующие механики:
|
||||
- Вращение фигур;
|
||||
- Перемещение фигуры по горизонтали;
|
||||
- Ускорение падения фигуры (при нажатии кнопки фигура перемещается до конца вниз);
|
||||
- Показ следующей фигуры;
|
||||
- Уничтожение заполненных линий;
|
||||
- Завершение игры при достижении верхней границы игрового поля;
|
||||
- В игре должны присутствовать все виды фигур, показанных на картинке ниже.
|
||||
- Для управления добавь поддержку всех кнопок, предусмотренных на физической консоли:
|
||||
- Начало игры,
|
||||
- Пауза,
|
||||
- Завершение игры,
|
||||
- Стрелка влево - движение фигуры влево,
|
||||
- Стрелка вправо - движение фигуры вправо,
|
||||
- Стрелка вниз - падение фигуры,
|
||||
- Стрелка вверх - ни используется в данной игре,
|
||||
- Действие (вращение фигуры).
|
||||
- Игровое поле должно соответствовать размерам игрового поля консоли - десять «пикселей» в ширину и двадцать «пикселей» в высоту.
|
||||
- Фигура, после достижения нижней границы поля или соприкосновения с другой фигурой, должна остановиться. После этого происходит генерация следующей фигуры, показанной на превью.
|
||||
- Интерфейс библиотеки должен соответствовать описанию, которое находится в materials/library-specification.md.
|
||||
- Пользовательский интерфейс должен поддерживать отрисовку игрового поля и дополнительной информации.
|
||||
- Подготовь в любом формате диаграмму, описывающую используемый КА (его состояния и все возможные переходы).
|
||||
|
||||
Используемые фигуры:
|
||||
|
||||

|
||||
|
||||
### Часть 2. Дополнительно. Подсчет очков и рекорд в игре
|
||||
|
||||
Добавь в игру следующие механики:
|
||||
|
||||
- подсчет очков;
|
||||
- хранение максимального количества очков.
|
||||
|
||||
Данная информация должна передаваться и выводиться пользовательским интерфейсом в боковой панели. Максимальное количество очков должно храниться в файле или встраиваемой СУБД и сохраняться между запусками программы.
|
||||
|
||||
Максимальное количество очков должно изменяться во время игры, если пользователь во время игры превышает текущий показатель максимального количества набранных очков.
|
||||
|
||||
Начисление очков будет происходить следующим образом:
|
||||
|
||||
- 1 линия - 100 очков;
|
||||
- 2 линии - 300 очков;
|
||||
- 3 линии - 700 очков;
|
||||
- 4 линии - 1500 очков.
|
||||
|
||||
### Часть 3. Дополнительно. Механика уровней
|
||||
|
||||
Добавь в игру механику уровней. Каждый раз, когда игрок набирает 600 очков, уровень увеличивается на 1. Повышение уровня увеличивает скорость движения фигур. Максимальное количество уровней - 10.
|
||||
|
||||
💡 [Нажми сюда](https://forms.yandex.ru/cloud/65d4a02673cee73bdc52da80/)**, чтобы поделиться с нами обратной связью на этот проект**. Это анонимно и поможет нашей команде сделать твоё обучение лучше.
|
||||
0
code-samples/.gitkeep
Normal file
0
code-samples/.gitkeep
Normal file
11
code-samples/frogger/README.md
Normal file
11
code-samples/frogger/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Frogger
|
||||
## Controls
|
||||
### Movement
|
||||
Arrow keys (up, right, down, left)
|
||||
### Exit
|
||||
Esc key
|
||||
## Installation
|
||||
```git clone XXX && cd frogger```
|
||||
## Make
|
||||
```make frogger``` makes switch-case realisation of fsm which you can observe in file src/fsm.c \
|
||||
```make frogger_fsmtable``` makes fsm realisation based on matrix of pointers on state-control functions which you can observe in file src/fsm_matrix.c
|
||||
54
code-samples/frogger/inc/defines.h
Normal file
54
code-samples/frogger/inc/defines.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define WIN_INIT(time) {\
|
||||
initscr();\
|
||||
noecho();\
|
||||
curs_set(0);\
|
||||
keypad(stdscr, TRUE);\
|
||||
timeout(time);\
|
||||
}
|
||||
|
||||
#define GET_USER_INPUT getch()
|
||||
|
||||
#define PRINT_FROG(x, y) mvprintw(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), "@")
|
||||
#define MVPRINTW(y, x, ...) mvprintw(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), __VA_ARGS__)
|
||||
#define MVADDCH(y, x, c) mvaddch(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), c)
|
||||
#define CLEAR_BACKPOS(y, x) mvaddch(BOARDS_BEGIN + (y), BOARDS_BEGIN + (x), ' ')
|
||||
|
||||
#define YOU_WON "tests/game_progress/you_won.txt"
|
||||
#define YOU_LOSE "tests/game_progress/you_lose.txt"
|
||||
#define LEVEL_DIR "tests/levels/level_"
|
||||
#define INTRO_MESSAGE "Press ENTER to start!"
|
||||
#define INTRO_MESSAGE_LEN 21
|
||||
#define LEVEL_CNT 5
|
||||
#define LEVELNAME_MAX 25
|
||||
|
||||
#define MAX_WIN_COUNT 10
|
||||
|
||||
#define ROWS_MAP 21
|
||||
#define COLS_MAP 90
|
||||
|
||||
#define BOARDS_BEGIN 2
|
||||
|
||||
#define FROGSTART_X (BOARD_M / 2)
|
||||
#define FROGSTART_Y (BOARD_N)
|
||||
#define INITIAL_TIMEOUT 150
|
||||
|
||||
#define BOARD_N (ROWS_MAP + MAP_PADDING * 2)
|
||||
#define BOARD_M 30
|
||||
#define HUD_WIDTH 12
|
||||
#define MAP_PADDING 3
|
||||
|
||||
#define BANNER_N 10
|
||||
#define BANNER_M 100
|
||||
|
||||
#define SUCCESS 0
|
||||
#define ERROR 1
|
||||
|
||||
#define NO_INPUT -1
|
||||
|
||||
#define ESCAPE 27
|
||||
#define ENTER_KEY 10
|
||||
|
||||
#endif
|
||||
20
code-samples/frogger/inc/frog_backend.h
Normal file
20
code-samples/frogger/inc/frog_backend.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef FROGGER_BACKEND_H
|
||||
#define FROGGER_BACKEND_H
|
||||
|
||||
#include <ncurses.h>
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
#include "string.h"
|
||||
|
||||
int lvlproc(board_t *map, game_stats_t *stats);
|
||||
void add_proggress(board_t *map);
|
||||
void stats_init(game_stats_t *stats);
|
||||
void frogpos_init(player_pos *frog);
|
||||
void fill_finish(char *finish_line);
|
||||
void shift_map(board_t *map);
|
||||
|
||||
bool check_collide(player_pos *frog, board_t *map);
|
||||
bool check_finish_state(player_pos *frog, board_t *map);
|
||||
bool check_level_compl(board_t *map);
|
||||
|
||||
#endif
|
||||
17
code-samples/frogger/inc/frog_frontend.h
Normal file
17
code-samples/frogger/inc/frog_frontend.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef FROGGER_FRONTEND_H
|
||||
#define FROGGER_FRONTEND_H
|
||||
|
||||
#include <string.h>
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
|
||||
void print_overlay(void);
|
||||
void print_rectangle(int top_y, int bottom_y, int left_x, int right_x);
|
||||
void print_stats(game_stats_t *stats);
|
||||
void print_board(board_t *game, player_pos *frog);
|
||||
void print_cars(board_t *game);
|
||||
void print_finished(board_t *game);
|
||||
void print_banner(game_stats_t *stats);
|
||||
int read_banner(game_stats_t *stats, banner_t *banner);
|
||||
|
||||
#endif
|
||||
11
code-samples/frogger/inc/frogger.h
Normal file
11
code-samples/frogger/inc/frogger.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef FROGGER_H
|
||||
#define FROGGER_H
|
||||
|
||||
#include <locale.h>
|
||||
#include "fsm.h"
|
||||
#include "frog_backend.h"
|
||||
#include "frog_frontend.h"
|
||||
|
||||
void game_loop();
|
||||
|
||||
#endif
|
||||
35
code-samples/frogger/inc/fsm.h
Normal file
35
code-samples/frogger/inc/fsm.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef FSM_H
|
||||
#define FSM_H
|
||||
|
||||
#include "defines.h"
|
||||
#include "objects.h"
|
||||
#include "frog_backend.h"
|
||||
#include "frog_frontend.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
START = 0,
|
||||
SPAWN,
|
||||
MOVING,
|
||||
SHIFTING,
|
||||
REACH,
|
||||
COLLIDE,
|
||||
GAMEOVER,
|
||||
EXIT_STATE
|
||||
} frog_state;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MOVE_UP = 0,
|
||||
MOVE_DOWN,
|
||||
MOVE_RIGHT,
|
||||
MOVE_LEFT,
|
||||
ESCAPE_BTN,
|
||||
ENTER_BTN,
|
||||
NOSIG
|
||||
} signals;
|
||||
|
||||
signals get_signal(int user_input);
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos);
|
||||
|
||||
#endif
|
||||
33
code-samples/frogger/inc/objects.h
Normal file
33
code-samples/frogger/inc/objects.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef OBJECTS_H
|
||||
#define OBJECTS_H
|
||||
|
||||
#include <ncurses.h>
|
||||
#include "defines.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} player_pos;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char finish[BOARD_M + 2];
|
||||
char ways[ROWS_MAP + 2][COLS_MAP + 2];
|
||||
} board_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int score;
|
||||
int level;
|
||||
int speed;
|
||||
int lives;
|
||||
int won;
|
||||
} game_stats_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char matrix[BANNER_N + 1][BANNER_M + 1];
|
||||
} banner_t;
|
||||
|
||||
#endif
|
||||
16
code-samples/frogger/makefile
Normal file
16
code-samples/frogger/makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
CC := gcc
|
||||
CFLAGS := -I inc -std=c99 -Wall -Werror -Wpedantic
|
||||
OBJS_FSMSWITCHCASE := out/frogger.o out/fsm.o out/backend.o out/frontend.o
|
||||
OBJS_FSMTABLE := out/frogger.o out/fsm_matrix.o out/backend.o out/frontend.o
|
||||
|
||||
frogger: $(OBJS_FSMSWITCHCASE)
|
||||
$(CC) $(CFLAGS) $^ -o $@ -lncurses
|
||||
|
||||
frogger_fsmtable: $(OBJS_FSMTABLE)
|
||||
$(CC) $(CFLAGS) $^ -o $@ -lncurses
|
||||
|
||||
out/%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
$(RM) out/*.o frogger frogger_fsmtable
|
||||
0
code-samples/frogger/out/.gitkeep
Normal file
0
code-samples/frogger/out/.gitkeep
Normal file
102
code-samples/frogger/src/backend.c
Normal file
102
code-samples/frogger/src/backend.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#include "frog_backend.h"
|
||||
|
||||
int lvlproc(board_t *map, game_stats_t *stats)
|
||||
{
|
||||
timeout(INITIAL_TIMEOUT - stats->speed * 15);
|
||||
|
||||
char levelname[LEVELNAME_MAX + 1] = { 0 };
|
||||
|
||||
sprintf(levelname, LEVEL_DIR"%d.txt", stats->level);
|
||||
|
||||
FILE *level = fopen(levelname, "r");
|
||||
|
||||
int rc = SUCCESS;
|
||||
|
||||
if (level)
|
||||
{
|
||||
for (int i = 0; i < ROWS_MAP && !rc; i++)
|
||||
{
|
||||
if (fgets(map->ways[i], COLS_MAP + 2, level) == NULL)
|
||||
rc = ERROR;
|
||||
else
|
||||
map->ways[i][strcspn(map->ways[i], "\n")] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
fclose(level);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void add_proggress(board_t *map)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
for (; map->finish[position] == '0'; position++) ;
|
||||
|
||||
for (int progress_cnt = BOARD_M / 5; progress_cnt > 0; progress_cnt--)
|
||||
map->finish[position++] = '0';
|
||||
}
|
||||
|
||||
bool check_finish_state(player_pos *frog, board_t *map)
|
||||
{
|
||||
bool rc = FALSE;
|
||||
|
||||
if (frog->y == 1)
|
||||
rc = TRUE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool check_level_compl(board_t *map)
|
||||
{
|
||||
bool rc = TRUE;
|
||||
for (int i = 0; i < BOARD_M && rc; i++)
|
||||
if (map->finish[i] != '0')
|
||||
rc = FALSE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool check_collide(player_pos *frog, board_t *map)
|
||||
{
|
||||
bool rc = FALSE;
|
||||
|
||||
if (frog->y > MAP_PADDING && frog->y < ROWS_MAP + MAP_PADDING + 1 && \
|
||||
map->ways[frog->y - MAP_PADDING - 1][frog->x - 1] == ']')
|
||||
rc = TRUE;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void frogpos_init(player_pos *frog)
|
||||
{
|
||||
frog->x = FROGSTART_X;
|
||||
frog->y = FROGSTART_Y;
|
||||
}
|
||||
|
||||
void fill_finish(char *finish_line)
|
||||
{
|
||||
for (int i = 0; i < BOARD_M; i++)
|
||||
finish_line[i] = ' ';
|
||||
|
||||
finish_line[BOARD_M] = '\0';
|
||||
}
|
||||
|
||||
void stats_init(game_stats_t *stats)
|
||||
{
|
||||
stats->level = 1;
|
||||
stats->score = 0;
|
||||
stats->speed = 1;
|
||||
stats->lives = 9;
|
||||
stats->won = FALSE;
|
||||
}
|
||||
|
||||
void shift_map(board_t *map)
|
||||
{
|
||||
for (int i = 1; i < ROWS_MAP; i += 2)
|
||||
{
|
||||
memmove(&map->ways[i][1], &map->ways[i][0], COLS_MAP * sizeof(char));
|
||||
map->ways[i][0] = map->ways[i][COLS_MAP];
|
||||
}
|
||||
}
|
||||
36
code-samples/frogger/src/frogger.c
Normal file
36
code-samples/frogger/src/frogger.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "frogger.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
WIN_INIT(50);
|
||||
setlocale(LC_ALL, "");
|
||||
print_overlay();
|
||||
game_loop();
|
||||
endwin();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void game_loop()
|
||||
{
|
||||
board_t map;
|
||||
game_stats_t stats;
|
||||
player_pos frog;
|
||||
|
||||
bool break_flag = TRUE;
|
||||
int signal = 0;
|
||||
frog_state state = START;
|
||||
|
||||
stats_init(&stats);
|
||||
|
||||
while (break_flag)
|
||||
{
|
||||
if (state == GAMEOVER || state == EXIT_STATE)
|
||||
break_flag = FALSE;
|
||||
|
||||
sigact(get_signal(signal), &state, &stats, &map, &frog);
|
||||
|
||||
if (state == MOVING || state == START)
|
||||
signal = GET_USER_INPUT;
|
||||
}
|
||||
}
|
||||
137
code-samples/frogger/src/frontend.c
Normal file
137
code-samples/frogger/src/frontend.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "frog_frontend.h"
|
||||
|
||||
void print_overlay(void)
|
||||
{
|
||||
print_rectangle(0, BOARD_N + 1, 0, BOARD_M + 1);
|
||||
print_rectangle(0, BOARD_N + 1, BOARD_M + 2, BOARD_M + HUD_WIDTH + 3);
|
||||
|
||||
print_rectangle(1, 3, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(4, 6, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(7, 9, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
print_rectangle(10, 12, BOARD_M + 3, BOARD_M + HUD_WIDTH + 2);
|
||||
|
||||
MVPRINTW(2, BOARD_M + 5, "LEVEL");
|
||||
MVPRINTW(5, BOARD_M + 5, "SCORE");
|
||||
MVPRINTW(8, BOARD_M + 5, "SPEED");
|
||||
MVPRINTW(11, BOARD_M + 5, "LIVES");
|
||||
|
||||
MVPRINTW(BOARD_N / 2, (BOARD_M - INTRO_MESSAGE_LEN) / 2 + 1, INTRO_MESSAGE);
|
||||
}
|
||||
|
||||
void print_rectangle(int top_y, int bottom_y, int left_x, int right_x)
|
||||
{
|
||||
MVADDCH(top_y, left_x, ACS_ULCORNER);
|
||||
|
||||
int i = left_x + 1;
|
||||
|
||||
for (;i < right_x; i++)
|
||||
MVADDCH(top_y, i, ACS_HLINE);
|
||||
MVADDCH(top_y, i, ACS_URCORNER);
|
||||
|
||||
for (int i = top_y + 1; i < bottom_y; i++)
|
||||
{
|
||||
MVADDCH(i, left_x, ACS_VLINE);
|
||||
MVADDCH(i, right_x, ACS_VLINE);
|
||||
}
|
||||
|
||||
MVADDCH(bottom_y, left_x, ACS_LLCORNER);
|
||||
i = left_x + 1;
|
||||
for (;i < right_x; i++)
|
||||
MVADDCH(bottom_y, i, ACS_HLINE);
|
||||
MVADDCH(bottom_y, i, ACS_LRCORNER);
|
||||
}
|
||||
|
||||
void print_stats(game_stats_t *stats)
|
||||
{
|
||||
MVPRINTW(2, BOARD_M + 12, "%d", stats->level);
|
||||
MVPRINTW(5, BOARD_M + 12, "%d", stats->score);
|
||||
MVPRINTW(8, BOARD_M + 12, "%d", stats->speed);
|
||||
MVPRINTW(11, BOARD_M + 12, "%d", stats->lives);
|
||||
}
|
||||
|
||||
void print_board(board_t *game, player_pos *frog)
|
||||
{
|
||||
print_cars(game);
|
||||
PRINT_FROG(frog->x, frog->y);
|
||||
}
|
||||
|
||||
void print_cars(board_t *game)
|
||||
{
|
||||
for(int i = MAP_PADDING + 1; i < BOARD_N - MAP_PADDING + 1; i++)
|
||||
{
|
||||
if (i % 2 == (MAP_PADDING + 1) % 2)
|
||||
{
|
||||
for (int j = 1; j < BOARD_M + 1; j++)
|
||||
MVADDCH(i, j, ACS_BLOCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 1; j < BOARD_M + 1; j++)
|
||||
{
|
||||
if (game->ways[i - MAP_PADDING - 1][j - 1] == '0')
|
||||
MVADDCH(i, j, ' ');
|
||||
else
|
||||
MVADDCH(i, j, ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_finished(board_t *game)
|
||||
{
|
||||
for (int i = 0; i < BOARD_M; i++)
|
||||
{
|
||||
if (game->finish[i] == '0')
|
||||
MVADDCH(1, i + 1, ACS_BLOCK);
|
||||
else
|
||||
MVADDCH(1, i + 1, ' ');
|
||||
}
|
||||
}
|
||||
void print_banner(game_stats_t *stats)
|
||||
{
|
||||
banner_t banner;
|
||||
|
||||
memset(banner.matrix, 0, (BANNER_N + 1) * (BANNER_M + 1));
|
||||
|
||||
clear();
|
||||
|
||||
if (!(read_banner(stats, &banner)))
|
||||
{
|
||||
for (int i = 0; i < BANNER_N; i++)
|
||||
for (int j = 0; j < BANNER_M; j++)
|
||||
if (banner.matrix[i][j] == '#')
|
||||
MVADDCH(i, j, ACS_BLOCK);
|
||||
else
|
||||
MVADDCH(i, j, ' ');
|
||||
refresh();
|
||||
napms(2000);
|
||||
}
|
||||
}
|
||||
|
||||
int read_banner(game_stats_t *stats, banner_t *banner)
|
||||
{
|
||||
int rc = SUCCESS;
|
||||
FILE *file = NULL;
|
||||
|
||||
if (stats->lives)
|
||||
file = fopen(YOU_WON, "r");
|
||||
else
|
||||
file = fopen(YOU_LOSE, "r");
|
||||
|
||||
if (file)
|
||||
{
|
||||
for (int i = 0; i < BANNER_N - 1 && !rc; i++)
|
||||
{
|
||||
if (fgets(banner->matrix[i], BANNER_M + 2, file) == NULL)
|
||||
rc = ERROR;
|
||||
else
|
||||
banner->matrix[i][strcspn(banner->matrix[i], "\n")] = '\0';
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
rc = ERROR;
|
||||
|
||||
return rc;
|
||||
}
|
||||
186
code-samples/frogger/src/fsm.c
Normal file
186
code-samples/frogger/src/fsm.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
#include "fsm.h"
|
||||
|
||||
// This is a finite state machine realisation based on switch-case statement.
|
||||
/*
|
||||
Function sigact() describes state switching logic.
|
||||
States are checked in order specified in function sigact().
|
||||
It enters a state-case which it corresponds to, where begins another switch-case statement.
|
||||
Inner switch-case statement is looking for a signal given by get_signal().
|
||||
After finding it makes some action and switches state to the next one.
|
||||
|
||||
Pros:
|
||||
1) Less memory usage.
|
||||
Cons:
|
||||
1) A lot of codelines.
|
||||
*/
|
||||
|
||||
signals get_signal(int user_input)
|
||||
{
|
||||
signals rc = NOSIG;
|
||||
|
||||
if (user_input == KEY_UP)
|
||||
rc = MOVE_UP;
|
||||
else if (user_input == KEY_DOWN)
|
||||
rc = MOVE_DOWN;
|
||||
else if (user_input == KEY_LEFT)
|
||||
rc = MOVE_LEFT;
|
||||
else if (user_input == KEY_RIGHT)
|
||||
rc = MOVE_RIGHT;
|
||||
else if (user_input == ESCAPE)
|
||||
rc = ESCAPE_BTN;
|
||||
else if (user_input == ENTER_KEY)
|
||||
rc = ENTER_BTN;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void moveup(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->y != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->y -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void movedown(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->y != BOARD_N)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->y += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void moveright(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->x != BOARD_M)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->x++;
|
||||
}
|
||||
}
|
||||
|
||||
void moveleft(player_pos *frog_pos)
|
||||
{
|
||||
if (frog_pos->x != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(frog_pos->y, frog_pos->x);
|
||||
frog_pos->x--;
|
||||
}
|
||||
}
|
||||
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case START:
|
||||
switch (sig)
|
||||
{
|
||||
case ENTER_BTN:
|
||||
*state = SPAWN;
|
||||
break;
|
||||
case ESCAPE_BTN:
|
||||
*state = EXIT_STATE;
|
||||
break;
|
||||
default:
|
||||
*state = START;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case SPAWN:
|
||||
if (stats->level > LEVEL_CNT)
|
||||
*state = GAMEOVER;
|
||||
else
|
||||
if (!lvlproc(map, stats))
|
||||
{
|
||||
fill_finish(map->finish);
|
||||
print_finished(map);
|
||||
frogpos_init(frog_pos);
|
||||
*state = MOVING;
|
||||
}
|
||||
else
|
||||
*state = EXIT_STATE;
|
||||
|
||||
break;
|
||||
case MOVING:
|
||||
switch (sig)
|
||||
{
|
||||
case MOVE_UP:
|
||||
moveup(frog_pos);
|
||||
break;
|
||||
case MOVE_DOWN:
|
||||
movedown(frog_pos);
|
||||
break;
|
||||
case MOVE_RIGHT:
|
||||
moveright(frog_pos);
|
||||
break;
|
||||
case MOVE_LEFT:
|
||||
moveleft(frog_pos);
|
||||
break;
|
||||
case ESCAPE_BTN:
|
||||
*state = EXIT_STATE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (*state != EXIT_STATE)
|
||||
{
|
||||
if (check_collide(frog_pos, map))
|
||||
*state = COLLIDE;
|
||||
else if (check_finish_state(frog_pos, map))
|
||||
*state = REACH;
|
||||
else
|
||||
*state = SHIFTING;
|
||||
}
|
||||
|
||||
break;
|
||||
case SHIFTING:
|
||||
shift_map(map);
|
||||
|
||||
if (check_collide(frog_pos, map))
|
||||
*state = COLLIDE;
|
||||
else
|
||||
{
|
||||
*state = MOVING;
|
||||
print_board(map, frog_pos);
|
||||
print_stats(stats);
|
||||
}
|
||||
|
||||
break;
|
||||
case REACH:
|
||||
stats->score += 1;
|
||||
add_proggress(map);
|
||||
if (check_level_compl(map))
|
||||
{
|
||||
stats->level++;
|
||||
stats->speed++;
|
||||
*state = SPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
frogpos_init(frog_pos);
|
||||
print_finished(map);
|
||||
*state = MOVING;
|
||||
}
|
||||
|
||||
break;
|
||||
case COLLIDE:
|
||||
if (stats->lives)
|
||||
{
|
||||
stats->lives--;
|
||||
frogpos_init(frog_pos);
|
||||
*state = MOVING;
|
||||
}
|
||||
else
|
||||
*state = GAMEOVER;
|
||||
break;
|
||||
case GAMEOVER:
|
||||
print_banner(stats);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
209
code-samples/frogger/src/fsm_matrix.c
Normal file
209
code-samples/frogger/src/fsm_matrix.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
#include "fsm.h"
|
||||
|
||||
// This is a finite state machine realisation based on matrix of "actions".
|
||||
/*
|
||||
Function sigact() takes an action function from fsm_table.
|
||||
Game state defines an index of line in matrix (where to get).
|
||||
User signal defines an index of column in matrix (what to get).
|
||||
|
||||
Pros:
|
||||
1) By instantly taking needed action, speed of processing is higher than switch-case realisation.
|
||||
2) Code is easy to read.
|
||||
3) Flexible (easy to add new state)
|
||||
Cons:
|
||||
1) More memory usage.
|
||||
*/
|
||||
|
||||
typedef struct game_params
|
||||
{
|
||||
game_stats_t *stats;
|
||||
frog_state *state;
|
||||
board_t *map;
|
||||
player_pos *frog_pos;
|
||||
bool *break_flag;
|
||||
} params_t;
|
||||
|
||||
typedef void (*action)(params_t *prms);
|
||||
|
||||
void spawn(params_t *prms);
|
||||
void moveup(params_t *prms);
|
||||
void movedown(params_t *prms);
|
||||
void moveright(params_t *prms);
|
||||
void moveleft(params_t *prms);
|
||||
void shifting(params_t *prms);
|
||||
void reach(params_t *prms);
|
||||
void collide(params_t *prms);
|
||||
void gameover(params_t *prms);
|
||||
void exitstate(params_t *prms);
|
||||
void check(params_t *prms);
|
||||
|
||||
action fsm_table[8][7] = {
|
||||
{NULL, NULL, NULL, NULL, exitstate, spawn, NULL},
|
||||
{spawn, spawn, spawn, spawn, spawn, spawn, spawn},
|
||||
{moveup, movedown, moveright, moveleft, exitstate, check, check},
|
||||
{shifting, shifting, shifting, shifting, shifting, shifting, shifting},
|
||||
{reach, reach, reach, reach, reach, reach, reach},
|
||||
{collide, collide, collide, collide, collide, collide, collide},
|
||||
{gameover, gameover, gameover, gameover, gameover, gameover, gameover},
|
||||
{exitstate, exitstate, exitstate, exitstate, exitstate, exitstate, exitstate}
|
||||
};
|
||||
|
||||
void sigact(signals sig, frog_state *state, game_stats_t *stats, board_t *map, player_pos *frog_pos)
|
||||
{
|
||||
params_t prms;
|
||||
prms.stats = stats;
|
||||
prms.state = state;
|
||||
prms.map = map;
|
||||
prms.frog_pos = frog_pos;
|
||||
|
||||
action act = fsm_table[*state][sig];
|
||||
|
||||
if (act)
|
||||
act(&prms);
|
||||
}
|
||||
|
||||
signals get_signal(int user_input)
|
||||
{
|
||||
signals rc = NOSIG;
|
||||
|
||||
if (user_input == KEY_UP)
|
||||
rc = MOVE_UP;
|
||||
else if (user_input == KEY_DOWN)
|
||||
rc = MOVE_DOWN;
|
||||
else if (user_input == KEY_LEFT)
|
||||
rc = MOVE_LEFT;
|
||||
else if (user_input == KEY_RIGHT)
|
||||
rc = MOVE_RIGHT;
|
||||
else if (user_input == ESCAPE)
|
||||
rc = ESCAPE_BTN;
|
||||
else if (user_input == ENTER_KEY)
|
||||
rc = ENTER_BTN;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void shifting(params_t *prms)
|
||||
{
|
||||
shift_map(prms->map);
|
||||
|
||||
if (check_collide(prms->frog_pos, prms->map))
|
||||
*prms->state = COLLIDE;
|
||||
else
|
||||
{
|
||||
*prms->state = MOVING;
|
||||
print_board(prms->map, prms->frog_pos);
|
||||
print_stats(prms->stats);
|
||||
}
|
||||
}
|
||||
|
||||
void check(params_t *prms)
|
||||
{
|
||||
if (check_collide(prms->frog_pos, prms->map))
|
||||
*prms->state = COLLIDE;
|
||||
else if (check_finish_state(prms->frog_pos, prms->map))
|
||||
*prms->state = REACH;
|
||||
else
|
||||
*prms->state = SHIFTING;
|
||||
}
|
||||
|
||||
void spawn(params_t *prms)
|
||||
{
|
||||
if (prms->stats->level > LEVEL_CNT)
|
||||
*prms->state = GAMEOVER;
|
||||
else
|
||||
{
|
||||
if (!lvlproc(prms->map, prms->stats))
|
||||
{
|
||||
fill_finish(prms->map->finish);
|
||||
print_finished(prms->map);
|
||||
frogpos_init(prms->frog_pos);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
else
|
||||
*prms->state = EXIT_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
void moveup(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->y != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->y -= 2;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void movedown(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->y != BOARD_N)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->y += 2;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void moveright(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->x != BOARD_M)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->x++;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void moveleft(params_t *prms)
|
||||
{
|
||||
if (prms->frog_pos->x != 1)
|
||||
{
|
||||
CLEAR_BACKPOS(prms->frog_pos->y, prms->frog_pos->x);
|
||||
prms->frog_pos->x--;
|
||||
}
|
||||
|
||||
check(prms);
|
||||
}
|
||||
|
||||
void reach(params_t *prms)
|
||||
{
|
||||
prms->stats->score += 1;
|
||||
add_proggress(prms->map);
|
||||
if (check_level_compl(prms->map))
|
||||
{
|
||||
prms->stats->level++;
|
||||
prms->stats->speed++;
|
||||
*prms->state = SPAWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
frogpos_init(prms->frog_pos);
|
||||
print_finished(prms->map);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
}
|
||||
|
||||
void collide(params_t *prms)
|
||||
{
|
||||
if (prms->stats->lives)
|
||||
{
|
||||
prms->stats->lives--;
|
||||
frogpos_init(prms->frog_pos);
|
||||
*prms->state = MOVING;
|
||||
}
|
||||
else
|
||||
*prms->state = GAMEOVER;
|
||||
}
|
||||
|
||||
void gameover(params_t *prms)
|
||||
{
|
||||
print_banner(prms->stats);
|
||||
}
|
||||
|
||||
void exitstate(params_t *prms)
|
||||
{
|
||||
*prms->state = EXIT_STATE;
|
||||
}
|
||||
0
data-samples/.gitkeep
Normal file
0
data-samples/.gitkeep
Normal file
0
datasets/.gitkeep
Normal file
0
datasets/.gitkeep
Normal file
0
materials/.gitkeep
Normal file
0
materials/.gitkeep
Normal file
20
materials/7 principles of structural programming.md
Normal file
20
materials/7 principles of structural programming.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Принципы структурного программирования
|
||||
|
||||
Становление и развитие структурного программирования связано с именем Эдсгера Дейкстры.
|
||||
* Принцип 1. Следует отказаться от использования оператора безусловного перехода goto.
|
||||
* Принцип 2. Любая программа строится из трёх базовых управляющих конструкций: последовательность, ветвление, цикл.
|
||||
* Принцип 3. В программе базовые управляющие конструкции могут быть вложены друг в друга произвольным образом. Никаких других средств управления последовательностью выполнения операций не предусматривается.
|
||||
* Принцип 4. Повторяющиеся фрагменты программы можно оформить в виде подпрограмм (процедур и функций). Таким же образом (в виде подпрограмм) можно оформить логически целостные фрагменты программы, даже если они не повторяются.
|
||||
* Принцип 5. Каждую логически законченную группу инструкций следует оформить как блок. Блоки являются основой структурного программирования.
|
||||
* Принцип 6. Все перечисленные конструкции должны иметь один вход и один выход.
|
||||
* Принцип 7. Разработка программы ведётся пошагово, методом «сверху вниз» (top-down method).
|
||||
|
||||
Следствия и дополнения вышеизложенных принципов:
|
||||
|
||||
1. Запрет на использование глобальных переменных
|
||||
2. Не более одного выхода из функции. Исключение составляет предварительная проверка аргументов функции.
|
||||
3. Не более одного выхода из цикла - это может быть как условие, так и ключевое слово break
|
||||
4. Вложенность любых блоков не должна превышать 4
|
||||
5. Размер функций ограничен по строкам и составляет 40-50 строк
|
||||
|
||||

|
||||
32
materials/from_developers.txt
Normal file
32
materials/from_developers.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Message from developers:
|
||||
Hello, dear friend!
|
||||
Let's play a game.
|
||||
Something like the good old text-based adventure games with elements of a puzzle.
|
||||
Each Task is a challenge, usually some kind of a hurdle you need to overcome.
|
||||
Only those who tackle them all will be able to move further.
|
||||
|
||||
Below are several tips to help you find your way:
|
||||
1. During the entire journey, you will be accompanied by the feeling of uncertainty and a severe shortage of information: THAT'S OK. It's a part of the game. Remember that the information in the repository and Google are always there for you. Just like other players. Communicate. Search. Collect. Do not be afraid to make a mistake.
|
||||
2. There may be a game inside the game, and another game inside it. That's normal. Just like in real life. Recursion is beautiful.
|
||||
3. Levels can be very different from one another. That's normal. It's a part of the game. You can't just learn one recipe and apply it everywhere. The only way to achieve the goal is by continuously learning and adapting.
|
||||
4. It's a multiplayer game, even if it doesn't seem like it in the beginning.
|
||||
5. You will, however, be able to get through most of it on your own.
|
||||
6. Be careful with information sources. Check. Think. Analyze. Compare. Do not trust.
|
||||
7. Pay attention to the text of the task. Think. Check.
|
||||
8. If the task seems unclear or impossible–it only seems like it. Take your time, sit down in silence or with your favorite music. Get back to the task in 10–15 minutes and read the entire text once again.
|
||||
9. If tip #8 hasn't helped–search for a guide. You are surrounded by many wanderers just like you and they will be happy to help you find the exit.
|
||||
10. Watch the time! It's deceitful. You have to complete at least one challenge a day!
|
||||
11. Be attentive and do not miss important things. Check the repository carefully!
|
||||
12. Always push only to the develop branch! The master branch will be ignored. Work in the src directory.
|
||||
13. Remember that each task undergoes a series of checks: code style check, static analyzer check, check for correct work with memory, check with a set of autotests, check with a checklist. Be careful.
|
||||
14. You will come across different tasks on your way. The tasks marked with the asterisk (*) are only for the most reckless ones. They are more difficult and not compulsory. But if you complete them, you will gain extra experience and knowledge.
|
||||
15. Some things may seem important but they are actually not.
|
||||
16. Remember that ultimately the fact of completing the challenge is not as important as HOW you complete it.
|
||||
17. The main goal of our journey is to understand what "HOW" means.
|
||||
18. Separate the wheat from the chaff.
|
||||
19. Divide and rule. Decompose.
|
||||
20. Think about the main thing (good code, obviously). Move from the general to the specific.
|
||||
21. Do not cheat, do not try to deceive the system and others. First of all, you will deceive yourself.
|
||||
22. Do not write off, but if you use help - always figure it out to the end. Otherwise, your journey will not make any sense.
|
||||
23. Check "materials" folder often. There can be a lot of useful things there!
|
||||
24. Reread these tips several times.
|
||||
33
materials/from_developers_rus.txt
Normal file
33
materials/from_developers_rus.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
От разработчиков:
|
||||
Здравствуй, дорогой друг!
|
||||
Мы предлагаем сыграть тебе в игру.
|
||||
Игру, в духе старых добрых текстовых квестовых игр-бродилок с элементами головоломки.
|
||||
Каждый Task — это очередное испытание, обычно некоторое препятствие, которое необходимо преодолеть.
|
||||
Лишь тот, кто пройдет все — сможет двинуться дальше.
|
||||
|
||||
Ниже приведено несколько напутствий, они помогут тебе найти свой путь:
|
||||
1. Всю дорогу тебя будет сопровождать чувство неопределенности и острого дефицита информации: ЭТО НОРМАЛЬНО. Это часть игры. Не забывай, что информация в репозитории и Google — всегда с тобой. Как и другие игроки. Общайся. Ищи. Собирай. Не бойся ошибиться.
|
||||
2. В игре может быть другая игра, в которой будет еще одна. Это нормально. Все как в жизни. Рекурсия — это красиво.
|
||||
3. Уровни могут сильно отличаться друг от друга. Это нормально. Это часть игры. Нельзя выучить один рецепт и его везде применять. Лишь непрерывно обучаясь и адаптируясь ты сможешь достигнуть цели.
|
||||
4. Наша игра — многопользовательская, даже если сначала тебе покажется иначе.
|
||||
5. Хотя, большую часть пути ты сможешь преодолеть и один.
|
||||
6. Будь внимателен к источникам информации. Проверяй. Думай. Анализируй. Сравнивай. Не доверяй.
|
||||
7. Будь внимателен к тексту задания. Думай. Проверяй.
|
||||
8. Если задание кажется непонятным или невыполнимым — это только так кажется. Просто посиди спокойно, в тишине, или включи любимую музыку. Вернись к заданию через 10-15 минут и перечитай его полностью.
|
||||
9. Если п.8 не помог — поищи проводника. Вокруг тебя — много таких же путников, как ты, они с радостью помогут найти тебе выход.
|
||||
10. Следи за временем! Оно коварно. В день ты должен преодолевать минимум одно испытание!
|
||||
11. Будь внимателен — и не упусти важное. Внимательно изучай репозиторий!
|
||||
12. Всегда делай push только в ветку develop! Ветка master будет проигнорирована. Работай в директории src.
|
||||
13. Помни, что каждое задание проходит ряд проверок: проверка на стиль кода, проверка статическим анализатором, проверка на корректную работу с памятью, проверка набором автотестов, проверка с помощью чеклиста. Будь внимателен.
|
||||
14. На твоем пути тебе встретятся разные задания. Те, что помечены звездочкой (*) — подходят только для самых отчаянных. Они с повышенной сложностью и в целом не являются обязательными к выполнению. Но если ты их сделаешь, то получишь дополнительный опыт и знания.
|
||||
15. Иногда то, что кажется важным — не есть важное.
|
||||
16. Помни, в конечном счете, факт преодоления препятствия не так важен, как то, КАК ты его преодолел.
|
||||
17. Главная цель нашего путешествия — осознать, что такое “КАК”.
|
||||
18. Отделяй зерна от плевел.
|
||||
19. Разделяй и властвуй. Декомпозируй.
|
||||
20. Думай о главном (о хорошем коде, разумеется). Следуй от общего к частному.
|
||||
21. Не жульничай, не пытайся обмануть систему и окружающих. В первую очередь ты обманешь себя.
|
||||
22. Не списывай, а если пользуешься помощью - всегда разбирайся до конца, почему, как и зачем. Иначе твое путешествие не будет иметь никакого смысла.
|
||||
23. Почаще заглядывай в папку materials. Там может быть много полезного!
|
||||
24. Перечитай напутствия несколько раз.
|
||||
|
||||
67
materials/instructions_for_testing.md
Normal file
67
materials/instructions_for_testing.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Instructions for running tests.
|
||||
|
||||
In addition to testing for correct output data, the autotest system will check your program and its source code for the
|
||||
following points:
|
||||
|
||||
* **Style tests.** To check how much the beauty of your code meets the standards, for example, you can test your code
|
||||
using the _clang-format_ utility. The ```materials/linters``` folder contains the ```.clang-format``` file, which
|
||||
contains the necessary settings for the style test. This configuration file extends its action to all files that lie
|
||||
with it in the directory or in the directories below. So in order for these settings to apply to your source code
|
||||
files, copy ```.clang-format``` to the ```src``` folder. \
|
||||
\
|
||||
To run the style check, run the following command: \
|
||||
```clang-format -n src/sourcefile_name.c``` \
|
||||
\
|
||||
To download _clang-format_, enter one of the following commands in the terminal: \
|
||||
```brew install clang-format``` \
|
||||
or if you have root rights (for Ubuntu / Linux Mint / Debian) \
|
||||
```sudo apt install clang-format```
|
||||
|
||||
Required version of clang-format: \
|
||||
**Mac** 14.0.5 \
|
||||
**Linux** 13.0.1
|
||||
|
||||
Google Style: https://google.github.io/styleguide/cppguide.html
|
||||
|
||||
|
||||
* **Test for correct operation with memory.** When writing C programs, it is very important to watch for memory leaks.
|
||||
To do this the _valgrind_ utility is quite often used in Unix-like operating systems. However, OS X has some troubles
|
||||
with _valgrind_ support, so it is possible to use the _leaks_ utility instead. We will not go into the mechanism of
|
||||
operation of these utilities now — if you are interested, you can read about it on Google.
|
||||
|
||||
**_LEAKS_**
|
||||
|
||||
To run your executable file using this utility, type in the terminal: \
|
||||
```leaks -atExit -- ./main.out | grep LEAK:```
|
||||
|
||||
Pay your attention that there is ```| grep LEAK:``` command. We use it to short leaks output to see only lines with
|
||||
leaks if they are there. If you want to see the whole output, just remove this command.
|
||||
|
||||
When you run your executable file using _leaks_ you may see an error:
|
||||
> dyld: could not load inserted library ‘/usr/local/lib/libLeaksAtExit.dylib’ because image not found
|
||||
|
||||
It’s because _leaks_ did not find _libLeaksAtExit.dylib_ library. \
|
||||
You need to type the following commands in this case.
|
||||
```sh
|
||||
cd /usr/local/lib
|
||||
sudo ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib
|
||||
```
|
||||
|
||||
_Additionally:_ \
|
||||
Use the ```-exclude``` option of _leaks_ to filter out leaks in functions with known memory leaks. This option helps
|
||||
reduce the amount of extra information reported by _leaks_.
|
||||
|
||||
**_VALGRIND_**
|
||||
|
||||
To install it on your computer, type one of the following commands: \
|
||||
```brew install valgrind``` \
|
||||
or if you have root rights (for Ubuntu / Linux Mint / Debian) \
|
||||
```sudo apt install valgrind``` \
|
||||
To run your executable file using this utility, type in the terminal: \
|
||||
```valgrind --tool=memcheck --leak-check=yes. /main. out```
|
||||
|
||||
It is strongly recommended not to use _valgrind_ utility in OS X, use _leaks_ utility instead.
|
||||
|
||||
* **Build test.** The program can be checked for correct build on a test system environment. This will require _Docker_
|
||||
installed. If the system has a docker, then you can go to the `materials/build` directory and run the run.sh script
|
||||
from there. The script will wrap your solution in docker and run it along with a typical build script.
|
||||
67
materials/instructions_for_testing_rus.md
Normal file
67
materials/instructions_for_testing_rus.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Инструкция по запуску тестов.
|
||||
|
||||
Помимо тестов на корректные выходные данные система автотестирования будет проверять вашу программу и ее исходный код по
|
||||
следующим пунктам:
|
||||
|
||||
* **Стилевые тесты.** Чтобы проверить, насколько красота вашего кода соответствует стандартам, вы можете протестировать
|
||||
ваш код с помощью утилиты _clang-format_. В папке ```materials/linters``` лежит файл ```.clang-format```, который
|
||||
содержит необходимые настройки для стилевого теста. Данный конфигурационный файл распространяет свое действие на все
|
||||
файлы, которые лежат с ним в директории или в директориях ниже. Поэтому, чтобы данные настройки применились к вашим
|
||||
файлам с исходным кодом, скопируйте ```.clang-format``` в папку ```src```. \
|
||||
\
|
||||
Чтобы запустить проверку на стиль, выполните следующую команду: \
|
||||
```clang-format -n src/sourcefile_name.c``` \
|
||||
\
|
||||
Чтобы скачать _clang-format_, введите в терминал одну из следующих команд: \
|
||||
```brew install clang-format``` \
|
||||
или, если у вас есть root-права (для Ubuntu / Linux Mint / Debian) \
|
||||
```sudo apt install clang-format```
|
||||
|
||||
Необходимая версия clang-format: \
|
||||
**Mac** 14.0.5 \
|
||||
**Linux** 13.0.1
|
||||
|
||||
Google Style: https://google.github.io/styleguide/cppguide.html
|
||||
|
||||
|
||||
* **Тест на корректную работу с памятью.** При написании C-программ очень важно следить за утечками памяти. Для этого в
|
||||
Unix-подобных операционных системах довольно часто используют утилиту _valgrind_. Однако, на OS X имеются проблемы с
|
||||
поддержкой _valgrind_, поэтому вместо нее можно использовать утилиту _leaks_. Вдаваться в механизм работы этих утилит
|
||||
мы сейчас не будем — если интересно, можете почитать в гугле.
|
||||
|
||||
**_LEAKS_**
|
||||
|
||||
Чтобы запустить ваш исполняемый файл с помощью этой утилиты, наберите в терминале: \
|
||||
```leaks -atExit -- ./main.out | grep LEAK:```
|
||||
|
||||
Обратите внимание на команду ```| grep LEAK:```. Мы используем ее для короткого вывода, чтобы видеть только линии с
|
||||
утечками, если они есть. Если вы хотите увидеть весь вывод, просто удалите эту команду.
|
||||
|
||||
При запуске исполняемого файла с помощью _leaks_ может появиться сообщение об ошибке:
|
||||
> dyld: could not load inserted library ‘/usr/local/lib/libLeaksAtExit.dylib’ because image not found
|
||||
|
||||
Ошибка возникает из-за того, что _leaks_ не может найти библиотеку _libLeaksAtExit.dylib_. \
|
||||
В этом случае вам необходимо ввести следующие команды:
|
||||
```sh
|
||||
cd /usr/local/lib
|
||||
sudo ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib
|
||||
```
|
||||
|
||||
_Дополнительно:_ \
|
||||
Используйте флаг ```-exclude``` утилиты _leaks_ для того, чтобы отфильтровать утечки в функциях, где известно об
|
||||
утечках памяти. Этот флаг позволяет уменьшить количество посторонней информации, сообщаемой _leaks_.
|
||||
|
||||
**_VALGRIND_**
|
||||
|
||||
Чтобы установить _valgrind_ на компьютер, введите одну из следующих команд: \
|
||||
```brew install valgrind``` \
|
||||
или, если у вас есть root-права (для Ubuntu / Linux Mint / Debian) \
|
||||
```sudo apt install valgrind``` \
|
||||
Чтобы запустить ваш исполняемый файл с помощью этой утилиты, наберите в терминале: \
|
||||
```valgrind --tool=memcheck --leak-check=yes ./main.out```
|
||||
|
||||
Не рекомендуется использовать _valgrind_ на OS X, вместо нее лучше использовать _leaks_.
|
||||
|
||||
* **Тест сборки.** Программу можно проверить на корректность сборки на тестовой системе. Для этого потребуется
|
||||
установленный _Docker_. Если на системе есть докер, то можно зайти в директорию `materials/build` и запустить оттуда
|
||||
скрипт run.sh. Скрипт обернет ваше решение в докер и запустит его вместе с типовым сценарием сборки.
|
||||
38
materials/library-specification.md
Normal file
38
materials/library-specification.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Спецификация для библиотеки игры из коллекции игр BrickGame
|
||||
|
||||
Это задание является первым из серии BrickGame. Всего будет четыре проекта, в каждой - своя игра и свои технологии. Но помимо разработки новых проектов, необходимо будет поддерживать и старые игры, и добавлять поддержку новых игр в старые проекты. В этот раз интерфейс будет консольным, в следующем - десктопный, и так далее. Для того чтобы поддерживать старые и новые игры необходимо заранее определиться как будет устроено АПИ интерфейсов и библиотек, чтобы в дальнейшем не приходилось переписывать уже сданные проекты.
|
||||
|
||||
Игровое поле представляется как матрица размерностью десять на двадцать. Каждый элемент матрицы соответствует "пикселю" игрового поля и может находится в одном из двух состояний: пустой и заполненный. Кроме игрового поля у каждой игры есть дополнительная информация, которая выводится в боковой панели справа от игрового поля. Для дополнительной информации, не используемой во время игры, предусмотреть заглушки.
|
||||
|
||||
Каждая библиотека с игрой должна иметь функцию, принимающую на вход пользовательский ввод. У консоли имеется восемь физических кнопок: начало игры, пауза, завершение игры, действие и четыре стрелочки.
|
||||
|
||||
Функция `userInput` принимает на вход пользовательское действие `action` и дополнительный параметр `hold`, который отвечает за зажатие клавиши.
|
||||
|
||||
Функция `updateCurrentState` предназначена для получения данных для отрисовки в интерфейсе. Она возвращает структуру, содержащую информацию о текущем состоянии игры. Например, для тетриса истечение таймера приводит к смещению фигуры вниз на один ряд. Эта функция должна вызываться из интерфейса с некоторой периодичностью для поддержания интерфейса в актуальном состоянии.
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
Start,
|
||||
Pause,
|
||||
Terminate,
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
Action
|
||||
} UserAction_t;
|
||||
|
||||
typedef struct {
|
||||
int **field;
|
||||
int **next;
|
||||
int score;
|
||||
int high_score;
|
||||
int level;
|
||||
int speed;
|
||||
int pause;
|
||||
} GameInfo_t;
|
||||
|
||||
void userInput(UserAction_t action, bool hold);
|
||||
|
||||
GameInfo_t updateCurrentState();
|
||||
```
|
||||
2
materials/linters/.clang-format
Normal file
2
materials/linters/.clang-format
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
BasedOnStyle: Google
|
||||
14
materials/topics-list.md
Normal file
14
materials/topics-list.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Topoics list
|
||||
|
||||
Hello, student of School21!😉
|
||||
|
||||
To make it easier for you to navigate the material, we have prepared a list of topics that you will learn in this project.
|
||||
|
||||
We will study:
|
||||
|
||||
- finite-state machine;
|
||||
- working with matrixes;
|
||||
- working with files;
|
||||
- working with GUI library.
|
||||
|
||||
Now, knowing what awaits you in this project, you can slowly begin to study the topics listed above.😇
|
||||
12
materials/topics-list_RUS.md
Normal file
12
materials/topics-list_RUS.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Topics list
|
||||
|
||||
Привет, участник Школы21!😉
|
||||
|
||||
Чтобы тебе было проще, мы подготовили список тем, на которые следует обратить особое внимание при выполнении данного проекта:
|
||||
|
||||
- конечные автоматы;
|
||||
- работа с матрицами;
|
||||
- работа с файлами;
|
||||
- работа с графическими интерфейсами.
|
||||
|
||||
Теперь, когда известен список тем, знания которых потребуются в проекте, можешь приступать к изучению.😇
|
||||
1
misc/.gitkeep
Normal file
1
misc/.gitkeep
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
0
misc/images/.gitkeep
Normal file
0
misc/images/.gitkeep
Normal file
3
misc/images/brickgame-console.jpg
Normal file
3
misc/images/brickgame-console.jpg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7c3ad78d45f6acd89f8d4c8e5bd01bfcc3565f802495d73662ceaca3501a0b49
|
||||
size 124914
|
||||
3
misc/images/frogger-game.png
Normal file
3
misc/images/frogger-game.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cb30e549097709224b1100f78096aae265a7b214dcdae2ae3cfe227ab8bea090
|
||||
size 87620
|
||||
3
misc/images/frogger.jpg
Normal file
3
misc/images/frogger.jpg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:633f701f1bb78d2d54a5221a402be10cb2dbc3d18b421e8e6630be7334a2efd7
|
||||
size 18930
|
||||
3
misc/images/tetris-game.png
Normal file
3
misc/images/tetris-game.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f3df7672c1cad5cdd3ed3c85ad6cfb08461f214e2618088646c6ac5c6a3d3205
|
||||
size 119669
|
||||
3
misc/images/tetris-pieces.png
Normal file
3
misc/images/tetris-pieces.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aea868cc51c81efe1481a1a53a1cce91d8a93ab09980a29c192252bde9a1a2f8
|
||||
size 35555
|
||||
3
misc/images/tetris.png
Normal file
3
misc/images/tetris.png
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2697426741be706663b4ab4e53eaa6eec922ecfb4bb253c79bdb2638f3130ae8
|
||||
size 30960
|
||||
0
src/.gitkeep
Normal file
0
src/.gitkeep
Normal file
Loading…
Add table
Add a link
Reference in a new issue