Как написать змейку на паскале

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
Uses crt;
 
var
  x, y, vx, vy, xap, yap, speed, i, score, go: integer;
  sim, snake,sim2: char;
  loose, begintext, wait: boolean;
 
procedure zone;
var
  i: integer;
begin
  textcolor(lightcyan);
  for i := 1 To 80 Do
    write('*');
  gotoxy(1, 2);
  for i := 1 To 24 Do
    writeln('*');
  gotoxy(2, 25);
  for i := 1 To 79 Do
    write('*');
  for i := 2 To 24 Do
  begin
    gotoxy(80, i);
    write('*');
  end;
  textcolor(white);
end;
 
 
procedure notplay;
var
  sim: char;
begin
  while keypressed Do
  begin
    sim := readkey;
    case sim Of 
      'd','a','w','s','в','ф','ц','ы','D','A','W','S','В','Ф','Ц','Ы':
        begin
          vx := 0;
          vy := -1;
        end;
    End;
  end;
end;
 
begin
  speed := 120;
  snake := '0';
  wait := true;
  SetWindowSize(80, 25);
  TextBackGround(black);
  clrscr;
  begintext := true;
  while begintext = true Do
  begin
    textColor(red);
    writeln('WARNING, NOT EXPAND THE WINDOW ,FOR CONVENIENCE!');
    textcolor(green);
    writeln('To control use "wasd"');
    textcolor(white);
    delay(2000);
    notplay;
    TextBackGround(green);
    begintext := false;
  end;
  clrscr;
  zone;
  x := 40;
  y := 25 Div 2;
  vy := -1;
  xap := random(79) + 2;
  yap := random(23) + 2;
  gotoxy(xap, yap);
  textcolor(red);
  write('+');
  textcolor(white);
  gotoxy(1, 1);
  score := 0;
  textcolor(yellow);
  write('Score: ', score, ' ');
  textcolor(white);
  while (x >= 1) Or (x <= 80) Or (y >= 1) Or (y <= 24) Do
  begin
    gotoxy(x, y);
    textcolor(black);
    write(snake);
    textcolor(white);
    
    while wait = true do 
    begin
      textcolor(red);
      gotoxy(39, 25);
      write(333);
      delay(1000);
      gotoxy(39, 25);
      write(222);
      delay(1000);
      gotoxy(39, 25);
      write(111);
      delay(1000);
      gotoxy(39, 25);
      write('GO!');
      delay(500);
      gotoxy(39, 25);
      textcolor(lightcyan);
      write('***');
      textcolor(white);
      notplay;
      wait := false;
    end;
    
    delay(speed);
    if keypressed Then
    begin
      sim := readkey;
      if ((sim2='d') or (sim2='D') or (sim2='в') or (sim2='В')) and ((sim='a') or (sim='A') or (sim='ф') or (sim='Ф')) then sim:='d';
      if ((sim2='a') or (sim2='A') or (sim2='ф') or (sim2='Ф')) and ((sim='d') or (sim='D') or (sim='в') or (sim='В')) then sim:='a';
      if ((sim2='w') or (sim2='W') or (sim2='ц') or (sim2='Ц')) and ((sim='s') or (sim='S') or (sim='ы') or (sim='Ы')) then sim:='w';
      if ((sim2='s') or (sim2='S') or (sim2='ы') or (sim2='Ы')) and ((sim='w') or (sim='W') or (sim='ц') or (sim='Ц')) then sim:='s';
      sim2:=sim;
      case sim Of 
        'd','D','в','В':
          begin
            vx := 1;
            vy := 0
          end;
          
        'a','A','ф','Ф':
          begin
            vx := -1;
            vy := 0
          end;
        'w','W','ц','Ц':
          begin
            vy := -1;
            vx := 0
          end;
        's','S','ы','Ы':
          begin
            vy := 1;
            vx := 0
          end;
      End;
    end;
    gotoxy(x, y);
    write(' ');
    inc(x, vx);
    inc(y, vy);
    if ((x < 2) Or (x > 79) Or (y < 2) Or (y > 24)) Then begin
      loose := true;
      
      while loose = true Do
      begin
        if (x >= 71) then begin
          gotoxy(x - 9, y);
          textcolor(red);
          Write('You Lose!');   
          textcolor(white); end else begin
          textcolor(red);
          write('You Lose!');
          textcolor(white);
        end;
        delay(5000);
        notplay;
        wait := true;
        loose := false;
      end;
      clrscr;
      zone;
      gotoxy(1, 1);
      score := 0;
      textcolor(yellow);
      write('Score: ', score, ' ');
      textcolor(white);
      if (vx = -1) And (vy = 0) Then
      begin
        vx := 0;
        vy := -1
      end;
      if (vy = 1) And (vx = 0) Then
      begin
        vx := 0;
        vy := -1
      end;
      if (vy = -1) And (vx = 0) Then
      begin
        vx := 0;
        vy := -1
      end;
      if (vx = 1) And (vy = 0) Then
      begin
        vx := 0;
        vy := -1;
      end;
      x := 40;
      y := 25 Div 2;
      gotoxy(x, y);
      textcolor(black);
      writeln(snake);
      textcolor(white);
      xap := random(79) + 2;
      yap := random(23) + 2;
      gotoxy(xap, yap);
      textcolor(red);
      write('+');
      textcolor(white);
      while wait = true do 
      begin
        textcolor(red);
        gotoxy(39, 25);
        write(222);
        delay(1000);
        gotoxy(39, 25);
        write(111);
        delay(1000);
        gotoxy(39, 25);
        write('GO!');
        delay(500);
        gotoxy(39, 25);
        textcolor(lightcyan);
        write('***');
        textcolor(white);
        notplay;
        wait := false;
      end;
    end;
    
    if (x = xap) And (y = yap) Then
    begin
      xap := random(79) + 2;
      yap := random(23) + 2;
      gotoxy(xap, yap);
      textcolor(red);
      write('+');
      textcolor(white);
      gotoxy(1, 1);
      score := score + 1;
      textcolor(yellow);
      write('Score: ', score, ' ');
      textcolor(white);
    end;
  end;
