Сапер

Всякие игры. Для всех платформ.

Сапер

Сообщение rvg » 26 авг 2024, 11:32

Сапер. MS-Dos игра. Работает в Windows XP (выше версии Windows - DosBOX).
Исходный код прилагается.
Для сборки нужен Borland C++ (наверное, можно любым). Здесь, для сборки, использовалась версия Borland C++ 5.02.
 Развернуть: Saper.cpp
Код: Выделить всё
// Saper.cpp

#include <dos.h>
#include <conio.h>
#include <graphics.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>

#define YES 1
#define NO  0
#define XPX 15 /* X pixels by square */
#define YPX 15 /* Y pixels by square */
#define DEFCX 30 /* Default number of squares */
#define DEFCY 28
#define MINE 255-'0' /* So that when it prints, it prints char 0xff */

struct STSQUARE {
   unsigned char value; /* Number of mines in the surround squares */
   unsigned char sqopen; /* Square is open */
   unsigned char sqpress; /* Square is pressed */
   unsigned char sqmark; /* Square is marked */
} *psquare;

#define value(x,y) (psquare+(x)*ncy+(y))->value
#define sqopen(x,y) (psquare+(x)*ncy+(y))->sqopen
#define sqpress(x,y) (psquare+(x)*ncy+(y))->sqpress
#define sqmark(x,y) (psquare+(x)*ncy+(y))->sqmark

int XST, /* Offset of first pixel X */
   YST,
   ncx, /* Number of squares in X */
   ncy,
   cmines,   /* Mines discovered */
   initmines, /* Number of initial mines */
   sqclosed, /* Squares still closed */
   maxy; /* Max. number of y pixels of the screen */

int mouse_status, mouse_x, mouse_y;

int mouse_reset(void) {
   _AX=0;
   geninterrupt(0x33);
   return _AX;
}

void mouse_enable(void) {
   _AX=1;
   geninterrupt(0x33);
}

void mouse_disable(void) {
   _AX=2;
   geninterrupt(0x33);
}

void mouse_read_cursor(void) {
   _AX=3;
   geninterrupt(0x33);
   mouse_status=_BX;
   mouse_x=_CX;
   mouse_y=_DX;
}

void mouse_horizontal_range(int xmin, int xmax) {
   _AX=7;
   _CX=xmin;
   _DX=xmax;
   geninterrupt(0x33);
}

void mouse_vertical_range(int ymin, int ymax) {
   _AX=8;
   _CX=ymin;
   _DX=ymax;
   geninterrupt(0x33);
}

void Set_mines(int nminas)
{
   int i, x, y, a, b;
   sqclosed = ncx * ncy - nminas;
   STSQUARE* p = psquare;
   for (i=ncx*ncy; i>0; --i, ++p)
      p->value = p->sqopen = p->sqpress = p->sqmark = NO;
   for (i=nminas; i>0; --i)
   {
      while (value(x=random(ncx), y=random(ncy)) == MINE);
         value(x,y)=MINE;
   }
   for (x=ncx-1; x>=0; --x)
   {
      for (y=ncy-1; y>=0; --y)
      {
         if (value(x,y) == MINE)
            continue;
         a=x-1;
         b=y-1;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         a++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         a++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         b++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         a-=2;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         b++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         a++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
         a++;
         if (a>=0 && b>=0 && a<ncx && b<ncy)
            value(x,y)+=(value(a,b) == MINE);
      }
   }
}

void Read_param(int argc, char *argv[])
{
   int x, y, m;
   x=y=m=0;
   if (argc!=1)
   {
      if (!isdigit(*argv[1]))
      {
         closegraph();
         cprintf(
         " Usage is: %s [x] [y] [m]\r\n\n"
         " Where x is the horizontal size\r\n"
         "      y is the vertical size\r\n"
         "      m is the number of mines\r\n\n"
         " Left mouse button: Open the square\r\n"
         " Right mouse button: Mark the square\r\n"
         " - The first time puts a 'mine' mark\r\n"
         " - The second time puts a 'possible "
         " mine' mark\r\n"
         " - The third time unmarks the square\r\n"
         " Left+Right buttons: Open the surrounded squares only if "
         " the count of mines\r\n"
         " is equal to the number in the square",
         argv[0]);
         exit (1);
      }
      
      switch (argc)
      {
      case 4:
         m=atoi(argv[3]);
      case 3:
         y=atoi(argv[2]);
      case 2:
         x=atoi(argv[1]);
      }
   }
   XST=100;
   ncx=DEFCX;
   if (maxy==479)
   {
      YST=30;
      ncy=DEFCY;
   }
   else
   {
      YST=25;
      ncy=20;
   }
   if (x>0 && x<ncx)
      ncx=x;
   if (y>0 && y<ncy)
   {
      YST+=((ncy-y)*YPX)>>1;
      ncy=y;
   }
   initmines= m ? m : ncx*ncy*4/25; /* There are about 16% of mines */
   if (((void*)psquare = calloc(ncx*ncy, sizeof(STSQUARE)))==NULL)
   {
      closegraph();
      printf("Failed. Not enought memory.\n");
      exit(1);
   }
}

