Как написать консольную игру на си

Как работает псевдо-3D графика в старых играх? Пишем на C++ консольную игру шутер от первого лица, используя метод «бросания лучей» (Ray casting).

Кстати, у меня есть замечательная школа математики для программистов – Академия вектозавров. Первую, бесплатную, главу пройти обязательно всем! :)

Сегодня я расскажу о том, как можно написать шутер от первого лица, используя псевдо-3D графику. Такая графика повсеместно использовалась в старых игрушках типа Wolfenstein 3D, Doom, Doom II и др.
Вдохновлением для написания данной статьи стал видеоролик Code-It-Yourself! First Person Shooter (Quick and Simple C++) с YouTube канала OneLoneCoder. Мне настолько понравилась идея и простота её реализации, что я просто не мог сдержаться, чтобы не рассказать о ней!
На моём YouTube канале есть видео с наглядными объяснениями этой темы:

Как выглядела Wolfenstein 3D:

А вот, что мы получим в итоге:

Можно ожидать, что для написания чего то подобного понадобятся тысячи строчек кода и недели работы, но эта программа содержит всего 180 строчек кода!
Я не буду много останавливаться на коде и углубляться в детали программирования, а только попытаюсь объяснить основную идею и показать результаты. На GitHub’e автора кода есть все исходники.

Вывод в консоль

Начнём с того, что просто создадим необходимые переменные:


int nScreenWidth = 120; // Ширина консольного окна
int nScreenHeight = 40; // Высота консольного окна

float fPlayerX = 1.0f; // Координата игрока по оси X
float fPlayerY = 1.0f; // Координата игрока по оси Y
float fPlayerA = 0.0f; // Направление игрока

int nMapHeight = 16; // Высота игрового поля
int nMapWidth = 16; // Ширина игрового поля

float fFOV = 3.14159 / 3; // Угол обзора (поле видимости)
float fDepth = 30.0f; // Максимальная дистанция обзора

Для вывода текста на экран мы не будем использовать стандартную функцию cout, ведь она слишком медленная. Вместо этого будет использоваться следующая конструкция:


wchar_t *screen = new wchar_t[nScreenWidth*nScreenHeight + 1]; // Массив для записи в буфер
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); // Буфер экрана
SetConsoleActiveScreenBuffer(hConsole); // Настройка консоли
DWORD dwBytesWritten = 0; // Для дебага

screen[nScreenWidth * nScreenHeight] = ''; // Последний символ - окончание строки
WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0, 0 }, &dwBytesWritten); // Запись в буфер

Это просто метод вывода, поэтому на нем сильно не останавливаемся.
Теперь все готово к написанию кода. Игровую карту мы будем хранить в виде двумерного массива. Решётка будет означать стену, а точка — пустое пространство:


wstring map; // Строковый массив
map += L"################";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"################";

Вдумчивый читатель может заметить, что это же никакое не 3D, и будет абсолютно прав. Третьего измерения не будет, но мы создадим его иллюзию.

Вернёмся к написанию алгоритма. Игровой цикл и вся заготовка будет выглядеть так:


using namespace std;
#include <iostream>
#include <Windows.h>

int nScreenWidth = 120; // Ширина консольного окна
int nScreenHeight = 40; // Высота консольного окна

float fPlayerX = 1.0f; // Координата игрока по оси X
float fPlayerY = 1.0f; // Координата игрока по оси Y
float fPlayerA = 0.0f; // Направление игрока

int nMapHeight = 16; // Высота игрового поля
int nMapWidth = 16; // Ширина игрового поля

float fFOV = 3.14159 / 3; // Угол обзора (поле видимости)
float fDepth = 30.0f; // Максимальная дистанция обзора

int main()
{
wchar_t *screen = new wchar_t[nScreenWidth*nScreenHeight + 1]; // Массив для записи в буфер
HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); // Буфер экрана
SetConsoleActiveScreenBuffer(hConsole); // Настройка консоли
DWORD dwBytesWritten = 0; // Для дебага

wstring map; // Строковый массив
map += L"################";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"#..............#";
map += L"################";

while (1) // Игровой цикл
{
// Повторяющиеся действия
}
return 0;
}

Мы будем строить изображение в два цикла, изменяя во внешнем цикле координату по (X), а во внутреннем — по (Y).
Напомню, что в консоли, как и полагается, вывод текста происходит слева направо с переносом вниз. Так что координатная сетка будет выглядеть следующим образом:

Управление

У нас будут две степени свободы: движение вперёд-назад и поворот.
Реализовать изменение этих параметров не составляет никакого труда:


auto tp1 = chrono::system_clock::now(); // Переменные для подсчета
auto tp2 = chrono::system_clock::now(); // пройденного времени

while (1) // Игровой цикл
{
tp2 = chrono::system_clock::now();
chrono::duration <float> elapsedTime = tp2 - tp1;
tp1 = tp2;
float fElapsedTime = elapsedTime.count();

if (GetAsyncKeyState((unsigned short)'A') & 0x8000)
fPlayerA -= (1.5f) * fElapsedTime; // Клавишей "A" поворачиваем по часовой стрелке

if (GetAsyncKeyState((unsigned short)'D') & 0x8000)
fPlayerA += (1.5f) * fElapsedTime; // Клавишей "D" поворачиваем против часовой стрелки

if (GetAsyncKeyState((unsigned short)'W') & 0x8000) // Клавишей "W" идём вперёд
{
fPlayerX += sinf(fPlayerA) * 5.0f * fElapsedTime;
fPlayerY += cosf(fPlayerA) * 5.0f * fElapsedTime;

if (map[(int)fPlayerY*nMapWidth + (int)fPlayerX] == '#') { // Если столкнулись со стеной, но откатываем шаг
fPlayerX -= sinf(fPlayerA) * 5.0f * fElapsedTime;
fPlayerY -= cosf(fPlayerA) * 5.0f * fElapsedTime;
}
}

if (GetAsyncKeyState((unsigned short)'S') & 0x8000) // Клавишей "S" идём назад
{
fPlayerX -= sinf(fPlayerA) * 5.0f * fElapsedTime;
fPlayerY -= cosf(fPlayerA) * 5.0f * fElapsedTime;
if (map[(int)fPlayerY*nMapWidth + (int)fPlayerX] == '#') { // Если столкнулись со стеной, но откатываем шаг
fPlayerX += sinf(fPlayerA) * 5.0f * fElapsedTime;
fPlayerY += cosf(fPlayerA) * 5.0f * fElapsedTime;
}
}

// Повторяющиеся действия
}

Ray casting

Мы будем строить изображение в два цикла, изменяя во внешнем цикле координату по (X), а во внутреннем — по (Y).
Для того, чтобы построить часть изображения — вертикальную полоску на экране, нужно найти расстояние от наблюдателя до предмета, который попадет в эту полоску.
У наблюдателя есть некоторый угол обзора (theta), в который могут попасть предметы. Расстояние до них мы и будем пытаться найти:

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

Чтобы не попадать в бесконечный цикл нужно ограничить радиус видимости. Если стенка не попала в радиус видимости, то мы будем воспринимать это как отсутствие препятствия в данном направлении.

Чем дальше находится стенка, тем меньше места она должна занимать на экране и тем больше места будут занимать небо и земля.
Такой метод определения расстояния до предмета в заданном направлении называется методом «бросания лучей» (Ray casting).
В статье на Википедии есть иллюстрация применения такого метода:

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


for (int x = 0; x < nScreenWidth; x++) // Проходим по всем X
{
float fRayAngle = (fPlayerA - fFOV/2.0f) + ((float)x / (float)nScreenWidth) * fFOV; // Направление луча
// Находим расстояние до стенки в направлении fRayAngle

float fDistanceToWall = 0.0f; // Расстояние до препятствия в направлении fRayAngle
bool bHitWall = false; // Достигнул ли луч стенку

float fEyeX = sinf(fRayAngle); // Координаты единичного вектора fRayAngle
float fEyeY = cosf(fRayAngle);

while (!bHitWall && fDistanceToWall < fDepth) // Пока не столкнулись со стеной
{ // Или не вышли за радиус видимости
fDistanceToWall += 0.1f;

int nTestX = (int)(fPlayerX + fEyeX*fDistanceToWall); // Точка на игровом поле
int nTestY = (int)(fPlayerY + fEyeY*fDistanceToWall); // в которую попал луч

if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight)
{ // Если мы вышли за зону
bHitWall = true;
fDistanceToWall = fDepth;
}
else if (map[nTestY*nMapWidth + nTestX] == '#')
bHitWall = true;

for (int y = 0; y < nScreenHeight; y++) // При заданном X проходим по всем Y
{
// В этом цикле рисуется вертикальная полоска
}
}

По сути, у нас теперь есть все для того, чтобы создать иллюзию 3D. Имея расстояние (d) до стенки в данном направлении, мы можем вычислить её высоту относительно экрана. Как это сделать? Нужно понять как изменяется относительная высота объектов при изменении расстояния до них:

Из подобия треугольников сразу получаем зависимость относительной высоты кота от расстояния до него. Мы строим проекцию в точку (глаз), при которой мы получаем перспективу:

Видно, что если расстояние (d) равно (d’), высота кота относительно экрана равна его «настоящей» высоте. То есть расстояние (d’), на котором находится экран от наблюдателя — это расстояние на котором размеры объектов не искажаются.
Для отрисовки полоски нужно задать две координаты по Y: первая — это координата, где начинается стенка и заканчивается небо (идем сверху вниз и сначала прорисовываем небо), а вторая указывает, где заканчивается стенка и начинается пол.
Сделаем эти две точки симметричными относительно центра по высоте, задав их следующими формулами:
$$
y_1 = frac{h’}{2}left(1-frac{1}{d}right) qquad (1)
$$
$$
y_2 = frac{h’}{2}left(1+frac{1}{d}right) qquad (2)
$$
Видно, что если расстояние (d) до стенки становится большим, то эти точки сходятся в центр и высота полоски становится маленькой. То есть небо и пол занимают почти все место.
Если расстояние становится маленьким, то эти точки уходят вниз и полоска увеличивается. Легко убедиться, что формулы (1) и (2) задают размер стенки, как и положено, обратно пропорциональным расстоянию до неё. Действительно:
$$
b’=h’ — 2frac{h’}{2}(1-frac{1}{d}) = frac{h’}{d}
$$
То есть размер стенки в данном случае равен размеру экрана, а экран расположен на расстоянии 1 метр от наблюдателя.

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

Теперь подробно разберём, как реализовать это:


for (int x = 0; x < nScreenWidth; x++) // Проходим по всем X
{
float fRayAngle = (fPlayerA - fFOV/2.0f) + ((float)x / (float)nScreenWidth) * fFOV; // Направление луча

float fDistanceToWall = 0.0f; // Расстояние до препятствия в направлении fRayAngle
bool bHitWall = false; // Достигнул ли луч стенку

float fEyeX = sinf(fRayAngle); // Координаты единичного вектора fRayAngle
float fEyeY = cosf(fRayAngle);

while (!bHitWall && fDistanceToWall < fDepth) // Пока не столкнулись со стеной
{ // Или не вышли за радиус видимости
fDistanceToWall += 0.1f;

int nTestX = (int)(fPlayerX + fEyeX*fDistanceToWall); // Точка на игровом поле
int nTestY = (int)(fPlayerY + fEyeY*fDistanceToWall); // в которую попал луч

if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight)
{ // Если мы вышли за карту, то дальше смотреть нет смысла - фиксируем соударение на расстоянии видимости
bHitWall = true;
fDistanceToWall = fDepth;
}
else if (map[nTestY*nMapWidth + nTestX] == '#')
{ // Если встретили стену, то заканчиваем цикл
bHitWall = true;
}
}

//Вычисляем координаты начала и конца стенки по формулам (1) и (2)
int nCeiling = (float)(nScreenHeight/2.0) - nScreenHeight / ((float)fDistanceToWall);
int nFloor = nScreenHeight - nCeiling;

short nShade;

if (fDistanceToWall <= fDepth / 3.0f) nShade = 0x2588; // Если стенка близко, то рисуем
else if (fDistanceToWall < fDepth / 2.0f) nShade = 0x2593; // светлую полоску
else if (fDistanceToWall < fDepth / 1.5f) nShade = 0x2592; // Для отдалённых участков
else if (fDistanceToWall < fDepth) nShade = 0x2591; // рисуем более темную
else nShade = ' ';

for (int y = 0; y < nScreenHeight; y++)
{
if (y <= nCeiling)
screen[y*nScreenWidth + x] = ' ';
else if(y > nCeiling && y <= nFloor)
screen[y*nScreenWidth + x] = nShade;
else
{
// То же самое с полом - более близкие части рисуем более заметными символами
float b = 1.0f - ((float)y - nScreenHeight / 2.0) / ((float)nScreenHeight / 2.0);
if (b < 0.25) nShade = '#';
else if (b < 0.5) nShade = 'x';
else if (b < 0.75) nShade = '~';
else if (b < 0.9) nShade = '-';
else nShade = ' ';

screen[y*nScreenWidth + x] = nShade;
}
}
}

На выходе получается достаточно красиво:

Отображение рёбер

Выглядит наша программа уже неплохо, но ориентироваться по карте всё равно тяжело. Хорошо бы добавить отображение рёбер стен.
Но как мы поймем, что смотрим именно на ребро? Если мы определили, что произошло столкновение со стеной, то мы сразу же можем (точно) определить её местоположение, а значит и местоположение её четырёх рёбер.
То есть у нас есть четыре вектора, которые направлены от наблюдателя точно в рёбра стенки. Если угол между испускаемым лучом и одним из этих векторов становится маленьким, то мы будем воспринимать эту часть стенки за ребро и рисовать её другим символом:

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


vector <pair <float, float>> p;

for (int tx = 0; tx < 2; tx++)
for (int ty = 0; ty < 2; ty++) // Проходим по всем 4м рёбрам
{
float vx = (float)nTestX + tx - fPlayerX; // Координаты вектора,
float vy = (float)nTestY + ty - fPlayerY; // ведущего из наблюдателя в ребро
float d = sqrt(vx*vx + vy*vy); // Модуль этого вектора
float dot = (fEyeX*vx / d) + (fEyeY*vy / d); // Скалярное произведение (единичных векторов)
p.push_back(make_pair(d, dot)); // Сохраняем результат в массив
}
// Мы будем выводить два ближайших ребра, поэтому сортируем их по модулю вектора ребра
sort(p.begin(), p.end(), [](const pair <float, float> &left, const pair <float, float> &right) {return left.first < right.first; });

float fBound = 0.005; // Угол, при котором начинаем различать ребро.
if (acos(p.at(0).second) < fBound) bBoundary = true;
if (acos(p.at(1).second) < fBound) bBoundary = true;

Если флаг bBoundary принимает значение true, то мы печатаем вертикальную черту вместо стенки.
Теперь мы можем видеть границы стен:

Получилась вполне себе сносная бродилка времен 90x.
Исходники, как я уже говорил выше, вы можете найти на GitHub’e автора кода.
Если данная статья вам понравилась, то поделитесь ею с друзьями или оставьте комментарий — мне будет очень приятно С:
Скорее всего я напишу вторую часть, в которой расскажу о том, как можно сильно улучшить данный результат и сделать настоящий шутер!


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

Если у вас остались вопросы или пожелания, то вы можете оставить комментарий (регистрироваться не нужно)

Анонимно:

Хорошо

Дата: 26-05-2019 в 13:54

Анонимно:

Ждём продолжения. Если можно, то хотелось бы на самом примитивном уровне объяснений отрисовки (и её реализации), на своём примере с единичными объектами.

Дата: 03-08-2019 в 11:59

Анонимно:

Тибу бы, заняться робетгутством и учить людей программированию бесплатно. )))
———————————————
Бесплатно бы я не хотел работать :)

Дата: 02-10-2019 в 09:14

Егорка:

Обидно что у тебя мало подписчиков и просмотров, ведь то что ты делаешь очень интересно особенно про илюзию 3d и про платы очень надеюсь что ты и далешь будешь снимать подобного рода вещи
——————————————
Пока есть вы, люди, которым это интересно, я буду дальше стараться для вас :)

Дата: 05-10-2019 в 19:27

Анонимно:

Великолепно! Требуем продолжения бро!!! )

Дата: 14-11-2019 в 18:26

Анонимно:

как бы сюда ещё бы спрайтов добавить

Дата: 16-11-2019 в 13:58

Анонимно:

На ютуб канале есть подобные видео у тебя?

Дата: 05-12-2019 в 17:02

Анонимно:

Я знаю чем займусь в ближайшее время! Спасибо

Дата: 06-12-2019 в 16:53

Анонимно:

Полный код где?

Дата: 12-12-2019 в 17:31

Анонимно:

клас

Дата: 11-01-2020 в 11:33

Анонимно:

SetConsoleColor и поехали 3000 year игры в консоле

Дата: 28-01-2020 в 07:35

Анонимно:

А можно полный код?
——————————
https://github.com/vectozavr/pseudo3DEngine

Дата: 16-02-2020 в 14:54

Анонимно:

Д

Дата: 22-02-2020 в 22:50

Анонимно:

Пожалуйста, сделай продолжение

Дата: 01-03-2020 в 15:51

Анонимно:

мой редактор С++ выдает ошибку в объявлении tp1 и tp2 : » ‘tp1’ does not mean a type » как с этим бороться?

Дата: 18-03-2020 в 19:48

Анонимно:

Спасибо за урок, очень доступно объяснил, лично я всё понял, хоть и не с первого раза.

Дата: 21-03-2020 в 11:32

Анонимно:

Круто

Дата: 24-03-2020 в 16:36

Анонимно:

это же C++?

Дата: 29-03-2020 в 20:30

Cat-code:

Тоесть мы делаем проверку на каждом луче что бы узнать где поставить ребро?если что мне 12 лет

Дата: 30-03-2020 в 00:58

Анонимно:

у меня не запускается(

Дата: 30-03-2020 в 12:41

фанатик:

как сохранить в какой формат ? просто текстовий дакуумант виходет ((((((

Дата: 30-03-2020 в 13:42

Анонимно:

Здравствуйте. Так в стандартной консоли же 80 столбцов и 25 строк. Почему у Вас 120 столбцов?
И я бы хотел запустить этот код в CodeBlocks v17.12. Он неработает, что делать? Можете мне с этим помочь?

Дата: 30-03-2020 в 20:04

BlabbingCrow:

Братан. Шикарная статья. Но тебе бы изучить основы ООП. Банально использование функций. Очень полезный навык, который тебе очень поможет. Статье уже больше года. Так что возможно ты уже обратил на это внимание, но если нет, то очень советую изучить данный вопрос. Так же более детально подойти к организации проекта на С++, т.е. инкапсулировать функционал по разным компонентам и добавить им хедеры (своего рода аналоги интерфейсов) и получится замечательный приятный код.

Дата: 30-03-2020 в 22:09

BlabbingCrow:

Чекнул вторую часть статьи. Предъявы за ООП сняты. Все по красоте)

Дата: 30-03-2020 в 22:19

Анонимно:

ewwef

Дата: 04-04-2020 в 20:27

Neboron:

Переписал урок под linux использовав кадровый буффер для отрисовки:
https://github.com/Neboron/NFB

Дата: 09-04-2020 в 13:33

Анонимно:

Интересная интерпретация определения предмета перед собой. Спасибо не знал есть ли ссылка на патирон?!

Дата: 09-04-2020 в 20:50

Анонимно:

А можно сразу весь код написать?

Дата: 09-04-2020 в 21:41

Анонимно:

у меня выдаёт ошибки при написании for в коде
паиагитеееееееееее

Дата: 12-04-2020 в 14:56

Никита:

У меня вопрос а как запустить программу с игрой

Дата: 15-04-2020 в 20:05

Анонимно:

А что делать если выдает ошибки и не запускается консоль

Дата: 24-05-2020 в 07:42

hunter:

Спасибо, получилось повторить

Дата: 24-05-2020 в 11:39

Анонимно:

ыы

Дата: 28-05-2020 в 20:41

Б. Страуструп:

Супер

Дата: 30-05-2020 в 17:08

Анонимно:

По-моему проще бы было реализовать это без псевдо трехмерной графики и на js с библиотекой three js, там бы на мой взгляд было бы намного проще

Дата: 14-06-2020 в 20:55

Анонимно:

17

Дата: 21-06-2020 в 18:05

Денис:

Очень хорошо сделано! Читая эту статью написал свой ‘2.5D engine’, не слегка изменив его) Не так давно узнал про твой канал и все твои видео просто огонь!:)

Дата: 28-06-2020 в 16:54

Анонимно:

эх жалко что полного кода нет

Дата: 09-07-2020 в 23:38

ДАЛБАЕБ КАТОРЫ НЕЧИВО НИЗНАЮЕ:

АПАЧИМУНИ ЗОБУСКАИЦА?

Дата: 18-07-2020 в 17:00

Анонимно:

Я нічого не зрозумів

Дата: 02-08-2020 в 22:24

Анонимно:

=

Дата: 10-08-2020 в 08:31

Анонимно:

у меня не получилось

Дата: 10-08-2020 в 08:48

PyGame [Python]:

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

Дата: 06-09-2020 в 10:32

Анонимно:

Топ спасибо за помощь ;)

Дата: 15-10-2020 в 21:44

Александр:

Статья супер. Хотел сказать по сайту. На ксиоми редми нот 7 в стандартном браузере не прогрузились картинки.

Дата: 20-11-2020 в 02:01

Анонимно:

Изи

Дата: 22-11-2020 в 12:12

Анонимно:

Нечего не работает!

Дата: 02-12-2020 в 16:09

Анонимно:

Кстати мне 11лет и я смог сделать карту .Перехожу к управлению

Дата: 03-12-2020 в 14:15

лол:

класс

Дата: 15-12-2020 в 13:40

Анонимно:

А как запустить?

Дата: 26-02-2021 в 11:33

Анонимно:

я бы не создавал массив для хранения буфера консоли, это очень сильно загромождает память (я пишу на fasm, я уменьшил размер файла с 8КБ до 2КБ), можно использовать LocalAlloc, он быстрее и лучше. По поводу микроконтроллера arduino для начинающий пойдет, но если тебе надо производительность и малый размер программы используй AVR (я тоже этим занимаюсь), и там же можно также сделать как это сделал я через LocalAlloc, но загружая данные напрямую в оперативку и выгружая её (в ассемблере с AVR не селен)

Дата: 26-02-2021 в 20:59

Борис:

3д мне пока не нужно, не дорос ещё. Пока пытаюсь привести в движение 2д. getch() не подошло. А у Вас нашёл GetAsyncKeyState(). Завтра попробую использовать.

Дата: 06-03-2021 в 22:53

Анонимно:

WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0, 0 }, &dwBytesWritten);
ошибку выдает, никак не могу исправить. Что делать?

Дата: 31-03-2021 в 11:15

Анонимно:

t

Дата: 08-04-2021 в 16:46

Егорка:

Я лох

Дата: 12-04-2021 в 14:37

Анонимус:

Скинь плиз полную версию кода :)))

Дата: 01-05-2021 в 06:58

Анонимно:

Хз

Дата: 03-05-2021 в 10:08

Анонимно:

Хорошо отлично

Дата: 03-05-2021 в 15:33

Анонимно:

Спс за исходник буду тестить

Дата: 04-05-2021 в 22:39

Анонимно:

а код

Дата: 05-05-2021 в 14:34

Анонимно:

Можно плиз PDF весь код?

Дата: 07-05-2021 в 20:48

Анонимно:

Lf

Дата: 11-05-2021 в 16:35

Анонимно:

лод

Дата: 14-05-2021 в 16:01

DELALEX:

Посмотри на мои проекты
twitter.com/@delalexdevelop

Дата: 28-05-2021 в 16:45

Анонимно:

26

Дата: 01-06-2021 в 20:06

Анонимно:

Привет, я хотел спросить, в какой программе ты работаешь и где её скачать?

Дата: 09-08-2021 в 16:34

Васёк:

Класс!

Дата: 11-08-2021 в 21:01

Анонимно:

к

Дата: 29-08-2021 в 07:33

Анонимно:

П

Дата: 18-09-2021 в 13:45

Анонимно:

Molodets Vectozavr

Дата: 04-10-2021 в 10:43

Анонимно:

круто!!!!

Дата: 18-10-2021 в 12:50

Анонимно:

круто!!!!

Дата: 18-10-2021 в 12:55

Анонивпеорыаролмно:

рапоуыено

Дата: 12-11-2021 в 09:17

Анонимно:

Хотел создать игру на sfml(долго мучался и ничего не получилось), вспомнил про этот сайт и понял что в консоли атмосфера хакинга будет лучше чувствоваться

Дата: 19-11-2021 в 16:16

Анонимно:

Гораздо проще,чем в sfml , идеально для игр с элементом хакинга

Дата: 19-11-2021 в 16:18

Анонимно:

нихуя не работает

Дата: 09-12-2021 в 20:31

Анонимно:

awd

Дата: 28-01-2022 в 20:54

Насонов:

Не получилось

Дата: 31-01-2022 в 09:13

Анонимно:

Ваш коментарий…

Дата: 13-02-2022 в 17:13

R0mbuk196:

Где скачать консоль

Дата: 26-02-2022 в 07:45

Анонимно:

вап

Дата: 03-03-2022 в 18:58

Анонимно:

цц

Дата: 22-03-2022 в 16:17

Анонимно:

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

Дата: 25-03-2022 в 07:19

Анонимно:

Можно полностью код

Дата: 27-04-2022 в 15:20

Анонимно:

Можно полностью код

Дата: 27-04-2022 в 15:20

Анонимнощ0-:

тш

Дата: 02-05-2022 в 13:33

Анонимно:

нпнпнгпнг

Дата: 04-05-2022 в 19:14

Анонимно:

топ

Дата: 08-05-2022 в 14:03

Анонимно:

suction

Дата: 08-05-2022 в 15:00

Анонимно:

33434

Дата: 08-05-2022 в 21:51

Анонимно:

33434

Дата: 08-05-2022 в 21:51

Анонимный бублик:

А как сделать такую же игру в блокноте???

Дата: 11-05-2022 в 22:22

Всем:

Круто

Дата: 16-05-2022 в 19:59

Анонимно:

СЛООООООООООООООЖНННННННОООООООО

Дата: 11-06-2022 в 13:09

Анонимно:

23

Дата: 17-06-2022 в 10:57

пИСЬКА:

АВРГРСРМРПАЛОА

Дата: 27-06-2022 в 14:23

Анонимно:

мне понравилось

Дата: 01-08-2022 в 21:45

Анонимно:

мне понравилось

Дата: 02-08-2022 в 07:51

Анонимно:

I liked

Дата: 02-08-2022 в 17:26

Чел на шарпе и жабе:

пусть и графика фиговая но зато 150+ фпс

Дата: 06-08-2022 в 11:45

Анонимно:

22

Дата: 18-08-2022 в 13:47

Артем хуй:

Чел хорош

Дата: 03-10-2022 в 16:41

Анонимно:

6 + 19 = 25

Дата: 30-12-2022 в 20:37

Кизлярский мастер:

я на тебе никогда не женюсь

Дата: 04-01-2023 в 15:13

челик:

прикольно

Дата: 16-01-2023 в 16:16

Анус:

Круто

Дата: 17-01-2023 в 13:50

Анонимно:

кцукцукцукцукуцацаываывауцацуацукцацуавыа. кароч — имба

Дата: 08-02-2023 в 11:15

Анонимно:

как запустить игру скажите пожалуйста

Дата: 21-02-2023 в 15:49

Анонимно:

6

Дата: 02-03-2023 в 13:34

Игра крестики нолики на Си

Задача заключается в реализации игры крестики-нолики на языке программирования Си++.  Программа должна создавать поле для игры в крестики-нолики. Игроки поочерёдно вводят номер строки и столбца, в котором они хотят сделать ход. Игра проходит таким образом до тех пор, пока кто-либо из игроков не победит или не произойдёт ничья. Если клетка уже занята, то программа не должна дать сделать некорректный ход. Если кто-либо победит, программа должна уведомить об этом, после чего пользователь должен нажать кнопку, чтобы выйти из программы.

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

Переменные и массивы. Массив a[i][j] отвечает за номер строки и столбца каждой клетки. i – номер строки клетки, j – номер столбца клетки. Подробно о работе с массивами в Си

Если a[i][j] =0 то данная клетка свободна

Если a[i][j] =1 то данная клетка занята ноликом

Если a[i][j] =2 то данная клетка занята крестиком

Переменные igra и res отвечают за состояние игры, если эти переменные равны нулю, то пока никто не победил, если 1 – победил нолик, если 2 – победил крестик. В переменную hi записывается ход игрока, например, «12» — первая строка, второй столбец. str и sto отвечают за номер выбранных строки и столбца. ver – проверяет возможность хода, если ход невозможен – 0, если возможен – 1.

В программе присутствует четыре процедуры. Подробно  о процедурах в Си.

nul() обнуляет находящиеся элементы каждой клетки на поле, это нужно для начала игры. Если клетка была пустой, то процедура оставит её пустой, если клетка была занята крестиком или ноликом, процедура уберёт их оттуда.

Алгоритм процедуры

процедура обнуления  массива

visual() предназначена для визуализации поля при каждом ходе. Если клетка пуста, то ничего в ней не нарисуется, если на клетке сделали ход, то процедура нарисует этот ход крестик или нолик.

Алгоритм процедуры визаулизации поля

процедура визуализации

Процедура hod(n). Процедура запрашивает номер строки и столбца в клетки, в которую ходит игрок и назначает на выбранную клетку нолик или крестик.  n – номер игрока, который должен ходить в данный момент. Если n = 1 то ходит нолик, если n = 2, то ходит крестик.

Для  проверки корректности хода, клетка должна быть пуста и номер должен быть один из номеров таблицы 3 на 3

if (a[str][sto]==0 && (hi==11 || hi==12 || hi==13 || hi==21 || hi==22 || hi==23 || hi==31 || hi==32 || hi==33 )) (ver=1);

Алгоритм процедуры ход.

процедура  хода

proverka() при каждом ходе проверяет, не победил ли какой-либо игрок, и возвращает одно из возможных значений. Если proverka() = 0, то никто пока не победил или случилась ничья, если proverka() = 1, то победил нолик, если 2 – крестик.

При проверке мы проверяем в цикле for  все строки и ищем есть в какой либо строке  все нолики

// пробегаем по всем строкам       

    for (i=1; i<=3; i++)

    {

       // проверка  все ли в строке нолики

        if (a[i][1]==1 && a[i][2]==1 && a[i][3]==1 ) {res=1;}

 }

Подробно о цикле for в Си

Аналогично идет проверрка по всем столбцам и проверка диагоналей

 // проверка диагоналей

      if (a[1][1]==1 && a[2][2]==1 && a[3][3]==1 )  {res=1;}

      if (a[1][3]==1 && a[2][2]==1 && a[3][1]==1 )  {res=1;}

Алгоритм проверки

Полный код программы.

#include <stdio.h>
#include <conio.h>

int a[3][3];// объявляем  текущее поле  3 строки и 3 столбца. если  нет ничего то поле 0, если нолик,  то  1, если крестик то 2 

// обнуление поля

void nul()
{ int i,j;

//  пробегаем по всем строкам
 for(i=1; i<=3; i++)
 {
// пробегаем по всем столбцам
  for (j=1;j<=3;j++)
  {
      a[i][j]=0;
  }  
 }
}

// вывод  поля на экран

void visual()
{
int i,j;
printf (»  1 2 3n»);

//  пробегаем по всем строкам  
 for(i=1; i<=3; i++)
 {
  printf («%d», i);  
// пробегаем по всем столбцам      
 for (j=1;j<=3;j++)
  {   
      if (a[i][j]==0){printf(«| «);};
      if (a[i][j]==1){printf(«|O»);};
      if (a[i][j]==2){printf(«|X»);};
  }

// переходим на следующую строку 

  printf («|n»);   
  printf («________n»);
 }      
 }

// Ход игрока n — номер игрока На выходе: 0 — 

void hod (int n)
{
int hi;// ход игрока
int sto; //  номер столбца в ходе
int str; // номер строки в ходе
int ver=0; // проверка на корректность хода, если нельзя сделать такой ход то 0, если можно то 1
// запрашиваем ход,  пока не будет введен корректный ход

while (ver==0)
{
// ввод хода
printf («Ваш ход. Введите номер строки и столбца. n»);  
scanf(«%d», &hi);

// определяем номер столбца — это последняя цифра в ходе
sto=hi%10;

// определяем номер строки хода — это первая цифра
str=(hi-sto)/10;

// проверка корректности хода, клетка должна быть пуста и номер должен быть один из номеров таблицы 3 на 3
if (a[str][sto]==0 && (hi==11 || hi==12 || hi==13 || hi==21 || hi==22 || hi==23 || hi==31 || hi==32 || hi==33 )) (ver=1);
}

// если  ходил игрок 1 то поле хода  1
if ( n==1) {a[str][sto]=1;}
// если  ходил игрок 2  то поле хода 2
if ( n==2) {a[str][sto]=2;} 
}

// Проверка  Если ни один игрок не выиграл то 0, если выиграл нолик то 1 если выиграл крестик то 2
int proverka()
{   int i;
    int res; // значение функции. Если ни один игрок не выиграл то 0, если выиграл нолик то 1 если выиграл крестик то 2
    res=0;
   // проверяем выигрыш первого игрока

   // пробегаем по всем строкам       
    for (i=1; i<=3; i++)
    {
        // проверка  все ли в строке нолики
        if (a[i][1]==1 && a[i][2]==1 && a[i][3]==1 ) {res=1;}
 }

   // пробегаем по всем столбцам     
    for (i=1; i<=3; i++)
    {
        // проверка все ли в столбце нолики
        if (a[1][i]==1 && a[2][i]==1 && a[3][i]==1 ) {res=1;}
    }

    // проверка диагоналей
      if (a[1][1]==1 && a[2][2]==1 && a[3][3]==1 )  {res=1;}
      if (a[1][3]==1 && a[2][2]==1 && a[3][1]==1 )  {res=1;}

   // проверяем выигрыш второго игрока
   // пробегаем по всем строкам       
      for (i=1; i<=3; i++)
    {
    // проверка  все ли в строке крестики
        if (a[i][1]==2 && a[i][2]==2 && a[i][3]==2 ) {res=2;}
    }

    // пробегаем по всем столбцам
    for (i=1; i<=3; i++)
    {
     // проверка все ли в столбце крестики 
        if (a[1][i]==2 && a[2][i]==2 && a[3][i]==2 ) {res=2;}
    }

      // проверка диагоналей
      if (a[1][1]==2 && a[2][2]==2 && a[3][3]==2 )  {res=2;}
      if (a[1][3]==2 && a[2][2]==2 && a[3][1]==2 )  {res=2;}   
    return res;
}

main()
{
int igra;// состояние игры если победил нолик то 1 , если победил крестик то 2 если никто пока не победил то 0
// обнуляем очищаем поле
nul();
// отображаем игровое поле
visual();
igra=0;

// пока никто не победил продолжается игра

while (igra==0)
{
// ход 1 го игрока нолика
hod(1);
// отображаем игровое поле
visual();
// проверка на победу первого игрока
igra=proverka();
// если первый игрок не победил , то ходит второй игрок

if (igra==0)
{
// ход второго игрока
hod(2);
// отображаем игровое поле
visual();
// проверка на победу второго игрока
igra=proverka();}

}

// отображение результатов игры
if (igra==1){printf («Победил ноликn»);};
if (igra==2){printf («Победил крестикn»);};
getch();
}

Задание для самостоятельной работы.

Расширьте игровое поле до размеров 5×5 клеток.

Вернуться к содержанию

Поделиться

Нет комментариев. Ваш будет первым!

Snake Game Project Using C Language

Introduction

This Snake Game Mini Project in C is a basic console program with no graphics. You may play the famous «Snake Game» in this project exactly as you would anywhere else. To move the snake, use the up, down, right, and left arrows.

Food is placed at various co-ordinates on the screen for the snake to consume. The snake’s length and score will both rise by one element each time it consumes the food.

Source Code for Snake Game Project Using C Language

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
#include<ctype.h>
#include <time.h>
#include <windows.h>
#include <process.h>

#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77

int length;
int bend_no;
int len;
char key;
void record();
void load();
int life;
void Delay(long double);
void Move();
void Food();
int Score();
void Print();
void gotoxy(int x, int y);
void GotoXY(int x,int y);
void Bend();
void Boarder();
void Down();
void Left();
void Up();
void Right();
void ExitGame();
int Scoreonly();

struct coordinate
{
    int x;
    int y;
    int direction;
};

typedef  struct coordinate coordinate;

coordinate head, bend[500],food,body[30];

int main()
{

    char key;

    Print();

    system("cls");

    load();

    length=5;

    head.x=25;

    head.y=20;

    head.direction=RIGHT;

    Boarder();

    Food(); //to generate food coordinates initially

    life=3; //number of extra lives

    bend[0]=head;

    Move();   //initialing initial bend coordinate

    return 0;

}

void Move()
{
    int a,i;

    do
    {

        Food();
        fflush(stdin);

        len=0;

        for(i=0; i<30; i++)

        {

            body[i].x=0;

            body[i].y=0;

            if(i==length)

                break;

        }

        Delay(length);

        Boarder();

        if(head.direction==RIGHT)

            Right();

        else if(head.direction==LEFT)

            Left();

        else if(head.direction==DOWN)

            Down();

        else if(head.direction==UP)

            Up();

        ExitGame();

    }
    while(!kbhit());

    a=getch();

    if(a==27)

    {

        system("cls");

        exit(0);

    }
    key=getch();

    if((key==RIGHT&&head.direction!=LEFT&&head.direction!=RIGHT)||(key==LEFT&&head.direction!=RIGHT&&head.direction!=LEFT)||(key==UP&&head.direction!=DOWN&&head.direction!=UP)||(key==DOWN&&head.direction!=UP&&head.direction!=DOWN))

    {

        bend_no++;

        bend[bend_no]=head;

        head.direction=key;

        if(key==UP)

            head.y--;

        if(key==DOWN)

            head.y++;

        if(key==RIGHT)

            head.x++;

        if(key==LEFT)

            head.x--;

        Move();

    }

    else if(key==27)

    {

        system("cls");

        exit(0);

    }

    else

    {

        printf("a");

        Move();

    }
}