end.

На чтение 5 мин. Опубликовано 03.03.2021

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

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

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

Решение задачи по созданию «Змейки» в Паскале

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

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

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

Вариант реализации игры «Змейка» на языке программирования Паскаль будет выглядеть следующим образом:

Игра «Змейка» на языке Паскаль

В модуле graph также можно предложить следующую модель реализации этой игры на Паскале. Будет выглядеть она следующим образом:

Игра «Змейка» на языке Паскаль

Детальное описание разработки

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

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

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

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

Процесс управления змейкой можно реализовать посредством применения следующих клавиш:

  • d – вправо;
  • a – влево;
  • s – вниз;
  • w – вверх.

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

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

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

Рассматривая функциональное описание, стоит обратить внимание на то, что для точки есть необходимость выбрать тип данных spoint=record. Максимальная длина змейки будет выступать в качестве константы и здесь программист должен самостоятельно выбрать предельное значение. Если же рассматривать переменные, то среди них можно выделить следующие:

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

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

{snake.pas} {classic game: avoid your tail and walls, go for apples} {TODO?: — if press key perpendicular to move + backwards — eats itself} program SnakeGame; uses crt; {ncurses analogue} const DelayDuration = 100; {movement delay} TRIESNUM = 128; {umber of tries to find a free space} MAXHEIGHT = 40; {heght of a game field} MAXWIDTH = 60; {width of a game field } type segment = ^star; Direction = (up, down, left, right, stop); star = record {body segment} CurX, CurY: integer; next: segment; trend: Direction end; AppleStatus = (eated, untouched); fruit = record {apple} CurX, CurY: integer; status: AppleStatus; end; papple = ^fruit; borders = record {game field borders} zeroX, endX, zeroY, endY: integer; end; procedure BuildBorder(var box: borders); {draws game field borders} var i: integer; begin TextColor(white); {white walls} {top wall} i:=1; while (i < MAXWIDTH) do begin GotoXY((i+box.zeroX),box.zeroY); write(_); i:=i+1; end; box.endX:=i+box.zeroX; {right wall} i:=1; while (i < MAXHEIGHT) do begin GotoXY(box.endX,(box.zeroY+i)); write(|); i:=i+1; end; box.endY:=i+box.zeroY-1; {bottom wall} i:=1; while (box.endX — i) > box.zeroX do begin GotoXY(box.endX-i,box.endY); write(_); i:=i+1; end; {left wall} i:=0; while (box.endY — i) > box.zeroY do begin GotoXY(box.zeroX,(box.endY-i)); write(|); i:=i+1; end; GotoXY(1,1); {return pointer to NW corner} end; procedure ShowStar(var s: segment); {reflect body segment} begin GotoXY(s^.CurX, s^.CurY); TextColor(Green); {we are green} write(*); GotoXY(1,1) end; procedure HideStar(var s: segment); {conceal body segment} begin GotoXY(s^.CurX, s^.CurY); write( ); GotoXY(1,1) end; procedure Grow(var tail, prev: segment); {adds segments to body} var i:integer = 0; begin while i < 2 do begin {one apple — two segments} new(tail^.next); tail:=tail^.next; prev:=tail; i:=i+1; end; exit; end; procedure SelfBiteTest(var s: segment); {selfdestruction check} var pp: ^segment; {pointer to pointer} begin pp := @(s^.next); {s^ is a head} while pp^ <> nil do begin {go throught list} if (s^.CurX = pp^^.CurX) AND (s^.CurY = pp^^.CurY) then begin writeln(Well done, autocannibal!); halt(1) end else pp:=@(pp^^.next) end; end; function TestFree(var x,y: integer; h: segment):boolean; {find free space} var pp: ^segment; {pointer to pointer} begin pp := @(h); {h — head} if pp^ = nil then begin {end check} TestFree := true; exit; end; {look if apple coordinates match any part of body} if (pp^^.CurX = x) AND (pp^^.CurY = y) then begin TestFree := false; exit; end else begin pp:=@(pp^^.next); TestFree(x,y,pp^); {recursion} end; end; procedure EmergeApple(var a: papple; x,y: integer); {draw an apple} begin a^.CurX:= x; a^.CurY:= y; a^.status:=untouched; GotoXY(a^.CurX, a^.CurY); TextColor(Red); {red one} write(@); GotoXY(1,1); end; procedure CreateApple(var apple: papple; h: segment; box: borders); {find place for an apple. it must be free from snake.} var x,y,dx,dy,i,znak, pdx, tmpx, tmpy: integer; {aarrrghhh!!} begin Randomize; {shake dice} x := random(box.endX-box.zeroX-2)+box.zeroX+1; {range of x} y := random(box.endY-box.zeroY-2)+box.zeroY+1; {range of y} dx :=0; {delta x} dy :=0; {delta y} pdx:=0; {previous dx} znak := —1; {even iterations should be with negative x,y} i:=1; {iterator} {works like clockwise spiral (0 — start, nums — steps): 678 501 432 x+1, y+1, x-2, y-2, x+3, y-3..-4…} while abs(i) < TRIESNUM do begin {move on x axis} while abs(dx) <= abs(pdx) do begin {abs(x) -> |x|} dx:=dx+i; tmpx:=x+dx; {functions unable to take this expressions} tmpy:=y+dy; {!} write(); {IF THERE IS NO STRING — NOTHING WORKS WHY??} {endless cycle of TestFree, becaue it is unable to call EmergeApple.} if TestFree(tmpx,tmpy,h) then begin EmergeApple(apple,tmpx,tmpy); exit; end; end; {move on y axis} while abs(dy) <= abs(dx) do begin dy:=dy+i; tmpy:=y+dy; {functions unable to take this expressions} tmpx:=x+dx; if TestFree(tmpx,tmpy,h) then begin EmergeApple(apple, tmpx, tmpy); exit; end; end; {prepare for new circle} y:=y+dy; x:=x+dx; pdx:=dx; i:=i*znak; {positivenegative switch} dy:=0; dx:=0; end; end; function AppleTest(var s: segment; a: papple): boolean; {check if we ate it} begin if (s^.CurX = a^.CurX) AND (s^.CurY = a^.CurY) then AppleTest:= true else AppleTest:=false end; procedure MoveBody(var s: segment; prev: segment); {move snake} begin if s^.next = nil then begin {end check} exit; end; HideStar(s); {erase segment} MoveBody(s^.next, s); {recursion} s^.CurX := prev^.CurX; {every next gets params of his prev} s^.CurY := prev^.CurY; s^.trend := prev^.trend; ShowStar(s); {show segment} end; procedure BorderTest(var head: segment; box: borders); {wall collision check} begin {if head coordinates match with walls — game over} if (head^.CurX = box.zeroX) OR (head^.CurX = box.endX) then begin writeln(Whatch tour step); halt(1); end else if (head^.CurY = box.zeroY) OR (head^.CurY = box.endY) then begin writeln(Whatch tour step); halt(1); end; end; procedure MoveHead(var head, tail, prev: segment; apple: papple); {NUFF said} {head is special case, because it selects direction} begin HideStar(head); {erase head} if head^.next <> nil then begin {if we have some body} MoveBody(head^.next, head); {move it} end; {if head moves in some direction, it advances} case head^.trend of left: head^.CurX := head^.CurX-1; right: head^.CurX := head^.CurX+1; up: head^.CurY := head^.CurY-1; down: head^.CurY := head^.CurY+1; end; ShowStar(head); {draw head} end; procedure HandleArrowKey(var head: segment; extcode: char); {snake control} {move in direction of pressed key} begin case extcode of #75: { left } if head^.trend <> right then head^.trend:=left; #77: { right } if head^.trend <> left then head^.trend:=right; #72: { up } if head^.trend <> down then head^.trend:=up; #80: { down } if head^.trend <> up then head^.trend:=down; : { stop moving } head^.trend:=stop; end end; procedure ShowScore(var score: integer); {show eated apples} begin TextColor(white); {white color} GotoXY(2, (ScreenHeight div 2)); {nice place} score:= score+1; {apple iteration} write(SCORE: ,score); GotoXY(1,1); {back in corner} end; var ch: char; head,tail,prev: segment; apple: papple; box: borders; score: integer; begin clrscr; {clean screen} {calculate box coordinates} box.zeroY:= ((ScreenHeight div 2) — (MAXHEIGHT div 2)); box.zeroX:= ((ScreenWidth div 2) — (MAXWIDTH div 2)); {create snake} new(head); tail:=head; prev:=head; head^.CurX := ScreenWidth div 2; head^.CurY := ScreenHeight div 2; head^.trend := stop; head^.next:=nil; {create apple} new(apple); apple^.status:=eated; apple^.curX:=0; apple^.curY:=0; {you start with -1 score =]} score:= —1; BuildBorder(box); ShowScore(score); ShowStar(head); CreateApple(apple, head, box); {main cycle} while true do begin {if we are not pressing keys} if not KeyPressed then begin if head^.trend <> stop then MoveHead(head, tail, prev, apple); BorderTest(head, box); SelfBiteTest(head); if AppleTest(head, apple) then begin Grow(tail, prev); ShowScore(score); CreateApple(apple, head, box) end; delay(DelayDuration); continue; end; {if we are trying to control snake} ch := ReadKey; case ch of #0: begin ch := ReadKey; { get extended code } HandleArrowKey(head, ch) end; #27: break; { esc for EXIT } {$IFDEF DEBUG} #13: Grow(tail, prev); { for tests} : head^.trend := stop; { stop moving } {$ENDIF} end end; clrscr; {clean screen} TextColor(LightGray); {back to normal color} end.
Uses graphABC,ABCObjects;
var
snake_lenght:integer{1};
i,xhead,yhead,z,appleX,appleY,t:integer;
head:CircleABC;
 