/*
   If status=1 then draw the square up, if it's 0 then draw it down
*/
void Set_square(int x, int y, int status)
{
   mouse_disable();
   int xl = XST + XPX * x;
   int xr = xl + XPX - 1;
   int yt = YST + YPX * y;
   int yb = yt + YPX - 1;
   
   setfillstyle(SOLID_FILL, LIGHTGRAY);
   bar(xl, yt, xr, yb);
   if (status)
   {
      setcolor(WHITE);
      line(xl,yt,xl,yb-1);
      line(xl,yt,xr-1,yt);
      setcolor(DARKGRAY);
      line(xr,yb,xl,yb);
      line(xr,yb,xr,yt);

      switch (sqmark(x,y))
      {
      case 2 : setfillstyle(SOLID_FILL, LIGHTBLUE);
      setcolor(LIGHTBLUE);
      break;
      case 1 : setfillstyle(SOLID_FILL, LIGHTRED);
      setcolor(LIGHTRED);
      break;
      default: setcolor(LIGHTGRAY);
      }
      fillellipse(XST+XPX*x+XPX/2, YST+YPX*y+YPX/2, 3, 3);

      switch (sqmark(x,y))
      {
      case 2 :
      case 1 :
      setfillstyle(SOLID_FILL, YELLOW);
      setcolor(YELLOW);
      fillellipse(XST+XPX*x+XPX/2, YST+YPX*y+YPX/2, 1, 1);
      }
   }
   else
   {
      --sqclosed;
      setcolor(DARKGRAY);
      line(xl,yt,xl,yb);
      line(xl,yt,xr,yt);
   }
   mouse_enable();
}

void Draw_squares(void)
{
   mouse_disable();
   for (int x=0; x<ncx; x++)
      for (int y=0; y<ncy; y++)
         Set_square(x,y,1);
   mouse_enable();
}

void Blow_up(void)
{
   int x, y, xl, yt, xr, yb;

   mouse_disable();
   for (x=0; x<ncx; x++) {
      for (y=0; y<ncy; y++) {
    if (value(x,y) == MINE) {
       settextjustify(CENTER_TEXT, CENTER_TEXT);
       setcolor(LIGHTRED);
       outtextxy(XST+XPX*x+XPX/2-1, YST+YPX*y+YPX/2, "Ы");
       setcolor(BLACK);
       outtextxy(XST+XPX*x+XPX/2, YST+YPX*y+YPX/2+1, "*");
    }
    else if (sqmark(x,y)==1) {
       setcolor(YELLOW);
       xl=XST+XPX*x;
       xr=xl+XPX-1;
       yt=YST+YPX*y;
       yb=yt+YPX-1;
       line(xl,yt,xr,yb);
       line(xl,yb,xr,yt);
    }
      }
   }
}

void Open_square(int x, int y)
{
   char num[2] = "0";
   int a, b, c;

   sqopen(x,y)=YES;
   if ((num[0]=value(x,y)) != 0) {
      num[0]+='0';
      switch(num[0]) {
    case '1' : c=LIGHTBLUE; break;
    case '2' : c=LIGHTGREEN; break;
    case '3' : c=YELLOW; break;
    case '4' : c=LIGHTRED; break;
    default  : c=LIGHTMAGENTA;
      }
      mouse_disable();
      setcolor(c);
      settextjustify(CENTER_TEXT, CENTER_TEXT);
      outtextxy(XST+XPX*x+XPX/2, YST+YPX*y+YPX/2+1, num);
      mouse_enable();
   }
   else {      /* Открыть квадрат рядом, если текущий равен 0 */
      a=x-1;
      b=y-1;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      b++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a-=2;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      b++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    Set_square(a,b,0);
    Open_square(a,b);
      }
   }
}

/*
   Open the sorrounded squares. Returns != 0 if I activated a mine
*/
int Open_near_squares(int x, int y)
{
   int a, b, suma=0;

   a=x-1;
   b=y-1;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   a++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   a++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   b++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   a-=2;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   b++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   a++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   a++;
   if (a>=0 && b>=0 && a<ncx && b<ncy && sqmark(a,b)==1)
      suma++;
   if (suma == value(x,y)) {
      suma=0;
      a=x-1;
      b=y-1;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      b++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a-=2;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      b++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      a++;
      if (a>=0 && b>=0 && a<ncx && b<ncy && !sqopen(a,b) && sqmark(a,b)!=1) {
    suma|=(value(a,b)==MINE);
    Set_square(a,b,0);
    Open_square(a,b);
      }
      return (suma);
   }
   else
      return 0;
}