void gotoxy(int x, int y)
{

    COORD coord;

    coord.X = x;

    coord.Y = y;

    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

}
void GotoXY(int x, int y)
{
    HANDLE a;
    COORD b;
    fflush(stdout);
    b.X = x;
    b.Y = y;
    a = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(a,b);
}
void load()
{
    int row,col,r,c,q;
    gotoxy(36,14);
    printf("loading...");
    gotoxy(30,15);
    for(r=1; r<=20; r++)
    {
        for(q=0; q<=100000000; q++); //to display the character slowly
        printf("%c",177);
    }
    getch();
}
void Down()
{
    int i;
    for(i=0; i<=(head.y-bend[bend_no].y)&&len<length; i++)
    {
        GotoXY(head.x,head.y-i);
        {
            if(len==0)
                printf("v");
            else
                printf("*");
        }
        body[len].x=head.x;
        body[len].y=head.y-i;
        len++;
    }
    Bend();
    if(!kbhit())
        head.y++;
}
void Delay(long double k)
{
    Score();
    long double i;
    for(i=0; i<=(10000000); i++);
}
void ExitGame()
{
    int i,check=0;
    for(i=4; i<length; i++) //starts with 4 because it needs minimum 4 element to touch its own body
    {
        if(body[0].x==body[i].x&&body[0].y==body[i].y)
        {
            check++;    //check's value increases as the coordinates of head is equal to any other body coordinate
        }
        if(i==length||check!=0)
            break;
    }
    if(head.x<=10||head.x>=70||head.y<=10||head.y>=30||check!=0)
    {
        life--;
        if(life>=0)
        {
            head.x=25;
            head.y=20;
            bend_no=0;
            head.direction=RIGHT;
            Move();
        }
        else
        {
            system("cls");
            printf("All lives completednBetter Luck Next Time!!!nPress any key to quit the gamen");
            record();
            exit(0);
        }
    }
}
void Food()
{
    if(head.x==food.x&&head.y==food.y)
    {
        length++;
        time_t a;
        a=time(0);
        srand(a);
        food.x=rand()%70;
        if(food.x<=10)
            food.x+=11;
        food.y=rand()%30;
        if(food.y<=10)

            food.y+=11;
    }
    else if(food.x==0)/*to create food for the first time coz global variable are initialized with 0*/
    {
        food.x=rand()%70;
        if(food.x<=10)
            food.x+=11;
        food.y=rand()%30;
        if(food.y<=10)
            food.y+=11;
    }
}
void Left()
{
    int i;
    for(i=0; i<=(bend[bend_no].x-head.x)&&len<length; i++)
    {
        GotoXY((head.x+i),head.y);
        {
            if(len==0)
                printf("<");
            else
                printf("*");
        }
        body[len].x=head.x+i;
        body[len].y=head.y;
        len++;
    }
    Bend();
    if(!kbhit())
        head.x--;

}
void Right()
{
    int i;
    for(i=0; i<=(head.x-bend[bend_no].x)&&len<length; i++)
    {
        //GotoXY((head.x-i),head.y);
        body[len].x=head.x-i;
        body[len].y=head.y;
        GotoXY(body[len].x,body[len].y);
        {
            if(len==0)
                printf(">");
            else
                printf("*");
        }
        /*body[len].x=head.x-i;
        body[len].y=head.y;*/
        len++;
    }
    Bend();
    if(!kbhit())
        head.x++;
}
void Bend()
{
    int i,j,diff;
    for(i=bend_no; i>=0&&len<length; i--)
    {
        if(bend[i].x==bend[i-1].x)
        {
            diff=bend[i].y-bend[i-1].y;
            if(diff<0)
                for(j=1; j<=(-diff); j++)
                {
                    body[len].x=bend[i].x;
                    body[len].y=bend[i].y+j;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
            else if(diff>0)
                for(j=1; j<=diff; j++)
                {
                    /*GotoXY(bend[i].x,(bend[i].y-j));
                    printf("*");*/
                    body[len].x=bend[i].x;
                    body[len].y=bend[i].y-j;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
        }
        else if(bend[i].y==bend[i-1].y)
        {
            diff=bend[i].x-bend[i-1].x;
            if(diff<0)
                for(j=1; j<=(-diff)&&len<length; j++)
                {
                    /*GotoXY((bend[i].x+j),bend[i].y);
                    printf("*");*/
                    body[len].x=bend[i].x+j;
                    body[len].y=bend[i].y;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
            else if(diff>0)
                for(j=1; j<=diff&&len<length; j++)
                {
                    /*GotoXY((bend[i].x-j),bend[i].y);
                    printf("*");*/
                    body[len].x=bend[i].x-j;
                    body[len].y=bend[i].y;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
        }
    }
}
void Boarder()
{
    system("cls");
    int i;
    GotoXY(food.x,food.y);   /*displaying food*/
    printf("F");
    for(i=10; i<71; i++)
    {
        GotoXY(i,10);
        printf("!");
        GotoXY(i,30);
        printf("!");
    }
    for(i=10; i<31; i++)
    {
        GotoXY(10,i);
        printf("!");
        GotoXY(70,i);
        printf("!");
    }
}
void Print()
{
    //GotoXY(10,12);
    printf("tWelcome to the mini Snake game.(press any key to continue)n");
    getch();
    system("cls");
    printf("tGame instructions:n");
    printf("n-> Use arrow keys to move the snake.nn-> You will be provided foods at the several coordinates of the screen which you have to eat. Everytime you eat a food the length of the snake will be increased by 1 element and thus the score.nn-> Here you are provided with three lives. Your life will decrease as you hit the wall or snake's body.nn-> YOu can pause the game in its middle by pressing any key. To continue the paused game press any other key once againnn-> If you want to exit press esc. n");
    printf("nnPress any key to play game...");
    if(getch()==27)
        exit(0);
}
void record()
{
    char plname[20],nplname[20],cha,c;
    int i,j,px;
    FILE *info;
    info=fopen("record.txt","a+");
    getch();
    system("cls");
    printf("Enter your namen");
    scanf("%[^n]",plname);
    //************************
    for(j=0; plname[j]!=''; j++) //to convert the first letter after space to capital
    {
        nplname[0]=toupper(plname[0]);
        if(plname[j-1]==' ')
        {
            nplname[j]=toupper(plname[j]);
            nplname[j-1]=plname[j-1];
        }
        else nplname[j]=plname[j];
    }
    nplname[j]='';
    //*****************************
    //sdfprintf(info,"tttPlayers Listn");
    fprintf(info,"Player Name :%sn",nplname);
    //for date and time

    time_t mytime;
    mytime = time(NULL);
    fprintf(info,"Played Date:%s",ctime(&mytime));
    //**************************
    fprintf(info,"Score:%dn",px=Scoreonly());//call score to display score
    //fprintf(info,"nLevel:%dn",10);//call level to display level
    for(i=0; i<=50; i++)
        fprintf(info,"%c",'_');
    fprintf(info,"n");
    fclose(info);
    printf("Wanna see past records press 'y'n");
    cha=getch();
    system("cls");
    if(cha=='y')
    {
        info=fopen("record.txt","r");
        do
        {
            putchar(c=getc(info));
        }
        while(c!=EOF);
    }
    fclose(info);
}
int Score()
{
    int score;
    GotoXY(20,8);
    score=length-5;
    printf("SCORE : %d",(length-5));
    score=length-5;
    GotoXY(50,8);
    printf("Life : %d",life);
    return score;
}
int Scoreonly()
{
    int score=Score();
    system("cls");
    return score;
}
void Up()
{
    int i;
    for(i=0; i<=(bend[bend_no].y-head.y)&&len<length; i++)
    {
        GotoXY(head.x,head.y+i);
        {
            if(len==0)
                printf("^");
            else
                printf("*");
        }
        body[len].x=head.x;
        body[len].y=head.y+i;
        len++;
    }
    Bend();
    if(!kbhit())
        head.y--;
}

Output

Snake Game

Explanation

In C, the following functions are utilized in the Snake Game Project:
In this Snake mini project, a variety of functionalities were employed. I’ll simply list them and explain the functions «gotoxy,» «GotoXY,» and «delay» since they’re some of the most significant functions used in this and many other C small projects.

  • void record()
  • void load()
  • void Delay(long double)
  • void Move()
  • void Food()
  • void Print()
  • void Bend()
  • int Score()
  • void Boarder()
  • void Down()
  • void Left()
  • void Up()
  • void Right()
  • void ExitGame()

gotoxy (int x, int y) – void gotoxy (int x, int y) – This is an essential function to learn since it is utilized in the Snake Game mini project in C. This feature enables you to print text wherever on the screen.

Final Words

To summarize, this C mini project on Snake lets you to keep track of the player’s name and the score they earned. This has been accomplished via the usage of file handling.

If you’re seeking for a reference project or want to make your own C small project game, this mini project may undoubtedly assist. It is strongly discouraged to submit this project with few or no changes.

Snake Game Project Using C Language

Introduction

This Snake Game Mini Project in C is a basic console program with no graphics. You may play the famous «Snake Game» in this project exactly as you would anywhere else. To move the snake, use the up, down, right, and left arrows.

Food is placed at various co-ordinates on the screen for the snake to consume. The snake’s length and score will both rise by one element each time it consumes the food.

Source Code for Snake Game Project Using C Language

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
#include<ctype.h>
#include <time.h>
#include <windows.h>
#include <process.h>

#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77

int length;
int bend_no;
int len;
char key;
void record();
void load();
int life;
void Delay(long double);
void Move();
void Food();
int Score();
void Print();
void gotoxy(int x, int y);
void GotoXY(int x,int y);
void Bend();
void Boarder();
void Down();
void Left();
void Up();
void Right();
void ExitGame();
int Scoreonly();

struct coordinate
{
    int x;
    int y;
    int direction;
};

typedef  struct coordinate coordinate;

coordinate head, bend[500],food,body[30];

int main()
{

    char key;

    Print();

    system("cls");

    load();

    length=5;

    head.x=25;

    head.y=20;

    head.direction=RIGHT;

    Boarder();

    Food(); //to generate food coordinates initially

    life=3; //number of extra lives

    bend[0]=head;

    Move();   //initialing initial bend coordinate

    return 0;

}

void Move()
{
    int a,i;

    do
    {

        Food();
        fflush(stdin);

        len=0;

        for(i=0; i<30; i++)

        {

            body[i].x=0;

            body[i].y=0;

            if(i==length)

                break;

        }

        Delay(length);

        Boarder();

        if(head.direction==RIGHT)

            Right();

        else if(head.direction==LEFT)

            Left();

        else if(head.direction==DOWN)

            Down();

        else if(head.direction==UP)

            Up();

        ExitGame();

    }
    while(!kbhit());

    a=getch();

    if(a==27)

    {

        system("cls");

        exit(0);

    }
    key=getch();

    if((key==RIGHT&&head.direction!=LEFT&&head.direction!=RIGHT)||(key==LEFT&&head.direction!=RIGHT&&head.direction!=LEFT)||(key==UP&&head.direction!=DOWN&&head.direction!=UP)||(key==DOWN&&head.direction!=UP&&head.direction!=DOWN))

    {

        bend_no++;

        bend[bend_no]=head;

        head.direction=key;

        if(key==UP)

            head.y--;

        if(key==DOWN)

            head.y++;

        if(key==RIGHT)

            head.x++;

        if(key==LEFT)

            head.x--;

        Move();

    }

    else if(key==27)

    {

        system("cls");

        exit(0);

    }

    else

    {

        printf("a");

        Move();

    }
}

void gotoxy(int x, int y)
{

    COORD coord;

    coord.X = x;

    coord.Y = y;

    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

}
void GotoXY(int x, int y)
{
    HANDLE a;
    COORD b;
    fflush(stdout);
    b.X = x;
    b.Y = y;
    a = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(a,b);
}
void load()
{
    int row,col,r,c,q;
    gotoxy(36,14);
    printf("loading...");
    gotoxy(30,15);
    for(r=1; r<=20; r++)
    {
        for(q=0; q<=100000000; q++); //to display the character slowly
        printf("%c",177);
    }
    getch();
}
void Down()
{
    int i;
    for(i=0; i<=(head.y-bend[bend_no].y)&&len<length; i++)
    {
        GotoXY(head.x,head.y-i);
        {
            if(len==0)
                printf("v");
            else
                printf("*");
        }
        body[len].x=head.x;
        body[len].y=head.y-i;
        len++;
    }
    Bend();
    if(!kbhit())
        head.y++;
}
void Delay(long double k)
{
    Score();
    long double i;
    for(i=0; i<=(10000000); i++);
}
void ExitGame()
{
    int i,check=0;
    for(i=4; i<length; i++) //starts with 4 because it needs minimum 4 element to touch its own body
    {
        if(body[0].x==body[i].x&&body[0].y==body[i].y)
        {
            check++;    //check's value increases as the coordinates of head is equal to any other body coordinate
        }
        if(i==length||check!=0)
            break;
    }
    if(head.x<=10||head.x>=70||head.y<=10||head.y>=30||check!=0)
    {
        life--;
        if(life>=0)
        {
            head.x=25;
            head.y=20;
            bend_no=0;
            head.direction=RIGHT;
            Move();
        }
        else
        {
            system("cls");
            printf("All lives completednBetter Luck Next Time!!!nPress any key to quit the gamen");
            record();
            exit(0);
        }
    }
}
void Food()
{
    if(head.x==food.x&&head.y==food.y)
    {
        length++;
        time_t a;
        a=time(0);
        srand(a);
        food.x=rand()%70;
        if(food.x<=10)
            food.x+=11;
        food.y=rand()%30;
        if(food.y<=10)

            food.y+=11;
    }
    else if(food.x==0)/*to create food for the first time coz global variable are initialized with 0*/
    {
        food.x=rand()%70;
        if(food.x<=10)
            food.x+=11;
        food.y=rand()%30;
        if(food.y<=10)
            food.y+=11;
    }
}
void Left()
{
    int i;
    for(i=0; i<=(bend[bend_no].x-head.x)&&len<length; i++)
    {
        GotoXY((head.x+i),head.y);
        {
            if(len==0)
                printf("<");
            else
                printf("*");
        }
        body[len].x=head.x+i;
        body[len].y=head.y;
        len++;
    }
    Bend();
    if(!kbhit())
        head.x--;

}
void Right()
{
    int i;
    for(i=0; i<=(head.x-bend[bend_no].x)&&len<length; i++)
    {
        //GotoXY((head.x-i),head.y);
        body[len].x=head.x-i;
        body[len].y=head.y;
        GotoXY(body[len].x,body[len].y);
        {
            if(len==0)
                printf(">");
            else
                printf("*");
        }
        /*body[len].x=head.x-i;
        body[len].y=head.y;*/
        len++;
    }
    Bend();
    if(!kbhit())
        head.x++;
}
void Bend()
{
    int i,j,diff;
    for(i=bend_no; i>=0&&len<length; i--)
    {
        if(bend[i].x==bend[i-1].x)
        {
            diff=bend[i].y-bend[i-1].y;
            if(diff<0)
                for(j=1; j<=(-diff); j++)
                {
                    body[len].x=bend[i].x;
                    body[len].y=bend[i].y+j;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
            else if(diff>0)
                for(j=1; j<=diff; j++)
                {
                    /*GotoXY(bend[i].x,(bend[i].y-j));
                    printf("*");*/
                    body[len].x=bend[i].x;
                    body[len].y=bend[i].y-j;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
        }
        else if(bend[i].y==bend[i-1].y)
        {
            diff=bend[i].x-bend[i-1].x;
            if(diff<0)
                for(j=1; j<=(-diff)&&len<length; j++)
                {
                    /*GotoXY((bend[i].x+j),bend[i].y);
                    printf("*");*/
                    body[len].x=bend[i].x+j;
                    body[len].y=bend[i].y;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
            else if(diff>0)
                for(j=1; j<=diff&&len<length; j++)
                {
                    /*GotoXY((bend[i].x-j),bend[i].y);
                    printf("*");*/
                    body[len].x=bend[i].x-j;
                    body[len].y=bend[i].y;
                    GotoXY(body[len].x,body[len].y);
                    printf("*");
                    len++;
                    if(len==length)
                        break;
                }
        }
    }
}
void Boarder()
{
    system("cls");
    int i;
    GotoXY(food.x,food.y);   /*displaying food*/
    printf("F");
    for(i=10; i<71; i++)
    {
        GotoXY(i,10);
        printf("!");
        GotoXY(i,30);
        printf("!");
    }
    for(i=10; i<31; i++)
    {
        GotoXY(10,i);
        printf("!");
        GotoXY(70,i);
        printf("!");
    }
}
void Print()
{
    //GotoXY(10,12);
    printf("tWelcome to the mini Snake game.(press any key to continue)n");
    getch();
    system("cls");
    printf("tGame instructions:n");
    printf("n-> Use arrow keys to move the snake.nn-> You will be provided foods at the several coordinates of the screen which you have to eat. Everytime you eat a food the length of the snake will be increased by 1 element and thus the score.nn-> Here you are provided with three lives. Your life will decrease as you hit the wall or snake's body.nn-> YOu can pause the game in its middle by pressing any key. To continue the paused game press any other key once againnn-> If you want to exit press esc. n");
    printf("nnPress any key to play game...");
    if(getch()==27)
        exit(0);
}
void record()
{
    char plname[20],nplname[20],cha,c;
    int i,j,px;
    FILE *info;
    info=fopen("record.txt","a+");
    getch();
    system("cls");
    printf("Enter your namen");
    scanf("%[^n]",plname);
    //************************
    for(j=0; plname[j]!=''; j++) //to convert the first letter after space to capital
    {
        nplname[0]=toupper(plname[0]);
        if(plname[j-1]==' ')
        {
            nplname[j]=toupper(plname[j]);
            nplname[j-1]=plname[j-1];
        }
        else nplname[j]=plname[j];
    }
    nplname[j]='';
    //*****************************
    //sdfprintf(info,"tttPlayers Listn");
    fprintf(info,"Player Name :%sn",nplname);
    //for date and time

    time_t mytime;
    mytime = time(NULL);
    fprintf(info,"Played Date:%s",ctime(&mytime));
    //**************************
    fprintf(info,"Score:%dn",px=Scoreonly());//call score to display score
    //fprintf(info,"nLevel:%dn",10);//call level to display level
    for(i=0; i<=50; i++)
        fprintf(info,"%c",'_');
    fprintf(info,"n");
    fclose(info);
    printf("Wanna see past records press 'y'n");
    cha=getch();
    system("cls");
    if(cha=='y')
    {
        info=fopen("record.txt","r");
        do
        {
            putchar(c=getc(info));
        }
        while(c!=EOF);
    }
    fclose(info);
}
int Score()
{
    int score;
    GotoXY(20,8);
    score=length-5;
    printf("SCORE : %d",(length-5));
    score=length-5;
    GotoXY(50,8);
    printf("Life : %d",life);
    return score;
}
int Scoreonly()
{
    int score=Score();
    system("cls");
    return score;
}
void Up()
{
    int i;
    for(i=0; i<=(bend[bend_no].y-head.y)&&len<length; i++)
    {
        GotoXY(head.x,head.y+i);
        {
            if(len==0)
                printf("^");
            else
                printf("*");
        }
        body[len].x=head.x;
        body[len].y=head.y+i;
        len++;
    }
    Bend();
    if(!kbhit())
        head.y--;
}

Output

Snake Game

Explanation

In C, the following functions are utilized in the Snake Game Project:
In this Snake mini project, a variety of functionalities were employed. I’ll simply list them and explain the functions «gotoxy,» «GotoXY,» and «delay» since they’re some of the most significant functions used in this and many other C small projects.

  • void record()
  • void load()
  • void Delay(long double)
  • void Move()
  • void Food()
  • void Print()
  • void Bend()
  • int Score()
  • void Boarder()
  • void Down()
  • void Left()
  • void Up()
  • void Right()
  • void ExitGame()

gotoxy (int x, int y) – void gotoxy (int x, int y) – This is an essential function to learn since it is utilized in the Snake Game mini project in C. This feature enables you to print text wherever on the screen.

Final Words

To summarize, this C mini project on Snake lets you to keep track of the player’s name and the score they earned. This has been accomplished via the usage of file handling.

If you’re seeking for a reference project or want to make your own C small project game, this mini project may undoubtedly assist. It is strongly discouraged to submit this project with few or no changes.

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

Введение

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

Ну что ж, для начала сделаю маленькую ремарку о том, что данный пункт из списка будет небольшим и больше поясняющим, направляющим и т.п. Т.к. по части проектирования, более подробно можно будет прочитать из книги «Совершенный код» автора Макконел С. Книга полезная для тех, кто хочет взяться за серьезный проект или по меньше ошибаться на этапах проектирования, при этом независимо от формального языка, на котором будет применять полученные знания. Однако, на мой взгляд это одна из немногих книг, написанная американцами, которая дотягивает до уровня профессоров СССР 80-ых годов, где открыл и понятно, что куда, и каким образом. Видимо, дозрели, так что книгу стоило назвать, «Пособие по проектированию нормально работающего кода, руками растущими не из жопы». Да-да, такова суровость русского языка, говорить более прямо и по существу вопроса. А теперь, перейдем, конкретно к теме статьи, и напомню, что пример будет описывать не с позиции знания вышеприведенной книги, а с позиции личного, накопленного опыта, т.к. это ценее. Да, и книгу, нашел год спустя после накопления своего опыта. Так что, почитал ее не с позиции утенка, а с позиции человека будучи в определенной мере в потоке.


Зеленый новичок

Самая первая проблема, любого зеленого программиста в том, что после универа или других источников обучения, есть ярая и порою детская уверенность в том, что можно спокойно собрать велосипед из трактора или наоборот. Т.к. отсутствие практического опыта на ходу заменяется самоуверенностью или самоубеждением в собственных силах. Это прямой и легкий путь, либо к разочарованию, либо к костылестроению. А как всем, «неизвестно», внутреннее часто проецируются на внешнее, а потом по обратной связи начинает взращивать в участнике такого процесса, внутренние конструкции, дающие еще большую прогрессию в этом деле. Для примера, взгляните в зеркало, и задайте себе внутренний вопрос: «А у меня не также?». Полагаю, ответ, вам сильно «понравится». 😉

Однако, разобраться в самоопределении — это еще только часть дилеммы «чистого листа», т.к. вышеописанная проблема — это не желание принять себя новичком и постоянный уход от этого, который неизбежно создает в себе упадок. А другая проблема, в том чтобы правильно начать. И ответ на этот вопрос ищут все по разному, у меня например удалось найти его через описание по составлению проектов в виде документации для архитекторов. Вкратце говоря, взял сам каркас подхода остальное отбросил и вложил со сферы деятельности программистов разных мастей. И, получилось, заработало. А по части реализации исходного кода программы могу сказать, что в силу опытности написания простых программ, сложную программу начал писать с самого простого места — с середины, т.к. сложно было обозначить начало и конец. Как раз об этом моменте и поговорим, подробнее.


Середина программы — движение механики

Сделаю еще одну, маленькую, ремарку. На вопрос «движение механики чего?», для особо страждущих у меня ответ таков. Все, как в том старом китайском фильме, где рабочему-новичку дали изоленту, и сказали, примерно следующее: «Вот, это твой рабочий инструмент, им можно починить, все, тебе будет его достаточно». Так, что движение механики — это ответ на ваш вопрос и он поможет вам понять все в этом мире. И это, работающая, правда.

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

И как ранее говорилось, учебный пример игры «Виселица», является по сути игрой, следовательно игровой процесс — это середина программы. А начало и конец, пока отложим в сторону. В итоге, пользователь программы принимает участие в работе программы, будучи игроком.

Каркас середины программы из себя представляет отгадывание слова, которое неизвестно игроку, а известно программе, при этом отгадывается по буквам. Значит, основной каркас программы в том, что игрок отгадывает слово по буквам и для реализации этого процесса применяется вся логика, конструкция и механика программы «Виселица». И смысл не в том, что это элементарно, т.к. элементарно для меня, потому что мне понятно, о чем идет речь, вам, наоборот. Т.к. умение разбирать программу на составляющие — это одно из умений, необходимых, для создания программ разного рода и уровня сложностей, без этого можно с легкостью создавать костыли, а не программы. И не надо убеждать меня в том, что якобы не прав — это значит, что вы ни разу не то, чтобы не брались за дело, даже в некоторой мере не реализовали сложный проект, пройдя все его тернии.

А теперь, представим себе игру «Виселица», как некий механизм (чем по сути оно и является, т.е. программный механизм). У любого механизма всегда есть начало, середина и конец. Помимо этого, любой, механизм состоит из основы (это каркас), и дополняющих направлений — это дополнения, которые задают границы возможностей механизма, закладываемые в него на этапе проектирования. То бишь, достаточно нарисовать круг и поставить в центре точку, где точка — это каркас программы, окружность — это дополнения, а пространство между ними — это конкретный алгоритм, классы, и т.д. Этот принцип построения программ применяется везде и всюду, т.к. основан на более древних принципах созидания, не только в искусстве разработки программ. А, остальное зависит от развития вашего умения высматривать и находить механику в любых местах деятельности.

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

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

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

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


Исходный код

А теперь, пора бы выложить все вышеописанное в исходном коде, коим будет сама реализация нашего содержания программы. Код, разумеется прост, как дважды, два, четыре. При этом, несмотря на простую реализацию игры, данный исходный код — это нормально работающий код, который можно превратить в нормальную программу-игру «Виселица». С этого варианта и продолжим развитие темы данного учебного примера.

И для краткости, немного по коду. Сам, игровой процесс начинается со строки 84, где запускается бесконечный цикл, пока игрок, либо отгадает слово, либо не отгадает слово и истратит допустимое кол-во ошибок. Также, помимо этого, была добавлена не только проверка на соответствие символов, вводимых с клавиатуры, буквам русского алфавита, а также проверка на повторный ввод ранее введенных букв. И разумеется в самом начале, игра вежливым общением, с элементами диалога, предлагает игроку сыграть в игру, объяснив ее правила. Также дает возможность выйти из программы до старта игрового процесса.

И как, было мною упомянуто ранее в статье, вне темы идут вопросы о wchar_t, wcin, wcout, setlocale, using, т.к. они выходят за рамки темы, поэтому объясняться не будут. И единственное, что скажу. Это то, что «L» перед кавычками ставится не просто так, это связано с кодировкой Utf8, в которой пишется файл на gedit в Линуксе. И разумеется, все ранее перечисленное применяется без создания очередных костылей. Да, и новичкам есть, что почерпнуть для своей практики из кода.

В заключение, пример того какой командой делал компиляцию после сохранения файла с исходными кодами.

g++ viselica1.cpp o viselica1

./viselica1

Пример работы программы игры Виселица

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

// ======================================================================

//  viselica-1.cpp

// ======================================================================

// ======================================================================

//  Имя программы: viselica-1 (Программа-игра «Виселица»)

//  Авторское право (c) 2016 Смирнов Андрей Владимирович известный, как Мирра Андрюхан

//  Лицензия: GNU GPL 2

//  Автор: Смирнов Андрей Владимирович

//  Почта: mirra.andryuhan@yandex.ru

//  Веб-сайт: http://andryuhan.ru

//  Лицензию можно прочитать, здесь http://www.gnu.org/licenses/old-licenses/gpl-2.0.html

// ======================================================================

#include <iostream>

#include <wchar.h>

using namespace std;

//Сбрасывает лишние символы, т.к. ввод идет с клавиатуры

inline void SbrosVvoda() { if (wcin.peek() != ‘n’) while (wcin.peek() != ‘n’) wcin.ignore(); }

int main()

{

//Устанавливаем локаль ru_RU.UTF-8, чтобы применять русские буквы в программе.

setlocale (LC_ALL,«ru_RU.UTF-8»);

//Флаг выхода из бесконечного цикла, по умолчанию ставится ложь.

bool isExit = false;

//Символ ответа

wchar_t simvol = ‘ ‘;

//Вступительный текст программы-игры «Виселица».

wcout << L«Привет, пользователь. Давай сыграем в игру «Виселица», правила которой просты.n Я, программа, загадываю слово, а ты его отгадываешь по буквам. Если ошибешься десять раз, то проиграешь.n Слово будет состоять из букв Русского алфавита.nn»;

//Получение ответа или повтор запроса от программы

while (!isExit)

{

wcout << L«Будем играть? (Дд/Нн)»;

wcin >> simvol;

SbrosVvoda();

if (simvol != L‘Д’ && simvol != L‘Н’ && simvol != L‘д’ && simvol != L‘н’)

{

wcout << L«nВведены не верные данные в качестве ответа, вводи Д или д, и Н или н!n»;

continue;

}

if (simvol == L‘Н’ || simvol == L‘н’)

{

wcout << L«nСпасибо, за внимание. До свидания, пользователь.n»;

//Выход из программы-игры «Виселица».

return 0;

}

else

isExit = true;

}

//———————————————-

//Проведение игрового процесса игры «Виселица».

//Алфавит Русского языка

wchar_t alhavit[33] = {L‘а’, L‘б’, L‘в’, L‘г’, L‘д’, L‘е’, L‘ё’, L‘ж’, L‘з’, L‘и’, L‘й’, L‘к’, L‘л’, L‘м’, L‘н’, L‘о’, L‘п’, L‘р’, L‘с’, L‘т’, L‘у’, L‘ф’, L‘х’, L‘ц’, L‘ч’, L‘ш’, L‘щ’, L‘ь’, L‘ы’, L‘ъ’, L‘э’, L‘ю’, L‘я’};

//Счетчик для циклов

short i;

//Массив загаданного слова

wchar_t slovo[7] = {L‘ч’, L‘е’, L‘м’, L‘о’, L‘д’, L‘а’, L‘н’};

//Массив отгадываемого слова

wchar_t otgSlovo[7] = {‘?’, ‘?’, ‘?’, ‘?’, ‘?’, ‘?’, ‘?’};

//Массив букв введеных игроком, для исключения дублированного ответа.

wchar_t vvedBukva[16] = {L‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’, ‘#’};

//Индекс введенных букв.

short indBukva = 0;

//Флаг соответствия введенного символа буквам русского алфавита или букве в загаданном слове.

bool isPravilno;

//Счетчик допустимых ошибок

short kolOshibok = 9;

//Счетчик отгаданных букв

short kolPravilno = 0;

//Переинициализация Символа ответа

simvol = ‘ ‘;

wcout << L«Загадываю слово… Хорошо, слово на строке ниже.n»;

//Собственно, сам процесс игры

while (true)

{

//Если игрок отгадал, загаданное слово, тогда поздравляем и завершаем программу.

if (kolPravilno == 7)

{

wcout << L«Поздравляю, ты, угадал мое слово.n»;

wcout << L«Слово было такое: «»;

wcout << slovo;

wcout << L«».n»;

wcout << L«Спасибо, за игру, было приятно с тобой поиграть.n»;

//Выход из программы-игры «Виселица».

return 0;

}

//Если игрок, не угадал слово и истратил кол-во допустимых ошибок, то сообщаем ему и завершаем программу.

if (kolOshibok < 0)

{

wcout << L«nУвы, у тебя, закончились допустимые ошибки.n»;

wcout << L«Слово было такое: «»;

wcout << slovo;

wcout << L«».n»;

wcout << L«Спасибо, за игру, было приятно с тобой поиграть.n»;

//Выход из программы-игры «Виселица».

return 0;

}

Povtor:

//Вывод отгадываемого слова на экран

wcout << otgSlovo << L«n»;

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

wcout << L«Кол-во допустимых ошибок:» << kolOshibok + 1 << «.n»;

wcout << L«Какая будет твоя буква из Русского Алфавита, пожайлуста, вводи маленькой буквой?n»;

wcin >> simvol;

SbrosVvoda();

//Проверка на ввод данных от пользователя

isPravilno = false;

for (i=0; i < 33; i++)

if (simvol == alhavit[i])

{

isPravilno = true;

break;

}

if (!isPravilno)

{

wcout << L«nВведены неверные данные.nn»;

goto Povtor;

}

//Проверка на повторение выбранной буквы

for (i=0; i < 15; i++)

if (simvol == vvedBukva[i])

{

wcout << L«nЭта буква, уже была введена, введи другую букву.nn»;

goto Povtor;

}

//Сравнение введеной буквы игроком с буквами загаданного слова

isPravilno = false;

for (i=0; i<7; i++)

if (simvol == slovo[i])

{

wcout << L«Правильно, есть такая буква в загаданном слове.nn»;

otgSlovo[i] = slovo[i];

kolPravilno++;

isPravilno = true;

break;

}

if (!isPravilno)

{

wcout << L«Не правильно, такой буквы в загаданом слове нет.nn»;

kolOshibok;

};

//Запоминаем введенную букву

vvedBukva[indBukva] = simvol;

indBukva++;

}

//———————————————

//Выход из программы-игры «Виселица».

return 0;

}

 5,137 total views,  2 views today

Хотя говорят, что я закончил самостоятельное изучение ввода языка Си (после прочтения «Программирование на Си»?), Фактическая способность все еще остается на очень низком уровне. По сути, это установка нескольких циклов и насильственное решение проблемы перестановки и комбинации. На этот раз написание консольной жадной программы — большая проблема для меня

Успокойся и подумай об этом, в текстовой версии Greedy Snake не так уж много вещей. Реализация игры состоит в основном в том, чтобы модифицировать и преобразовывать двумерный массив в соответствии с определенной логикой. (В реальной работе, чтобы уменьшить мерцание, я использовал строка). Я не буду повторять процесс написания здесь, я буду в основном говорить о логике самых основных функций и некоторых функций, которые раньше использовались меньше.

1. Базовая логика функции

1. Фон и печать игры

Определите двумерную строку символов, используйте «■» и пробел, чтобы указать границу, тело змеи, пробел и т. Д. Печать заключается в использовании цикла for для прохождения всей строки и обновления ее с определенной частотой для достижения игрового эффекта.

2. Создайте массив змей

Учитывая, что я ничего не сделал со связанным списком и не очень опытен, я использовал массивы для создания змей. Массив в основном имеет ограниченную емкость, сначала нужно определить самую длинную длину (при условии, что я установил его достаточно долго), и во многих местах нужно взять адрес (N раз «&») и другие недостатки. В массиве хранятся такие параметры, как номер узла змеи, координаты XY и направление движения. Главное, что следует отметить, это то, что «■» занимает два байта, и при записи координат его нужно умножить на два во многих местах.

3. Генерация случайных координат змеи

Сначала посадите случайное семя и используйте системное время в качестве семени. Определите переменные x и y в качестве значений координат и используйте функцию rand () с остатком, чтобы получить желаемый диапазон значений координат. Затем сначала создайте два или три раздела.

4. Нарисуйте змею на карте

Создайте цикл for для обхода всей змеи и используйте функцию strncpy (), чтобы скопировать пустую часть как «■».

5. Движение змей

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

6. Сотрите дорожку движения

Запись к предыдущему шагу обнаружит, что змея становится все длиннее и длиннее. , , , Так же, как курсор мыши после сбоя. , , , Это связано с тем, что хотя атрибуты предыдущего узла назначены последнему узлу, этот узел не изменился. Поэтому перед каждым упражнением стирайте предыдущую змею, метод такой же, как четвертый шаг, просто замените «■» на два пробела.

7. Змея меняет направление

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

8. Производить еду

Случайные координаты, копирование, печать.

9. Змеи долго едят пищу

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

Во-вторых, некоторые функции или что-то

1. Консоль воспроизводит музыку.

Консоль воспроизводит музыку с помощью функции «PlaySoud ()».
При использовании функции PlaySound добавьте #include <windows.h> после:

#include <mmsystem.h>
#pragma comment(lib, "WINMM.LIB")

playsound () требует трех функций, первая из которых может быть именем файла WAVE, или именем ресурса WAV, или указателем звуковых данных в памяти, или звуком системного события, определенным в системном реестре WIN.INI. Если параметр имеет значение NULL, остановите воспроизводимый звук (чтобы вы могли использовать PlaySound (NULL, 0, 0), чтобы остановить воспроизведение музыки). Второй и третий — некоторые другие признаки игры.

2. Абсолютный путь, относительный путь и т. Д.

Когда вышеуказанная функция playsound () вызывает файл wav, путь к файлу обязателен. Можно ввести абсолютный путь, начиная с буквы диска и затем чего угодно. Это может быть полезно только на вашем компьютере. Второй — это относительный путь, поместите файл wav и исполняемый файл в одну и ту же папку (для этого нужно только ввести имя файла в vs2005, а в vs2017, который я использую, нужно написать «.// имя файла»), этот метод Может быть опубликован, и музыкальные файлы могут быть заменены в любое время, если имя совпадает. Третье — добавить в файл ресурсов, это можно вызвать только путем ввода имени файла, но это приведет к тому, что исполняемый файл будет слишком большим, и его не удобно изменять.

3. getch () и GetAsyncKeyState (), getchar ()

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

Вот наконец то, написал играбельный МОРСКОЙ БОЙ, хромает только компоновка кода.
Функции по разному понатыканы, все компилируется в студии! 5 файлов:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//Start_M.cpp
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
 
using namespace std;
#include "Class_player.h"
#include "Funk_for_MB.h"
    player human;
    player computer;
 
 
 
 
int main()
{
int whoisturn=1;
int *korC, *tmp,*korH;
int palubC=0,palubH=0;
  setlocale(LC_CTYPE, "Russian");
  int message = 0; // переменная хранит коды сообщений
// установка начального значения генератора случайных чисел
  srand(time(NULL) );
  human.ships_init();
  computer.ships_init();
//--------------------------
 
  while (message != 2)
  {
  map_init(map);
    int user_input = 0;
    system("cls");
    show(map);
/* map_initC(map); Это если хотите подглядывать поле кмпьютера!(для отладки)
  cout<<endl;
      show(map);*/
    message = 0;
 
int characte, digi;
char character, digit;
 
  
 
switch(whoisturn){
    case 1:
        cout<<endl<<"Ход игрока"<<endl;
    input(human, character, digit);
//character=rand()%10;
//digit=rand()%10;
   if( human.turn(computer,character, digit)){
       human.hits[character][digit]=9;
       if(palubC==0){
        palubC=1;
        korC=new int[palubC*2];
        *(korC)=character;
        *(korC+1)=digit;
       }
       else
       {
        palubC++;
        tmp=new int[palubC*2];
        for(int i=0;i<(palubC*2)-2;i++)
        *(tmp+i)=*(korC+i);
        delete[]korC;
        korC=tmp;
        *(korC+((palubC*2)-2))=character;
        *(korC+((palubC*2)-2)+1)=digit;
       }
 
    if  (ship_die(computer,korC,palubC*2)){
        do_after_die(human,korC,palubC*2);
    system("cls");  
    cout<<endl<<"Вы УБИЛИ корабль компьтера!!!";
    Sleep(3000);
        whoisturn=1;
        palubC=0;
        delete[] korC;
    }
    else
    {
    system("cls");  
    cout<<endl<<"Вы РАНИЛИ корабль компьтера!!!nttНастоятельно рекомендую ДОБИТЬ иначе будут глюки!!! :))";
    Sleep(3000);
        whoisturn=1;
    }
   }
   else
   {
    human.hits[character][digit]=1;
    if( palubH>0)
    whoisturn=3;
    else
    whoisturn=2;
   }
//      system("pause");
        break;
    case 2:
        {
 
computer.forturn(computer,characte, digi);
if (computer.turn(human,characte, digi)){
    computer.hits[characte][digi]=9;
    palubH=1;
    korH=new int[palubH*2];
    *(korH)=characte;
    *(korH+1)=digi;
    if  (ship_die(human,korH,palubH*2)){
    do_after_die(computer,korH,palubH*2);
    system("cls");  
    cout<<endl<<"Компьтер УБИЛЛЛ ваш корабль!!!";
    Sleep(3000);
        whoisturn=2;
        palubH=0;
        delete[] korH;
        
    }
    else
    {
        system("cls");
        cout<<endl<<"Компьтер РАНИЛЛЛ ваш корабль!!!";
        Sleep(3000);
        whoisturn=3;
    }
}
else
{
        computer.hits[characte][digi]=1;
                whoisturn=1;
}
 
}
break;
    case 3:
    input(characte, digi,computer ,korH,2*palubH);
   if( computer.turn(human,characte, digi)){
       computer.hits[characte][digi]=9;
       palubH+=1;
        tmp=new int[palubH*2];
        for(int i=0;i<(palubH*2)-2;i++)
        *(tmp+i)=*(korH+i);
        delete[]korH;
        korH=tmp;
        *(korH+((palubH*2)-2))=characte;
        *(korH+((palubH*2)-2)+1)=digi;
    if  (ship_die(human,korH,palubH*2)){
        do_after_die(computer,korH,palubH*2);
 
        delete [] korH;
        palubH=0;
    system("cls");  
    cout<<endl<<"Компьтер УБИЛЛЛ ваш корабль!!!";
    Sleep(3000);
 
        whoisturn=2;
    }
    else
    {
        system("cls");
        cout<<endl<<"Компьтер РАНИЛЛЛ ваш корабль!!!";
        Sleep(3000);
        whoisturn=3;
    }
   }
   else
   {
    computer.hits[characte][digi]=1;
    whoisturn=1;
   }
        /*system("pause");*/
        break;
}
computer.defeat();
human.defeat();
 
    message = check_ending();
  }
if(computer.defeat_flag){
    system ("cls");
    cout<<"ntПоздравляю ВАС ИГРОК - ФЛОТ противника разбит!!!";
}
if(human.defeat_flag){
    system ("cls");
    cout<<"ntКомпьютер РАЗБИЛ ВАШ Флот- эх игрок ;)!!!";
}   
  getch();
  return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//Funk_for_MB.cpp
#include "Class_player.h"
#include <iostream>
using namespace std;
const int s=13, c=29;
char numbers[]={'0','1','2','3','4','5','6','7','8','9'};
bool chekRange(int St,int _1,int _2,int End){
    if ((St<=_1)&&(St<=_2))
        if((End>=_1)&&(End>=_2))
            return true;
    return false;
}
void show(char map[s][c]){
    cout<<endl;
    for (int i=0;i<s;i++){
        for(int j=0;j<c;j++)
            cout<<map[i][j];
        cout<<endl;}
    }
void map_init(char map[s][c]){//здесь происходит помещение данных о кораблях игрока которые берутся из human.ships
    for (int i=0;i<s;i++)
        for(int j=0;j<c;j++){
            if((j>=2)&&(j<=11))
                if((i>=2)&&(i<=11)){
                    if (human.ships[i-2][j-2]==1)
                    map[i][j]= 49;
                    if (human.ships[i-2][j-2]==2)
                    map[i][j]= 50;
                    if (human.ships[i-2][j-2]==3)
                    map[i][j]= 51;
                }
            if((j>=17)&&(j<=26))
                if((i>=2)&&(i<=11)){
                    if (human.hits[i-2][j-17]==0)
                    map[i][j]= 48;
                    if (human.hits[i-2][j-17]==1)
                    map[i][j]= 49;
                    if (human.hits[i-2][j-17]==9)
                    map[i][j]= 'A';
 
        }
}
}
void map_initC(char map[s][c]){
    //функция для записи в графический интерфейс полей компьтера
    //Эта функция пригодится для отладки
    for (int i=0;i<s;i++)
        for(int j=0;j<c;j++){
            if((j>=2)&&(j<=11))
                if((i>=2)&&(i<=11)){
                    if (computer.ships[i-2][j-2]==1)
                    map[i][j]= 49;
                    if (computer.ships[i-2][j-2]==2)
                    map[i][j]= 50;
                    if (computer.ships[i-2][j-2]==3)
                    map[i][j]= 51;
                }
            if((j>=17)&&(j<=26))
                if((i>=2)&&(i<=11)){
                    if (computer.hits[i-2][j-17]==0)
                    map[i][j]= 48;
                    if (computer.hits[i-2][j-17]==1)
                    map[i][j]= 49;
                    if (computer.hits[i-2][j-17]==9)
                    map[i][j]= 'A';
 
        }
}
}
int check_ending(){
    if((human.defeat_flag)||(computer.defeat_flag))
    return 2;
    else 
        return 0;
}
void input (player& H, char& character,char& digit){
    int S, C, TR=0;
    for(;;){
    cout<<endl<<"Enter координату по строкам"<<endl;
    character=getche();
    cout<<endl<<"Enter координату по столбцам"<<endl;
    digit=getche();
    for(int i=0;i<10;i++){
        if (numbers[i] == character){
            S=i;
            TR++;
        }
        if (numbers[i] == digit){
            C=i;
            TR++;
        }
    }
    if(TR==2){
    if(H.hits[S][C]==0){
    character=S;
    digit=C;
    return ;
    }
    else
    cout<<"nВы ввели значени куда уже стреляли введите еще раз:n";
    }
    else
    {
    cout<<"nФигню вводить не надо!!n";
    TR=0;
    }
    }
 
 
}
void input (int& character,int& digit,player& C, int *kor, int n){
    int match=1;
    if(n==2)
        for(;;){
            character=*kor;
            digit=*(kor+1);
            switch(match)
            {
            case 1:
                if((chekRange(0,character+1,digit,9))&&(C.hits[character+1][digit]==0)){
                    character++;
                    return ;
                }
                else
                    match=2;
            break;
            case 2:
                if((chekRange(0,character-1,digit,9))&&(C.hits[character-1][digit]==0)){
                    character--;
                    return ;
                }
                else
                    match=3;
 
                break;
            case 3:
                if((chekRange(0,character,digit+1,9))&&(C.hits[character][digit+1]==0)){
                    digit++;
                    return ;
                }
                else
                    match=4;
 
                break;
            case 4:
                if((chekRange(0,character,digit-1,9))&&(C.hits[character][digit-1]==0)){
                    digit--;
                    return ;
                }
                else
                    match=5;
                break;
            }
        }
    if(n==4){
        
            if((*(kor)-*(kor+2))==-1){
            character=*(kor+2);
            digit=*(kor+1);
            }
            if((*(kor)-*(kor+2))==1){
            character=*(kor);
            digit=*(kor+1);
            }
            if((*(kor+1)-*(kor+3))==-1){
            character=*(kor);
            digit=*(kor+3);
            match=3;
            }
            if((*(kor+1)-*(kor+3))==1){
            character=*(kor);
            digit=*(kor+1);
            match=3;
            }
       for(;;){
            switch(match)
            {
            case 1:
                if((chekRange(0,character+1,digit,9))&&(C.hits[character+1][digit]==0)){
                    character++;
                    return ;
                }
                else
                    match=2;
            break;
            case 2:
                if((chekRange(0,character-2,digit,9))&&(C.hits[character-2][digit]==0)){
                    character-=2;
                    return ;
                }
                else
                    match=5;
 
                break;
            case 3:
                if((chekRange(0,character,digit+1,9))&&(C.hits[character][digit+1]==0)){
                    digit++;
                    return ;
                }
                else
                    match=4;
 
                break;
            case 4:
                if((chekRange(0,character,digit-2,9))&&(C.hits[character][digit-2]==0)){
                    digit-=2;
                    return ;
                }
                else
                    match=5;
                break;
            }
        
            if(match==5)
                break;
        }
    }
    if(n==6){
            if((*(kor)-*(kor+2))==0){
            character=*(kor+2);
            digit=*(kor+1);
                if(digit<*(kor+3))
                    digit=*(kor+3);
                if(digit<*(kor+5))
                    digit=*(kor+5);
                match=3;
            }
            if((*(kor+1)-*(kor+3))==0){
            digit=*(kor+1);
            character=*(kor);
                if(character<*(kor+2))
            character=*(kor+2);
                if(character<*(kor+4))
            character=*(kor+4);
            }
 
       for(;;){
            switch(match)
            {
            case 1:
                if((chekRange(0,character+1,digit,9))&&(C.hits[character+1][digit]==0)){
                    character++;
                    return ;
                }
                else
                    match=2;
            break;
            case 2:
                if((chekRange(0,character-3,digit,9))&&(C.hits[character-3][digit]==0)){
                    character-=3;
                    return ;
                }
                else
                    match=5;
 
                break;
            case 3:
                if((chekRange(0,character,digit+1,9))&&(C.hits[character][digit+1]==0)){
                    digit++;
                    return ;
                }
                else
                    match=4;
 
                break;
            case 4:
                if((chekRange(0,character,digit-3,9))&&(C.hits[character][digit-3]==0)){
                    digit-=3;
                    return ;
                }
                else
                    match=5;
                break;
            }
        
            if(match==5)
                break;
        }
    }
 
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//Class_player.cpp
#include "Class_player.h"
player::player (){
        defeat_flag=0;
        
        //крнтсруктор класса player
    }
void player::ships_init(){
        //Инициализация массива ships помещение в него кораблей
        for(int i=0;i<10;i++)
            for(int j=0;j<10;j++){
                hits[i][j]=0;
                ships[i][j]=1;
        }
    for(int i=4;i>0;i--)
            for(int j=i; j<5; j++){
                 set(i);
                  //Вызываем функцию которая устанавливает корабли
 
            }
    }
    void player::set(int deck){
        //Заполнить генератором случ чисел направления и координаты
        //в
    bool doit=true;
        direction d;
    
        
        do {
            if (rand()%2)
                d=h;
            else
                d=v;
 
    int S=rand()%10;    
    int C=rand()%10;
    doit=place_ship(S,C,d,deck);
 
        }while(!doit);
 
    }
    bool player::place_ship(int s,int c, direction dir, int desk){
        //
        //
    //  bool doit=true;
        //for (int i=
        switch(dir){
            case v:
                    if (s>=desk-1)
    {
                if(s==desk-1){
            for(int i=1;i>=-(desk-1);i--)
                for(int j=1;j>=-1;j--){
                    if(((s+i)<0)||((c+j)<0)) continue;
                    if(((s+i)>9)||((c+j)>9)) continue;
    //          cout<<"n"<<"s+i= "<<s+i<<"  c+j= "<<c+j;
 
                    if(ships[s+i][c+j]==2){
                        return false;
                    }
                }
        }
        if(s>desk-1){
            for(int i=1;i>=-desk;i--)
                for(int j=1;j>=-1;j--){
                    if(((s+i)<0)||((c+j)<0)) continue;
                    if(((s+i)>9)||((c+j)>9)) continue;
    //                  cout<<"n"<<"s+i= "<<s+i<<"  c+j= "<<c+j;
                    if(ships[s+i][c+j]==2){
                        return false;
 
                    }
                }
        }
 
        for(int i=desk;i>0;i--)
                ships[s-(desk-i)][c]=2;
            return true;
        }
    else
    {
        return false;
    }
                    
                break;
            case h:
    if (c>=desk-1)
    {
        if(c==desk-1){
            for(int i=1;i>=-1;i--)
                for(int j=1;j>=-(desk-1);j--){
                    if(((s+i)<0)||((c+j)<0)) continue;
                    if(((s+i)>9)||((c+j)>9)) continue;
    //          cout<<"n"<<"s+i= "<<s+i<<"  c+j= "<<c+j;
 
                    if(ships[s+i][c+j]==2){
                        return false;
                    }
                }
        }
        if(c>desk-1){
            for(int i=1;i>=-1;i--)
                for(int j=1;j>=-desk;j--){
                    if(((s+i)<0)||((c+j)<0)) continue;
                    if(((s+i)>9)||((c+j)>9)) continue;
    //                  cout<<"n"<<"s+i= "<<s+i<<"  c+j= "<<c+j;
                    if(ships[s+i][c+j]==2){
                        return false;
 
                    }
                }
        }
        for(int i=desk-1;i>=0;i--)
                ships[s][(c-i)]=2;
        return true;
    }
    else
    {
        return false;
    }
                break;
        
 
 
    }
    }
    bool player::turn(player& computer, int character,int digit){
 
        if ((computer.ships[character][digit]==2)||(computer.ships[character][digit]==3)){
            computer.ships[character][digit]=3;
            return true;}
        return false;
    }
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//Funk_for_MB.h
#ifndef _FUNK_FOR_MB_
#define _FUNK_FOR_MB_
 
const int s=13, c=29;
char map[s][c]={
    "  0123456789     0123456789 ",
    " #----------#   #----------#",
    "0|          |  0|          |",
    "1|          |  1|          |",
    "2|          |  2|          |",
    "3|          |  3|          |",
    "4|          |  4|          |",
    "5|          |  5|          |",
    "6|          |  6|          |",
    "7|          |  7|          |",
    "8|          |  8|          |",
    "9|          |  9|          |",
    " #----------#   #----------#"};
 
 
 
void map_init(char map[s][c]);
void map_initC(char map[s][c]);//Техническая Ф-ция для отображения полей Компа
 
void show(char map[s][c]);
 
void input (player& H, char& character,char& digit);
 
void test();
int check_ending();
 
/**/bool chekRange(int St,int _1,int _2,int End);
int IQ (player& human , int Sc,int Cc){
    for(int i=-1;i<2;i++)
        for(int j=-1;j<2;j++)
            if(chekRange(0,Sc+i,Cc+j,9))
                if (human.ships[Sc+i][Cc+j]==2)
                    return 1;
    return 0;
}
void logic_hit (player& C, int Sc,int Cc){
    for(int i=-1;i<2;i++)
        for(int j=-1;j<2;j++)
            if(chekRange(0,Sc+i,Cc+j,9))
                if ((C.hits[Sc+i][Cc+j]!=1)&&(C.hits[Sc+i][Cc+j]!=9))
                    C.hits[Sc+i][Cc+j]=1;
}
 
void input (int& character,int& digit,player& C, int *kor, int n);
/*bool chekRange(int St,int _1,int _2,int End){
    if ((St<=_1)&&(St<=_2))
        if((End>=_1)&&(End>=_2))
            return true;
    return false;
}*/
 
bool ship_die (player& human, int *k, int n){
    int car, dig;
    int count=0;
    for(int i=0; i<n; i++){
        if (i%2==0)
            car=k[i];
        if (i%2==1){
            dig=k[i];
            count+=IQ(human,car,dig);}
    }
    if (count==0)
        return true;
    else 
        return false;
}
void do_after_die (player& human, int *k, int n){
    int car, dig;
    for(int i=0; i<n; i++){
        if (i%2==0)
            car=k[i];
        if (i%2==1){
            dig=k[i];
            logic_hit(human,car,dig);
            }
    }
}
 
#endif //_FUNK_FOR_MB_
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//Class_player.h 
#ifndef _CLASS_PLAYER_
#define _CLASS_PLAYER_
 
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
 
enum direction {v=1,h=2};
class player
{
public:
    bool defeat_flag;
    int hits[10][10];// маска попаданий принимает либо 0 либо 1 или 9
    int ships[10][10];// маска кораблей 1-море 2-корабль 3 убитый корабль
    player ();
 
    void ships_init();
    void set(int deck);
bool place_ship(int s,int c, direction dir, int desk);
 
    bool turn(player& computer, int character,int digit);
 
    void forturn(player& computer, int &character,int &digit){
 
         for(;;){
         character=rand()%10;
        digit=rand()%10;
        if((computer.hits[character][digit]==9)||(computer.hits[character][digit]==1))
            continue;
        else 
            break;
         }
 
    }
 
    void defeat(){
        for(int i=0;i<10;i++)
            for(int j=0;j<10;j++)
                if (ships[i][j]==2)
                    return;
            
defeat_flag=true;
return;
    }
 
};
extern  player human;
extern player computer;
 
#endif /*_CLASS_PLAYER_*/

Я так понял здесь на форуме два типа людей, одни профессионалы, которым писать консольные игрушки вообще не надо, они умеют просто не надо. И второй тип это ленивые(ну может времени нету) начинающие , которые просто не доросли, между этими людьми пропасть.
Та вот: Ищу людей которым будет полезно пописать консольные игрушки на Си++ для совместной разработки. И возможно, какого-то толкового профи, который знает, как толково руководить разработкой таких программы.

Я думаю следующую программу я буду писать это консольный тетрис — есть предложения, или умные советы, или толковые ссылки в сети???

Также принимаются замечания по коду морского боя, (зы по нужным файлам функции я еще раскидаю, еще не знаю будет либо 5 либо 7 файлов в проекте). Нужен небольшой анализ на тему какие функции стоило-бы разместить внутри класса(плеер).

Добавлено через 49 минут
Нашел исходник тетриса!
http://p-a2.blogspot.com/2012/04/tetris-c.html
Вот здесь вроде все работает , буду разбирать )



0



Понравилась статья? Поделить с друзьями:
  • Как написать конец эссе
  • Как написать конец сочинения рассуждения
  • Как написать конец репортажа
  • Как написать конец презентации
  • Как написать конец объяснительной