snake:array[1..4] of CircleABC;
apple:circleABC;
score:TextABC;
 
destructor Destroy;
 
procedure keyDown(key:integer);
begin
if(key=vk_Right) then z:=1; 
if(key=vk_Left) then z:=2; 
if(key=vk_Up) then z:=3; 
if(key=vk_Down) then z:=4; 
end;
 
 
begin
snake_lenght:=1;
for i:=0 to 6 do
begin
line(0,i*80,windowWidth,i*80);
end;
 
for i:=0 to 8 do
begin
line(i*80,0,i*80,windowHeight);
end;
 
xhead :=3*80-40;
yhead:=2*80-40;
 
appleX:=6*80-40;
appleY:=3*80-40;
 
apple:= CircleABC.Create(appleX,appleY,40,clRed);
 
head :=CircleABC.Create(xhead,yhead,40,clBlue);
 
 
for i:=1 to snake_lenght do
begin 
snake [i]:=CircleABC.Create(xhead,yhead+80*i,40,clBlue);
end;
 
 
score := TextABC.Create(5,0,80,'0',clGreen);
 
 
while(true) do
begin
onKeyDown :=keyDown;
 
if(z<>0)then
begin 
for i:= snake_lenght downto 2 do
begin
snake[i].MoveTo(snake[i-1].Position.X,snake[i-1].Position.Y);
end;
 
snake[1].MoveTo(xhead-40,yhead-40);
end;
 
if(z = 1) then xhead := xhead + 80
else if (z = 2) then xhead := xhead - 80
else if (z = 3) then yhead := yhead - 80
else if (z = 4) then yhead := yhead + 80;
 
 
if(xhead > windowWidth) then xhead := 40;
if(xhead < 0) then xhead := windowWidth - 40;
if(yhead > windowHeight) then yhead := 40;
if(yhead < 0) then yhead := windowHeight - 40;
 
if((xHead = appleX) and (yHead = appleY)) then
begin
if snake_lenght<4 then begin snake_lenght:=snake_lenght+1;
snake [snake_lenght]:=CircleABC.Create(snake[snake_lenght-1].Position.X,snake[snake_lenght-1].Position.Y,40,clBlue);end;
appleX := random(1,8)*80 - 40;
appleY := random(1,6)*80 - 40;
apple.MoveTo(appleX-40,appleY - 40);
score.Text := ((score.Text).ToInteger + 1).ToString();
 
end;
 
head.MoveTo(xhead-40,yhead-40);
sleep(500)
end;
 
 
end.

Exe Download

Code Download

uses crt;

const arenaSize=20;  //The size of the arena

startingSpeed=120;   //The starting speed(smaller=faster)

startingSize=18;     //The starting size of the snake

snakeColor=10;       //The snake color

foodColor=14;        //The food color

wallColor=9;         //The wall color

var xfood,yfood,count,size,cycle,i,last,first,score,negativePoints,food:integer;

keyCheck,sizeChange,foodNotOnSnake:boolean;

direction,d2:string;

speed:real;

Snake:array [1..2, 1..4000] of integer;

ch:char;

label start,lose;

begin

start:

begin

        clrscr;

        randomize;

        size:=startingSize+1;

        first:=size-1;

        speed:=startingSpeed;

        last:=0;

        score:=0;

        food:=0;

        negativePoints:=0;

        for count:=size downto 1 do

        begin

           snake[1,count]:=count+1;

           snake[2,count]:=2;

        end;

        direction:=’right’;

        repeat

        FoodNotOnSnake:=true;

        xfood:=random(arenaSize+8)+2;

        yfood:=random(arenaSize-2)+2;

        for i:=1 to first do

           for count:=first to size+1 do

              if ((xfood=snake[1,count])and(yfood=snake[2,count]))or((xfood=snake[1,i])and(yfood=snake[2,i])) then

                 foodNotOnSnake:=false;

        until foodNotOnSNake;

        xfood:=random(arenaSize+8)+2;

        yfood:=random(arenaSize-2)+2;

        textcolor(wallColor);

        gotoxy(1,1);

        write(#201);

        gotoxy(arenaSize+10,1);

        write(#187);

        gotoxy(1,arenaSize);

        write(#200);

        gotoxy(arenaSize+10,arenaSize);

        write(#188);

        for i:=2 to arenaSize+9 do

        begin

           gotoxy(i,1);

           write(#205);

           gotoxy(i,arenaSize);

           write(#205);

        end;

        for i:=2 to arenaSize-1 do

        begin

           gotoxy(1,i);

           write(#186);

           gotoxy(arenaSize+10,i);

           write(#186);

        end;

        textcolor(white);

        while (true) do

        begin

        speed:=speed-0.01;

        textcolor(foodColor);

        gotoxy(xfood,yfood);

        write(‘@’);

        textcolor(white);

        for count:=1 to size do

        begin

           textcolor(snakeColor);

           gotoxy(snake[1,count],snake[2,count]);

           if count=first+1 then

           begin

              case direction of

                 ‘up’:write(#30);

                 ‘down’:write(#31);

                 ‘left’:write(#17);

                 ‘right’:write(#16);

              end;

           end

           else

              write(#249);

           textcolor(white);

        end;

        gotoxy(1,1);

        for i:=1 to first-1 do

           for count:=first+1 to size-1 do

              if ((snake[1,first]=snake[1,count])and(snake[2,first]=snake[2,count]))or((snake[1,first]=snake[1,i])and(snake[2,first]=snake[2,i])) then

                 goto lose;

        sizeChange:=false;

        if (xfood=snake[1,first])and(yfood=snake[2,first]) then

        begin

           size:=size+1;

           snake[1,size]:=snake[1,last];

           snake[2,size]:=snake[2,last];

           sizeChange:=true;

           inc(food);

           speed:=speed-1;

           repeat

           FoodNotOnSnake:=true;

           xfood:=random(arenaSize+8)+2;

           yfood:=random(arenaSize-2)+2;

           for i:=1 to first-1 do

              for count:=first+1 to size+1 do

                 if ((xfood=snake[1,count])and(yfood=snake[2,count]))or((xfood=snake[1,i])and(yfood=snake[2,i])) then

                    foodNotOnSnake:=false;

        until foodNotOnSNake;

        end

        else inc(negativePoints);

        begin

        if last=size then

           last:=1

        else

           inc(last);

        end;

        if sizeChange then

        begin

           if first=size-1 then

              first:=1

           else

              inc(first);

        end

        else

        begin

        if first=size then

           first:=1

        else

           inc(first);

        end;

        gotoxy(snake[1,last],snake[2,last]);

        write(‘ ‘);

        if (snake[1,first]<2)or(snake[2,first]<2)or(snake[1,first]>=arenaSize+10)or(snake[2,first]>=arenaSize) then

           goto lose;

        if keypressed then

        begin

           ch:=readkey;

           if ch=’p’ then

              ch:=readkey;

           if ch=#0 then

           begin

              ch:=readkey;

              case ch of

                 #72:if direction<>’down’ then

                        direction:=’up’;

                 #80:if direction<>’up’ then

                        direction:=’down’;

                 #75:if direction<>’right’ then

                        direction:=’left’;

                 #77:if direction<>’left’ then

                        direction:=’right’;

              end;

           end

           else

           if ch=#27 then

              exit;

        end;

        if direction=’left’ then

        begin

           snake[1,last]:=snake[1,first]-1;

           snake[2,last]:=snake[2,first];

        end;

        if direction=’right’ then

        begin

           snake[1,last]:=snake[1,first]+1;

           snake[2,last]:=snake[2,first];

        end;

        if direction=’up’ then

        begin

           snake[1,last]:=snake[1,first];

           snake[2,last]:=snake[2,first]-1;

        end;

        if direction=’down’ then

        begin

           snake[1,last]:=snake[1,first];

           snake[2,last]:=snake[2,first]+1;

        end;

        score:=food*100-negativePoints;

        if score<0 then

           score:=0;

        gotoxy(5,arenaSize+1);

        write(‘Eaten food:’,food);

        delay(round(speed));

        end;

end;

        lose:

        begin

           textcolor(12);

           gotoxy(arenaSize+11,1);

           writeln(‘You lose!Your score is:’,score);

           gotoxy(arenaSize+11,2);

           write(‘Press any key to play again or Esc to quit…’);

           repeat

              ch:=readkey;

              if ch=#13 then

                 goto start;

           until ch=#27;

        end;

end.

К оглавлению | Назад | Вперёд

Все программы, код которых выложен здесь, являются работоспособными. Ниже приведены возможные варианты реализации игр «Крестики-нолики» и «Змейка» на PascalABC.Net 3.0.

Крестики-нолики[править]

Описание алгоритма
  1. Отрисовать игровое поле.
  2. Позволить сделать шаг игроку.
  3. Проверить выиграл ли кто-то.
  4. Если да — выиграл текущий игрок, иначе — вернуться к шагу 1.

Управление:

  • Левая кнопка мыши — установить крестик/нолик.
uses GraphABC;
const
  N = 2;
  Z = '0';
  K = 'X';
  Size = 200;
  Border = 1;
  Sx = 1200;
  Sy = 70;

var
  Matrix: array [0..N, 0..N] of char;
  Player1: boolean;

procedure Draw();
  procedure DrawZ(i, j: integer);
  begin
    SetPenColor(clCyan);
    SetPenWidth(4);
    var size2 := Size div 2;
    DrawCircle((i + 1) * Size - size2, (j + 1) * Size - size2, Round(size2 * 0.7));
  end;
  
  procedure DrawK(i, j: integer);
    procedure RLine(x, y, x1, y1: real):=Line(Round(x), Round(y), Round(x1), Round(y1));

  begin
    SetPenColor(clPink);
    SetPenWidth(4);
    var size2 := Size div 2 * 0.3;
    var cx1 := i * Size + size2;
    var cy1 := j * Size + size2;
    var cx2 := (i + 1) * Size - size2;
    var cy2 := (j + 1) * Size - size2;
    RLine(cx1, cy1, cx2, cy2);
    RLine(cx1, cy2, cx2, cy1);
  end;

  begin
    ClearWindow(clBlack);
    if Player1 then SetWindowCaption('Ходит первый игрок') else SetWindowCaption('Ходит второй игрок');
    for var i := 0 to N do
      for var j := 0 to N do
      begin
        SetPenColor(clLightBlue);
        SetPenWidth(1);
        DrawRectangle(i * Size + Border, j * Size + Border, (i + 1) * Size - Border, (j + 1) * Size - Border);
        if Matrix[i, j] = Z then DrawZ(i, j)
        else if Matrix[i, j] = K then DrawK(i, j);
      end;
    Redraw();
  end;

function Won(c: char): boolean;
var
  count: byte;
begin
  Result := false;
  for var i := 0 to N do
  begin
    count := 0;
    for var j := 0 to N do
      if Matrix[i, j] = c then Inc(count);
    if count = 3 then Result := true;
  end;
  
  if not Result then
  begin
    for var i := 0 to N do
    begin
      count := 0;
      for var j := 0 to N do
        if Matrix[j, i] = c then Inc(count);
      if count = 3 then Result := true;
    end;
    
    if not Result then
    begin
      count := 0;
      for var i := 0 to N do
        if Matrix[i, i] = c then Inc(count);
      if count = 3 then Result := true;
      
      if not Result then
      begin
        count := 0;
        for var i := 0 to N do
          if Matrix[N - i, i] = c then Inc(count);
        if count = 3 then Result := true;
      end;
    end;
  end;
end;

function IsFull(): boolean;
begin
  Result := true;
  for var i := 0 to N do
    for var j := 0 to N do
      if (Matrix[i, j] <> Z) and (Matrix[i, j] <> K) then
      begin
        Result := false;
        break;
      end;
end;

procedure MouseDown(x, y, mb: integer);
  procedure ShowWinner(s: string; c: Color);
  begin
    SetWindowCaption('Результат игры');
    Sleep(2000);
    SetWindowSize(Sx, Sy);
    CenterWindow();
    ClearWindow(clBlack);
    
    SetFontSize(16);
    SetFontStyle(fsBold);
    SetFontColor(c);
    DrawTextCentered(0, 0, Sx, Sy, s);
    
    Redraw();
    Sleep(2000);
    Halt();
  end;

begin
  var i := x div Size;
  var j := y div Size;
  if (Matrix[i, j] <> Z) and (Matrix[i, j] <> K) then
  begin
    if Player1 then Matrix[i, j] := Z else Matrix[i, j] := K;
    Draw();
    
    var winnerExists := Won(Z) or Won(K);
    if winnerExists then
      if Player1 then ShowWinner('Игрок первый победил!', clLightBlue) else ShowWinner('Игрок второй победил!', clLightBlue);
    
    if IsFull() and not winnerExists then ShowWinner('Ничья!', clOrange);
    
    Player1 := not Player1;
  end;
end;

begin
  var Size2 := Size * 3;
  SetWindowIsFixedSize(true);
  SetWindowSize(Size2, Size2);
  CenterWindow();
  LockDrawing();
  
  Player1 := true;
  Draw();
  
  OnMouseDown := MouseDown;
end.

Змейка[править]

==Упрощенный вариант== (просто змейка которой можно управлять)

Описание алгоритма
  1. Нарисовать змейку.
  2. Если нажали клавишу — добавить новую точку, в которую перешла голова змейки, в список и удалить первую точку в списке. Перейти к шагу 1.

Управление:

  • W — вверх.
  • S — вниз.
  • A — влево.
  • D — вправо.
uses GraphABC;
const
  Size = 20;

var
  Snake: List<Point>;

procedure Draw();
begin
  ClearWindow();
  Polyline(Snake.ToArray());
  
  var c := Snake.Count - 1;
  Circle(Snake[c].X, Snake[c].Y, 5);
  Redraw();
end;

procedure KeyDown(Key: integer);
begin
  var c := Snake.Count - 2;
  case Key of
    VK_Left:
      begin
        Snake.RemoveAt(0);
        Snake.Add(new Point(Snake[c].X - Size, Snake[c].Y));
      end;
    VK_Right:
      begin
        Snake.RemoveAt(0);
        Snake.Add(new Point(Snake[c].X + Size, Snake[c].Y));
      end;
    VK_Up:
      begin
        Snake.RemoveAt(0);
        Snake.Add(new Point(Snake[c].X, Snake[c].Y  - Size));
      end;
    VK_Down:
      begin
        Snake.RemoveAt(0);
        Snake.Add(new Point(Snake[c].X, Snake[c].Y  + Size));
      end;
  end;
  Draw();
end;

begin
  LockDrawing();
  SetSmoothingOff();
  
  Snake := new List<Point>();
  for var x := 1 to 30 do
    Snake.Add(new Point(x * Size, Size));
  
  Draw();
  OnKeyDown := KeyDown;
end.

Возрастающая последовательность[править]

uses GraphABC, ABCObjects;
const
  Border = 100;


var
  Obj: CircleABC;
  DX, DY: integer;
  Move: boolean;
  Numbers: TCircles;

function IsEqual(L2: TCircles): boolean;
begin
  Result := true;
  for var i := 0 to L2.Count - 1 do
    if Numbers[i].Number <> L2[i].Number then
    begin
      Result := false;
      break;
    end;
end;

procedure MouseUp(x, y, mb: integer);
procedure MouseMove(x, y, mb: integer);
begin
  if mb = 1 then
    if not Move then
    begin
      for var i := 0 to Numbers.Count - 1 do
        if Numbers[i].PtInside(x, y) then
        begin
          DX := x - Numbers[i].Position.X;
          DY := y - Numbers[i].Position.Y;
          Obj := Numbers[i];
          
          Move := true;
          break;
        end;
    end
    else
      Obj.Position := new Point(x - Dx, y - Dy);
end;

begin
  var W := Window.Width - 2 * Border;
  var H := Window.Height - 2 * Border;
  
  Numbers := new TCircles();
  for var i := 0 to 6 do
  end
    Numbers.Add(new CircleABC(Border + Random(W), Border + Random(H), 30, clRandom()));
    Numbers.Last().Number := i;
  
  Move := false;
  OnMouseMove := MouseMove;
  OnMouseUp := MouseUp;
end.

59

Программирование на языке Pascal

Практикум: Разработка приложения «Змейка»

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

Тело змейки будет состоять из каких-либо символов, перемещаемых вслед за ведущим символом – головой змеи.

При перемещении, нам, по сути дела, потребуется изменять координату только головы змеи – все остальные части тела будут лишь «перебираться» на предыдущие положения впередистоящих звеньев.

Движение влево

0

1

2

3

4

5

6

7

0

1

2

3

4

5

6

7

Таким образом, алгоритм движения змейки будет заключаться в следующем:

1.Вычислить новые координаты головы змеи (на нашем рисунке – это нулевой элемент) по следующему правилу:

Если была нажата кнопка «ВВЕРХ», то вычитаем из вертикальной координаты Y единицу. Координата X остается прежней.

Если была нажата кнопка «ВНИЗ», то прибавляем к вертикальной координате Y единицу. Координата X также остается без изменений.

Если была нажата кнопка «ВЛЕВО», то вычитаем единицу из координаты X.

Если была нажата кнопка «ВПРАВО» то прибавляем единицу к координате X.

2.Переместить первое звено на место предыдущего нулевого звена, второе звено – на место предыдущего первого и т.д.

Отлавливать нажатие клавиш управления курсором мы будем при помощи процедуры

ReadKey из модуля Crt.

Координаты X и Y будем хранить в двух различных массивах. Длина змейки будет

определяться количеством элементов в этих массивах.

Uses Crt;

Const

SNAKE_LEN=6;

Type

TSnakeCoords=Array[0..SNAKE_LEN] Of Byte;

Var

X, Y : TSnakeCoords; c : Char;

i : Integer;

NewX, NewY : Integer;

Begin

{первоночальное положение змейки – левый верхний угол}

For i:=0 To SNAKE_LEN Do

Begin

59

60

Программирование на языке Pascal

X[i]:=i+1;

Y[i]:=1;

End;

{Основной цикл – до тех пор пока не нажмут Esc}

Repeat

ClrScr;

{Вывод на экран змейки}

For i:=0 To SNAKE_LEN Do

Begin

GotoXY(X[i], Y[i]); Write(‘*’);

End;

c:=ReadKey;

If c=#0 Then c:=ReadKey;

{Получаем местоположение головы змейки}

NewX:=X[0];

NewY:=Y[0];

{На их основе вычисляем новые координаты}

Case C Of

#72: NewY:=NewY-1;

#80: NewY:=NewY+1;

#75: NewX:=NewX-1;

#77: NewX:=NewX+1;

End;

{Перебрасываем звенья на положения впередистоящих участков}

For i:=SNAKE_LEN DownTo 1 Do

Begin

X[i]:=X[i-1];

Y[i]:=Y[i-1];

End;

{Записываем новые координаты головы змеи}

X[0]:=NewX;

Y[0]:=NewY; Until c=#27;

End.

60

61

Программирование на языке Pascal

Модуль 5. Строки и многомерные массивы

Представление строк в Pascal

Мы уже сталкивались с типом данных, способным хранить один символ. Это тип данных Char. Но в прикладных задачах часто приходится иметь дело не с одним символом, а с целыми словами и предложениями (вспомним хотя бы текстовый редактор). Можно,

конечно, работать со строками, объявив массив символов, например, так:

Const

String_Len=100;

Type

StringType=Array[1..StringLen] Of Char;

Var

MyString: StringType;

Но такой подход зачастую неудобен, поскольку требует непосредственного написания всех процедур манипулирования со строками (копирование строчек, поиск подстроки, извлечение подстроки и т.д.). Поэтому был введен специальный тип данных для работы со строками: String. По сути дела, строковый тип данных – это тот же массив символов, однако для него предусмотрены специальные процедуры и функции, облегчающие разработку программ.

Максимальная длина строки для типа данных String ограничена 255-ю символами. Это ограничение было снято в реализации языка Object Pascal, используемой в среде Delphi. Все символы строки нумеруются от 1 до длины строки. В нулевом символе хранится символ, с кодом, равным длине строки. Так, например, если строка содержит 32 символа, то нулевой символ будет пробелом (‘ ‘), так как его код равен 32.

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

использования тех переменных, которые мы использовали ранее. Приведем пример:

Var

UserName : String;

Begin

WriteLn(‘Введите ваше имя’); ReadLn(UserName);

WriteLn(‘Рады приветствовать, ‘, UserName);

End.

Эта программа просит ввести пользователя его имя, и затем просто выводит приветственное сообщение, содержащее обращение по имени к пользователю.

Операции над строками

Для строковых переменных определены операции присваивания (для нее используется уже знакомый нам оператор ‘:= ‘), сравнения (‘=‘ – равенство, ‘<‘ – меньше, ‘>‘ – больше, ‘<=‘ – меньше или равно, ‘>=‘ – больше или равно) и конкатенации – объединения строк. Для конкатенации используется символ «+», который, несмотря на то, что используется для сложения, не подразумевает независимость результат от мест «слагаемых»-строчек.

Действительно, если у нас есть две строки

S1:=’Маша’; S2:=’ ела кашу.’;

то в результате конкатенации S1+S2 мы получим строчку «Маша ела кашу», а поменяв «слагаемые» местами – « ела кашу.Маша».

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

61

62

Программирование на языке Pascal

совпадать со знаком неравенства несовпадающих символов. При этом символ в нижнем регистре считается больше соответствующего символа в верхнем регистре (например, ‘m>M‘). Общее же правило при сравнении символов такое: среди двух сравниваемых символов тот из них считается больше, чей код является больше. Приведем примеры сравнения строк

Строка 1

Строка 2

Результат сравнения

Pascal

pascal

pascal>Pascal

Turbo Pascal

Pascal

Turbo Pascal>Pascal

abcdef

acdeff

abcdef<acdeff

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

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

Var S: String;

L: Byte;

Begin

WriteLn(‘Введите строку’);

ReadLn(S);

L:=Ord(S[0]);

WriteLn(‘Вы ввели строку, длиной ‘, L);

End.

В этом примере мы использовали функцию Ord для получения кода нулевого символа строки S[0].

2.Использовать функцию Length.

Var S: String;

L: Byte;

Begin

WriteLn(‘Введите строку’);

ReadLn(S);

L:=Length(S);

WriteLn(‘Вы ввели строку, длиной ‘, L);

End.

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

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

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

62

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Понравилась статья? Поделить с друзьями:
  • Как написать злой смайлик знаками
  • Как написать зимнюю сказку
  • Как написать зимний пейзаж маслом
  • Как написать зимний пейзаж гуашью
  • Как написать зимний пейзаж акварелью