/*
   Здесь делаем всю работу.
*/
int Do_all(void)
{
   int x, y, xant, yant, mlstant, mrstant, cminasant, ttrans, tant;
   long tst, tact;
   
   char* str = "xxxxx: 0000";
   char* blk = "ЫЫЫЫЫЫЫЫЫЫЫ";

   xant = -1;
   cminasant = ttrans = tant = 0;

   mouse_enable();
   time(&tst);
   
   while (!kbhit())
   {
      if (!sqclosed && !mouse_status)
      {
         settextjustify(LEFT_TEXT, CENTER_TEXT);
         setcolor(BLACK);
         outtextxy(0, maxy/2-10, blk);
         sprintf(str,"Mines:    0");
         setcolor(LIGHTRED);
         outtextxy(0, maxy/2-10, str);
         settextjustify(LEFT_TEXT, CENTER_TEXT);
         setcolor(BLACK);
         outtextxy(0, maxy/2+10, blk);
         sprintf(str," Time: %4d",ttrans);
         setcolor(LIGHTGREEN);
         outtextxy(0, maxy/2+10, str);
         
         for (x=ncx-1; x>=0; x--)
            for (y=ncy-1; y>=0; y--)
               if (value(x,y)==MINE)
               {
                  sqmark(x,y)=1;
                  Set_square(x,y,1);
               }
         break;
      }
      
      if (cminasant != cmines)
      {
         /* Update Mines: */
         cminasant=cmines;
         settextjustify(LEFT_TEXT, CENTER_TEXT);
         setcolor(BLACK);
         outtextxy(0, maxy/2-10, blk);
         sprintf(str,"Mines: %4d",cmines);
         setcolor(LIGHTRED);
         outtextxy(0, maxy/2-10, str);
      }

      if (tant != (ttrans=(int)(time(&tact)-tst)))\
      {
         /* Update Time: */
         tant=ttrans;
         settextjustify(LEFT_TEXT, CENTER_TEXT);
         setcolor(BLACK);
         outtextxy(0, maxy/2+10, blk);
         sprintf(str," Time: %4d",ttrans);
         setcolor(LIGHTRED);
         outtextxy(0, maxy/2+10, str);
      }
      mouse_read_cursor();
      mouse_status&=3;
      x=(mouse_x-XST)/XPX;
      y=(mouse_y-YST)/YPX;
      
      if (xant == -1)
      {
         xant=x;
         yant=y;
      }
      
      if (x!=xant || y!=yant)
      {
         /* Position change */
         if (sqpress(xant,yant) && !sqopen(xant,yant))
         {
            sqpress(xant,yant)=NO;
            Set_square(xant,yant,1);
         }
         xant=x;
         yant=y;
      }
      
      if (!mouse_status)
         mlstant=mrstant=0;
      if ((mouse_status == 2)
         && !sqopen(x,y)
         && mlstant!=mouse_status)
         {
            /* Right button pressed */
            mlstant=mouse_status;
            mouse_disable();

            switch (sqmark(x,y)=(sqmark(x,y)+1) % 3)
            {
            case 1 : cmines--;
            break;
            case 2 : cmines++;
            }
            Set_square(x,y,1);
            mouse_enable();
         }
         else if (mouse_status==1
         && !sqopen(x,y)/* Left button pressed */
         && !sqpress(x,y)
         && sqmark(x,y)!=1 /* And square not pressed */
         )
         {
            sqpress(x,y)=YES;
            Set_square(x,y,0);
         }
      else if (!mouse_status
         && !sqopen(x,y) /* Left button released */
         && sqpress(x,y)
         && sqmark(x,y)!=1)/* Open the square */
      {
         if (value(x,y) == MINE)
         {
            Blow_up();
            break;
         }
         else
            Open_square(x,y);
      }
      else if (mouse_status==3
         && sqopen(x,y)
         && mrstant!=mouse_status)/* Open near squares */
      {
         mrstant=mouse_status;
         if (Open_near_squares(x,y) == YES)
         {
            Blow_up();
            break;
         }
      }
   } // End "while"
   mouse_disable();
   return getch();
}

/*
* Entry point.
*/
void main(int argc, char *argv[])
{
   if (!mouse_reset()) {
      printf("Failed find a mouse driver.\n");
      exit(1);
   }
   int graphdriver = DETECT, graphmode;
   initgraph(&graphdriver, &graphmode, "");
   
   int errorcode = graphresult();
   if (errorcode!=grOk) {
      printf("Failed graphics. Error: %s\n",
         grapherrormsg(errorcode));
      exit(1);
   }
   
   maxy = getmaxy();
   Read_param(argc, argv);

   mouse_horizontal_range(XST, XST + XPX * ncx - 3);
   mouse_vertical_range(YST, YST + YPX * ncy - 3);

   do
   {
      randomize();
      cleardevice();
      Set_mines(cmines=initmines);
      mouse_enable();   
      Draw_squares();
   } while (Do_all() != '\x1b');
   closegraph();
}

Изображение
Вложения
Saper.zip
(40.38 Кб) Скачиваний: 107
Аватара пользователя
rvg
Мастер Даунгрейда
 
Сообщения: 661
Зарегистрирован: 18 июл 2023, 14:12

Вернуться в Игры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2