Advertisement
Ilitid

фыфы

Dec 13th, 2019
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.60 KB | None | 0 0
  1. // ThreadWar.cpp : Defines the entry point for the console application.
  2.  
  3. //
  4.  
  5.  
  6.  
  7. #include "stdafx.h"
  8.  
  9.  
  10.  
  11. //      Простая компьютерная игра Thread War
  12.  
  13. //      Thread War'
  14.  
  15. //      Используйте клавиши "влево" и "вправо", чтобы перемещать пушку
  16.  
  17. //      клавиша "пробел" производит выстрел
  18.  
  19. //      Если 30 врагов уйдут с экрана неуничтоженными,  вы проиграли
  20.  
  21. //      Очки даются за каждого убитого противника
  22.  
  23. #include <windows.h>
  24.  
  25. #include <process.h>
  26.  
  27. #include <stdlib.h>
  28.  
  29. #include <time.h>
  30.  
  31. #include <stdio.h>
  32.  
  33. // Объекты синхронизации
  34.  
  35. HANDLE screenlock; // изменением экрана занимается только один поток
  36.  
  37. HANDLE bulletsem;  // можно выстрелить только три раза подряд
  38.  
  39. HANDLE startevt;     // игра начинается с нажатием клавиши "влево" или "вправо"
  40.  
  41. HANDLE conin, conout;  // дескрипторы консоли
  42.  
  43. HANDLE mainthread; // Основной поток main
  44.  
  45. CRITICAL_SECTION gameover;
  46.  
  47. CONSOLE_SCREEN_BUFFER_INFO info; // информация о консоли
  48.  
  49. // количество попаданий и промахов
  50.  
  51. long hit=0;
  52.  
  53. long miss=0;
  54.  
  55. long delayfactor=7; // фактор задержки для
  56.  
  57.  
  58.  
  59. // Создание случайного числа от n0 до n1
  60.  
  61. int random(int n0, int n1)
  62.  
  63. {
  64.  
  65.         if (n0==0&&n1==1) return rand()%2;
  66.  
  67.         return rand()%(n1-n0)+n0;
  68.  
  69. }
  70.  
  71.  
  72.  
  73. // Очистка экрана консоли
  74.  
  75. void cls()
  76.  
  77. {
  78.  
  79.         COORD org={0,0};
  80.  
  81.         DWORD res;
  82.  
  83.         FillConsoleOutputCharacter(conout,' ',info.dwSize.X*info.dwSize.Y,org,&res);
  84.  
  85. }
  86.  
  87.  
  88.  
  89. // вывести на экран символ в позицию х и у
  90.  
  91. void writeat (int x,int y, char c)
  92.  
  93. {
  94.  
  95. // Блокировать вывод на экран при помощи мьютекса
  96.  
  97.         WaitForSingleObject(screenlock,INFINITE);
  98.  
  99.         COORD pos={x,y};
  100.  
  101.         DWORD res;
  102.  
  103.         WriteConsoleOutputCharacter(conout, &c , 1 , pos , &res );
  104.  
  105.         ReleaseMutex(screenlock);
  106.  
  107. }
  108.  
  109. // Получить нажатие на клавишу (счетчик повторейний в ct)
  110.  
  111. int getakey(int &ct)
  112.  
  113. {
  114.  
  115.         INPUT_RECORD input;
  116.  
  117.         DWORD res;
  118.  
  119.         while (1)
  120.  
  121.         {
  122.  
  123.                ReadConsoleInput (conin, &input, 1 , &res);
  124.  
  125.                // игнорировать другие события
  126.  
  127.                if (input.EventType!=KEY_EVENT) continue;
  128.  
  129.                // игнорировать события отпускания клавиш
  130.  
  131.                // нас интересуют только нажатия
  132.  
  133.                if (!input.Event.KeyEvent.bKeyDown) continue;
  134.  
  135.                ct=input.Event.KeyEvent.wRepeatCount;
  136.  
  137.                return input.Event.KeyEvent.wVirtualKeyCode;
  138.  
  139.         }
  140.  
  141. }
  142.  
  143.  
  144.  
  145. // Обработка комбинаций ^С. ^Break, и т.п.
  146.  
  147. BOOL WINAPI ctrl (DWORD type)
  148.  
  149. {
  150.  
  151.         exit(0);
  152.  
  153.         return TRUE; // не достижимый участок кода
  154.  
  155. }
  156.  
  157.  
  158.  
  159. // Определить символ в заданной позиции экрана
  160.  
  161. int getat(int x, int y)
  162.  
  163. {
  164.  
  165.         char c;
  166.  
  167.         DWORD res;
  168.  
  169.         COORD org={x,y};
  170.  
  171.         // Блокировать доступ к консоли до тех пор, пока процедура не будет выполнена
  172.  
  173.         WaitForSingleObject(screenlock,INFINITE);
  174.  
  175.         ReadConsoleOutputCharacter(conout,&c,1,org,&res);
  176.  
  177.         ReleaseMutex(screenlock); // unlock
  178.  
  179.         return c;
  180.  
  181. }
  182.  
  183.  
  184.  
  185.  
  186.  
  187. // Отобразить очки в заголовке окна и проверить условие завершения игры
  188.  
  189.  
  190.  
  191. void score(void)
  192.  
  193. {
  194.  
  195.         char s[128];
  196.  
  197.         sprintf(s, "Thread War! Попаданий:%d  Промахов:%d", hit, miss);
  198.  
  199.         SetConsoleTitle(s);
  200.  
  201.         if (miss>=30)
  202.  
  203.         {
  204.  
  205.                EnterCriticalSection(&gameover);
  206.  
  207.                SuspendThread(mainthread); // stop main thread
  208.  
  209.                MessageBox(NULL,"Game Over!" ,"Thread War", MB_OK|MB_SETFOREGROUND);
  210.  
  211.                exit(0); // не выходит из критической секции
  212.  
  213.         }
  214.  
  215.         if ((hit+miss)%20==0)
  216.  
  217.                InterlockedDecrement(&delayfactor); // должен быть ilock
  218.  
  219. }
  220.  
  221.  
  222.  
  223. char badchar[]="-\\|/";
  224.  
  225.  
  226.  
  227. // это поток противника
  228.  
  229. void badguy(void *_y)
  230.  
  231. {
  232.  
  233.         int y=(int)_y; // случайная координата у
  234.  
  235.         int dir;
  236.  
  237.         int x;
  238.  
  239.         // нечетные у появляются слева, четные у появляются справа
  240.  
  241.         x=y%2?0:info.dwSize.X;
  242.  
  243.         // установить направление в зависимости от начальной позиции
  244.  
  245.         dir=x?-1:1;
  246.  
  247.         // пока противник находится в пределах экрана
  248.  
  249.         while ((dir==1&&x!=info.dwSize.X)||(dir==-1&&x!=0))
  250.  
  251.         {
  252.  
  253.                int dly;
  254.  
  255.                BOOL hitme=FALSE;
  256.  
  257.                // проверка на попадание (пуля?)
  258.  
  259.                if (getat(x,y)=='*') hitme=TRUE;
  260.  
  261.                // вывод символа на экран
  262.  
  263.                writeat(x,y,badchar[x%4]);
  264.  
  265.                // еще одна проверка на попадание
  266.  
  267.                if (getat(x,y)=='*') hitme=TRUE;
  268.  
  269.                // проверка на попадание через небольшие
  270.  
  271.                //  промежутки времени
  272.  
  273.                if (delayfactor<3) dly=3;
  274.  
  275.                else dly=delayfactor+3;
  276.  
  277.                for (int i=0;i<dly;i++)
  278.  
  279.                {
  280.  
  281.                        Sleep(40);
  282.  
  283.                        if (getat(x,y)=='*')
  284.  
  285.                        {
  286.  
  287.                                hitme=TRUE;
  288.  
  289.                                break;
  290.  
  291.                        }
  292.  
  293.                }
  294.  
  295.                writeat(x,y, ' ');
  296.  
  297. // еще одна проверка на попадание
  298.  
  299.                if (getat(x,y)=='*') hitme=TRUE;
  300.  
  301.                if (hitme)
  302.  
  303.                {
  304.  
  305.                        // в противника попали!
  306.  
  307.                        MessageBeep(-1);
  308.  
  309.                        InterlockedIncrement(&hit) ;
  310.  
  311.                        score();
  312.  
  313.                        _endthread();
  314.  
  315.                }
  316.  
  317.                x+=dir;
  318.  
  319.         }
  320.  
  321. // противник убежал!
  322.  
  323.         InterlockedIncrement(&miss) ;
  324.  
  325.         score();
  326.  
  327. }
  328.  
  329.  
  330.  
  331. // этот поток занимается созданием потоков противников
  332.  
  333. void badguys(void *)
  334.  
  335. {
  336.  
  337. // ждем сигнала к началу игры в течение 15 секунд
  338.  
  339.         WaitForSingleObject(startevt, 15000);
  340.  
  341.         // создаем случайного врага
  342.  
  343.         // каждые 5 секунд появляется шанс создать
  344.  
  345.         // противника с координатами от 1 до 10
  346.  
  347.         while (1)
  348.  
  349.         {
  350.  
  351.                if (random(0,100)<(hit+miss)/25+20)
  352.  
  353.                // со временем вероятность увеличивается
  354.  
  355.                _beginthread(badguy,0, (void *)(random(1,10)));
  356.  
  357.                Sleep(1000); // каждую секунду
  358.  
  359.         }
  360.  
  361. }
  362.  
  363.  
  364.  
  365. // Это поток пули
  366.  
  367. // каждая пуля - это отдельный поток
  368.  
  369. void bullet(void *_xy_)
  370.  
  371. {
  372.  
  373.         COORD xy=*(COORD *)_xy_;
  374.  
  375.         if (getat(xy.X,xy.Y)=='*') return; // здесь уже есть пуля
  376.  
  377.         // надо подождать
  378.  
  379.         // Проверить семафор
  380.  
  381.         // если семафор равен 0, выстрела не происходит
  382.  
  383.         if (WaitForSingleObject(bulletsem,0)==WAIT_TIMEOUT) return;
  384.  
  385.  
  386.  
  387.         while (--xy.Y)
  388.  
  389.         {
  390.  
  391.                writeat(xy.X,xy.Y,'*'); // отобразить пулю
  392.  
  393.                Sleep(100);
  394.  
  395.                writeat(xy.X, xy.Y, ' ');    // стереть пулю
  396.  
  397.         }
  398.  
  399.         // выстрел сделан.- добавить 1 к семафору
  400.  
  401.         ReleaseSemaphore ( bulletsem, 1, NULL);
  402.  
  403. }
  404.  
  405. // Основная программа
  406.  
  407. void main()
  408.  
  409. {
  410.  
  411.         HANDLE me;
  412.  
  413.         // Настройка глобальных переменных
  414.  
  415.         conin=GetStdHandle(STD_INPUT_HANDLE );
  416.  
  417.         conout=GetStdHandle(STD_OUTPUT_HANDLE);
  418.  
  419.         SetConsoleCtrlHandler(ctrl,TRUE);
  420.  
  421.         SetConsoleMode(conin, ENABLE_WINDOW_INPUT);
  422.  
  423.         me=GetCurrentThread(); // не является реальным дескриптором
  424.  
  425.         // изменить псевдодескриптор на реальный дескриптор текущего потока
  426.  
  427.         DuplicateHandle(GetCurrentProcess(),me,GetCurrentProcess(), &mainthread, 0, FALSE, DUPLICATE_SAME_ACCESS);
  428.  
  429.         startevt=CreateEvent(NULL, TRUE, FALSE, NULL);
  430.  
  431.         screenlock=CreateMutex(NULL, FALSE, NULL);
  432.  
  433.         InitializeCriticalSection ( &gameover);
  434.  
  435.         bulletsem=CreateSemaphore(NULL, 3, 3, NULL);
  436.  
  437.         GetConsoleScreenBufferInfo(conout, &info);
  438.  
  439.  
  440.  
  441.         // Инициализировать отображение информации об очках
  442.  
  443.         score();
  444.  
  445.         // Настроить генератор случайных чисел
  446.  
  447.         srand((unsigned)time(NULL));
  448.  
  449.         cls(); // на самом деле не нужно
  450.  
  451.         // установка начальной позиции пушки
  452.  
  453.         int y=info.dwSize.Y-1;
  454.  
  455.         int x=info.dwSize.X/2;
  456.  
  457.         // запустить поток badguys; ничего не делать до тех пор,
  458.  
  459.         // пока не произойдет событие или истекут 15 секунд
  460.  
  461.         _beginthread (badguys, 0, NULL); // основной цикл игры
  462.  
  463.         while (1)
  464.  
  465.         {
  466.  
  467.                int c,ct;
  468.  
  469.                writeat(x,y, '|'); // нарисовать пушку
  470.  
  471.                c=getakey(ct);   // получить символ
  472.  
  473.                switch (c)
  474.  
  475.                {
  476.  
  477.                case VK_SPACE:
  478.  
  479.                        {
  480.  
  481.                                static COORD xy;
  482.  
  483.                                xy.X=x;
  484.  
  485.                                xy.Y=y;
  486.  
  487.                                _beginthread(bullet,0,(void *)&xy);
  488.  
  489.                                Sleep(100); // дать пуле время улететь на некоторое расстояние
  490.  
  491.                                break;
  492.  
  493.                        }
  494.  
  495.                case VK_LEFT:  // команда "влево!"
  496.  
  497.                        SetEvent(startevt);    // поток badguys работает
  498.  
  499.                        writeat(x,y,' ');      // убрать с экрана пушку
  500.  
  501.                        while (ct--)        // переместиться
  502.  
  503.                                if (x) x--;
  504.  
  505.                        break;
  506.  
  507.                case VK_RIGHT: // команда "вправо!"; логика та же
  508.  
  509.                        SetEvent(startevt);
  510.  
  511.                        writeat(x,y,' ');
  512.  
  513.                        while (ct--)
  514.  
  515.                                if (x!=info.dwSize.X-1) x++;
  516.  
  517.                        break;
  518.  
  519.                }
  520.  
  521.         }
  522.  
  523. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement