Форум программистов, компьютерный форум, киберфорум
PascalABC.NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.54/222: Рейтинг темы: голосов - 222, средняя оценка - 4.54
0 / 0 / 0
Регистрация: 15.07.2018
Сообщений: 9

Змейка на паскале. Хвост

17.07.2018, 19:09. Показов 48681. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Ребята, помогите пожалуйста!
Делаю змейку на PascalABC и никак не могу сделать нормальный рабочих хвост, как в классической змейке
Накиньте ,пожалуйста, идей, а лучше код)

Вот мой код:

Pascal
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.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.07.2018, 19:09
Ответы с готовыми решениями:

Змейка на Паскале
Ребята, помогите пожалуйста! Я только начинающий программист и решил сделать что-то сложное на PascalABC.NET. Как вариант выбрал змейку, ну...

Змейка в паскале
Короче ток недавно заинтересовался программированием и офк начал с паскаля абц.нет Долгими усилиями делаю змейку Подскажите,как...

Игра змейка С++ . Хвост. как создать хвост змейки
День добрый помогите, не знаю как сделать хвост. Код был взят с форума и переделан. Но с хвостом не знаю что делать... буду рад любому...

18
 Аватар для JuriiMW
5095 / 2661 / 2355
Регистрация: 10.12.2014
Сообщений: 10,059
18.07.2018, 08:10
Вот так:
Pascal
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
uses crt;
 
const
  maxLength = 1000;
  wndWidth = 80;
  wndHeight = 25;
  
type
  Point = record
    X, Y : Integer;
    
    constructor (X_, Y_ : Integer);
    begin
      X := X_; Y := Y_;
    end;
  end;
 
procedure InitWindow;
begin
  HideCursor;
  TextBackGround(green);
  ClrScr;
  TextColor(LightCyan);
  for var x := 1 to wndWidth do
    begin
      GoToXY(x, 1); Write('*');
      GoToXY(x, wndHeight); Write('*');
    end;
  for var y := 2 to 24 do
    begin
      GoToXY(1, y); Write('*');
      GoToXY(80, y); Write('*');
    end;
  GoToXY(1,1);
end;
 
var
  Snake : array of Point;
  Head, Tail : Integer;
  dir : Integer;
  speed : Integer;
  Steps : Integer;
 
procedure NewSnake;
begin
  (Head, Tail, dir, speed) := (1, 0, 0, 120);
  (Snake[0], Snake[1]) := (New Point(wndWidth div 2, wndHeight div 2 + 1), New Point(wndWidth div 2, wndHeight div 2));
end;
 
procedure ShowSnake;
begin
  TextColor(Black);
  var n := Head;
  GoToXY(Snake[n].X, Snake[n].Y); Write('@');
  while n <> Tail do
    begin
      if n = 0 then n := maxLength; n -= 1;
      GoToXY(Snake[n].X, Snake[n].Y); Write(n = Tail ? ' ' : 'o');
    end;
end;
 
procedure whaitKeyPressed;
begin
  SetWindowTitle('Нажмите любую клавишу для старта');
  ReadKey;
  SetWindowTitle('Движение стрелками');
end;
 
var
  Live := True;
 
procedure NextStep;
begin
  Steps += 1;
  var H := Snake[Head];
  case dir of
    0 : H.Y -= 1;
    1 : H.X += 1;
    2 : H.Y += 1;
    3 : H.X -= 1;
  end;
  Head += 1; if Head = maxLength then Head := 0;
  Snake[Head] := H;
  if Steps mod 20 > 0 then
    begin
      Tail += 1; if Tail = maxLength then Tail := 0;
    end;
  if (H.X = 1) or (H.X = wndWidth) or (H.Y = 1) or (H.Y = wndHeight) then
    Live := False
  else
    begin
      var n := Head;
      while n <> Tail do
        begin
          if n = 0 then n := maxLength; n -= 1;
          if (n <> Tail) and (H.X = Snake[n].X) and (H.Y = Snake[n].Y) then
            Live := False;
        end;
    end;
end;
 
procedure onKeyPressed(c : Char);
begin
  case c of
    #37 : if dir <> 1 then dir := 3;
    #38 : if dir <> 2 then dir := 0;
    #39 : if dir <> 3 then dir := 1;
    #40 : if dir <> 0 then dir := 2;
  else
    SetWindowTitle(Ord(c).ToString);
  end;
end;
 
begin
  SetLength(Snake, maxLength);
  NewSnake;
  InitWindow;
  ShowSnake;
  whaitKeyPressed;
  repeat
    NextStep;
    ShowSnake;
    Sleep(speed);
    if KeyPressed then
      begin
        var c := ReadKey;
        if c = #0 then
          onKeyPressed(ReadKey);
      end;
  until Not Live;
  SetWindowTitle('Вы проиграли');
  GoToXY(1,1);
end.
Только без кроликов…
;–)
0
79 / 49 / 23
Регистрация: 15.07.2018
Сообщений: 255
18.07.2018, 09:07
Мне кажется движение в твоей змейке будет лучше начинать в ту сторону куда нажал пользователь/игрок.
0
 Аватар для JuriiMW
5095 / 2661 / 2355
Регистрация: 10.12.2014
Сообщений: 10,059
18.07.2018, 09:17
Во-первых, Get_Over_Here, „тыкать“ незнакомому человеку нехорошо! В своих ответах я к вам ни когда на „ты“ не обращался, хотя точно знаю, что старше, как минимум, в два раза…
Во-вторых, я лишь показал ТС, что его концепция изначально провальная. И нужно было думать о „хвосте“ ещё в самом начале, а не тогда, когда „голова“ начала двигаться.
Ну и в-третьих, это всего-лишь пример, а не готовое изделие, которое, по крайней мере, в конце второго десятилетия двадцать первого века, выглядит очень странно в консоли…
0
79 / 49 / 23
Регистрация: 15.07.2018
Сообщений: 255
18.07.2018, 09:21
Понял, принял
Но только обращался я не к вам, забыл ник указать
0
 Аватар для JuriiMW
5095 / 2661 / 2355
Регистрация: 10.12.2014
Сообщений: 10,059
18.07.2018, 09:25
Цитата Сообщение от Get_Over_Here Посмотреть сообщение
Но только обращался я не к вам,
А к кому же?
Змейка ТС своё движение начинает самостоятельно, а моя по нажатию кнопки…
0
79 / 49 / 23
Регистрация: 15.07.2018
Сообщений: 255
18.07.2018, 09:36
Ну вот я и посоветовал начинать движение по нажатию и в сторону куда нажали

Добавлено через 49 секунд
Я понимаю что вы профессионал и мне с вами лучше не связываться
0
 Аватар для JuriiMW
5095 / 2661 / 2355
Регистрация: 10.12.2014
Сообщений: 10,059
18.07.2018, 11:07
Лучший ответ Сообщение было отмечено ZX Spectrum-128 как решение

Решение

А вот уже и с кроликами:
Pascal
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
uses crt;
 
const
  maxLength = 1000;
  wndWidth = 80;
  wndHeight = 25;
  maxRabbits = (wndWidth * wndHeight) div 6;
  newRabbitByStep = 1;
  
type
  Point = record
    X, Y : Integer;
    
    constructor (X_, Y_ : Integer);
    begin
      X := X_; Y := Y_;
    end;
  end;
 
procedure InitWindow;
begin
  HideCursor;
  TextBackGround(green);
  ClrScr;
  TextColor(LightCyan);
  for var x := 1 to wndWidth do
    begin
      GoToXY(x, 1); Write('*');
      GoToXY(x, wndHeight); Write('*');
    end;
  for var y := 2 to 24 do
    begin
      GoToXY(1, y); Write('*');
      GoToXY(80, y); Write('*');
    end;
  GoToXY(1,1);
end;
 
var
  Snake : array of Point;
  Head, Tail : Integer;
  dir : Integer;
  speed : Integer;
  Steps : Integer;
  Rabbits : array of Point;
  countRabbits : Integer;
 
procedure AddRabbit;
begin
  if countRabbits = maxRabbits then Exit;
  
  var Ok := False;
  var R := New Point;
  repeat
    R.X := Random(2, wndWidth - 2);
    R.Y := Random(2, wndHeight - 2);
    Ok := True;
    for var n := 0 to countRabbits-1 do
      if (R.X = Rabbits[n].X) and (R.Y = Rabbits[n].Y) then
        Ok := False;
    if Ok then
      begin
        var n := Head;
        while Ok and (n <> Tail) do
          begin
            if (R.X = Snake[n].X) and (R.Y = Snake[n].Y) then
              Ok := False;
            if n = 0 then n := maxLength; n -= 1;
          end;
      end;
  until Ok;
  Rabbits[countRabbits] := R; countRabbits += 1;
end;
 
procedure NewSnake;
begin
  (Head, Tail, dir, speed) := (1, 0, 0, 120);
  (Snake[0], Snake[1]) := (New Point(wndWidth div 2, wndHeight div 2 + 1), New Point(wndWidth div 2, wndHeight div 2));
  countRabbits := 0; AddRabbit;
end;
 
procedure ShowSnake;
begin
  TextColor(Black);
  var n := Head;
  GoToXY(Snake[n].X, Snake[n].Y); Write('@');
  while n <> Tail do
    begin
      if n = 0 then n := maxLength; n -= 1;
      GoToXY(Snake[n].X, Snake[n].Y); Write(n = Tail ? ' ' : 'o');
    end;
end;
 
procedure ShowRabbits;
begin
  TextColor(White);
  for var i := 0 to countRabbits - 1 do
    begin
      GoToXY(Rabbits[i].X, Rabbits[i].Y); Write('R');
    end;
end;
 
procedure whaitKeyPressed;
begin
  SetWindowTitle('Нажмите любую клавишу для старта');
  ReadKey;
  SetWindowTitle('Движение стрелками');
end;
 
var
  Live := True;
 
procedure NextStep;
begin
  Steps += 1;
  var H := Snake[Head];
  case dir of
    0 : H.Y -= 1;
    1 : H.X += 1;
    2 : H.Y += 1;
    3 : H.X -= 1;
  end;
  Head += 1; if Head = maxLength then Head := 0;
  Snake[Head] := H;
  if (H.X = 1) or (H.X = wndWidth) or (H.Y = 1) or (H.Y = wndHeight) then
    Live := False
  else
    begin
      var n := Head;
      while n <> Tail do
        begin
          if n = 0 then n := maxLength; n -= 1;
          if (n <> Tail) and (H.X = Snake[n].X) and (H.Y = Snake[n].Y) then
            Live := False;
        end;
    end;
  var n := 0;
  while n < countRabbits do
    begin
      if (H.X = Rabbits[n].X) and (H.Y = Rabbits[n].Y) then
        begin
          countRabbits -= 1;
          repeat
            Rabbits[n] := Rabbits[n + 1];
            n += 1;
          until n >= countRabbits;
          Exit;
        end;
      n += 1;
    end;
    
  Tail += 1; if Tail = maxLength then Tail := 0;
  if Steps mod newRabbitByStep = 0 then
    AddRabbit;
end;
 
procedure onKeyPressed(c : Char);
begin
  case c of
    #37 : if dir <> 1 then dir := 3;
    #38 : if dir <> 2 then dir := 0;
    #39 : if dir <> 3 then dir := 1;
    #40 : if dir <> 0 then dir := 2;
  else
    SetWindowTitle(Ord(c).ToString);
  end;
end;
 
begin
  SetLength(Snake, maxLength);
  SetLength(Rabbits, maxRabbits);
  NewSnake;
  InitWindow;
  ShowSnake;
  whaitKeyPressed;
  repeat
    NextStep;
    ShowSnake;
    ShowRabbits;
    Sleep(speed);
    if KeyPressed then
      begin
        var c := ReadKey;
        if c = #0 then
          onKeyPressed(ReadKey);
      end;
  until Not Live;
  SetWindowTitle('Вы проиграли');
  GoToXY(1,1);
end.
0
0 / 0 / 0
Регистрация: 15.07.2018
Сообщений: 9
18.07.2018, 13:37  [ТС]
Мне, конечно очень интересно смотреть на эти творения профессионалов, но к сожалению это всё понять мне пока не под силу)
Ибо я школоло из 10 класса и занимаюсь программированием только год
Но собираюсь развиваться в этой сфере, так что спасибо за помощь
0
 Аватар для Kuzia domovenok
4268 / 3327 / 926
Регистрация: 25.03.2012
Сообщений: 12,531
Записей в блоге: 1
18.07.2018, 15:03
JuriiMW, всем тыкаю в интернете и тебе советую
Rautmazar, тут и не надо в каких-то деталях разбираться. Ты самое главное в своей проге упусти. Змейка - это массив и тебе не достаточно для нормальной игры как ты думал хранить только лишь пару x, y
Тебе нужно хранить массив иксов и массив игреков для каждой клетки от головы до хвоста. Массивы-то ты надеюсь за год узнал?
0
0 / 0 / 0
Регистрация: 15.07.2018
Сообщений: 9
18.07.2018, 17:55  [ТС]
Kuzia domovenok, да, к счастью за этот год я многое узнал, так что знаю и про массив и даже про двумерный их вид
Тогда засяду и начну переписывать, может что-то и получится!
Огромное Спасибо за поддержку!
0
Aimez-vous les baguettes?
193 / 26 / 27
Регистрация: 25.10.2017
Сообщений: 165
24.07.2018, 09:49
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
JuriiMW, всем тыкаю в интернете и тебе советую

Не по теме:

Вам*

0
26.07.2018, 22:05

Не по теме:

Цитата Сообщение от alex5code Посмотреть сообщение
Вам*
Не спорьте с ним, опуститесь до его уровня, а там у него опыта больше, задавит.
:)

0
 Аватар для canadamoscow
1179 / 430 / 194
Регистрация: 23.03.2020
Сообщений: 1,021
Записей в блоге: 1
04.10.2020, 16:43
Pascal
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
uses graphWPF;
 
begin
  window.SetSize(20 * 30 - 10, 20 * 30 - 10);
  Window.IsFixedSize := True; 
  var NewGame: boolean; 
  var q := new queue<integer>;//очередь для нажатых клавиш
  OnKeyDown := procedure (k: key) →
  case k of
    key.Left: q.Enqueue(1);
    Key.Right: q.Enqueue(2);
    Key.Up: q.Enqueue(8);
    Key.Down: q.Enqueue(9);
    Key.Escape: halt();
    Key.Enter: NewGame := true; //по нажатию Enter - новая игра
  end;
  repeat
    NewGame := false;
    Window.Clear;
    var (i, j) := (-1, 0); //координаты головы
    var n := 5; //длина змейки
    var p := 2; //направление следующего шага для головы
    var a := |(-1, 0)| * n; //создаем массив индексов для звеньев змейки
    var (bi, bj) := Random2(2, 19); //координаты еды
    FillRectangle(bi * 30, bj * 30, 30, 30, Colors.DarkCyan); //вывод еды на экран
    repeat
      var newp := if q.Any then q.Dequeue else p; //перебираем очередь
      while q.Any and (abs(newp - p) < 2) do newp := q.Dequeue; //всё не нужное выбрасываем
      if abs(newp - p) > 2 then p := newp; //если новое направление "поворот", то записываем его в p
      case p of //меняем индекс для головы змейки в  торону p
        1: i -= 1; //влево
        2: i += 1;//вправо
        8: j -= 1;//вверх
        9: j += 1;//вниз
      end;
      if i = -1 then i := 19 else if i = 20 then i := 0; //перескок от стенки до стенки в другой конец экрана
      if j = -1 then j := 19 else if j = 20 then j := 0;
      if a.Contains((i, j)) and (a[n - 1] <> (i, j)) then //проверка на столкновение головы с телом змейки
      begin FillRectangle(i * 30, j * 30, 30, 30, Colors.Magenta); break; end;
      if (i = bi) and (j = bj) then //поели? удлиняем змейку на три клетки
      begin
        a := a + |a[n - 1]| * 3; //массив змейки увеличить на 3 элемента
        n += 3; 
        (bi, bj) := Random2(0, 19); //новые координаты еды, которые..
        while a.Contains((bi, bj)) do (bi, bj) := Random2(0, 19); //..не совпадут с телом змейки
        FillRectangle(bi * 30, bj * 30, 30, 30, Colors.DarkCyan);//вывод еды на экран
      end;
      var pXBOCT: integer; //направление в котором нужно затирать клетку хвоста (след после хвоста)
      if abs(a[n - 2].Item1 - a[n - 3].Item1 + (a[n - 2].Item2 - a[n - 3].Item2) * 2 + 3) < 6 then//не перескчили в другой край экрана?
        pXBOCT := (a[n - 2].Item1 - a[n - 3].Item1 + (a[n - 2].Item2 - a[n - 3].Item2) * 2 + 3); 
      for var f := n - 1 downto 1 do a[f] := a[f - 1]; a[0] := (i, j); //каждая клетка змейки продвинулась на шаг впреред
      for var f := 0 to 29 do //вывод головы и затирание хвоста
      begin
        case p of //рисуем плавный шаг головы в новой клетке
          1: FillRectangle(29 - f + i * 30, j * 30, 1, 30, Colors.Red);
          2: FillRectangle(i * 30 + f, j * 30, 1, 30, Colors.Red);
          8: FillRectangle(i * 30, 29 - f + j * 30, 30, 1, Colors.Red);
          9: FillRectangle(i * 30, j * 30 + f, 30, 1, Colors.Red);
        end;
        case pXBOCT of //затираем плавно последнюю клетку хвоста
          4: FillRectangle(29 - f + a[n - 1].Item1 * 30, a[n - 1].Item2 * 30, 1, 30, Colors.White); //лево
          2: FillRectangle(a[n - 1].Item1 * 30 + f, a[n - 1].Item2 * 30, 1, 30, Colors.White); //право
          5: FillRectangle(a[n - 1].Item1 * 30, 29 - f + a[n - 1].Item2 * 30, 30, 1, Colors.White);//вверх
          1: FillRectangle(a[n - 1].Item1 * 30, a[n - 1].Item2 * 30 + f, 30, 1, Colors.White); //вниз
        end;      
        sleep(7);//скорость змейки
      end
    until NewGame;
    repeat sleep(100) until NewGame; //ждем нажатия Enter или Escape
  until false;
end.
0
80 / 33 / 10
Регистрация: 14.06.2019
Сообщений: 516
04.10.2020, 17:33
Цитата Сообщение от Rautmazar Посмотреть сообщение
даже про двумерный
Я один не могу удержаться от улыбки, читая это?
0
 Аватар для Sun Serega
2355 / 1458 / 526
Регистрация: 07.04.2017
Сообщений: 4,798
04.10.2020, 20:48
canadamoscow,

1. Обработчик сообщений окна - это отдельный поток. А тип Queue<>, как и все остальные стандартные коллекции элементов - не потоко-безопасен.
Поэтому его нельзя читать и писать сразу из 2 потоков, иначе можно получить мусор. Используйте lock.

2. Для тела змейки тоже используйте Queue<>. Очередь делает именно то что вам надо - позволяет вырезать элементы хвоста и добавлять новые спереди головы.
И вместо постоянных выделений и удалений массивов как у вас - очередь использует зацикленный массив и перевыделяет его только когда не хватает места.
1
 Аватар для canadamoscow
1179 / 430 / 194
Регистрация: 23.03.2020
Сообщений: 1,021
Записей в блоге: 1
04.10.2020, 22:44
1.Впервые с lock знакомлюсь. Понял, что так надо:
Pascal
1
2
3
4
5
lock q do begin //блокируем q от второго потока OnKeyDown во избежание получения мусора 
 var newp := if q.Any then q.Dequeue else p; //перебираем очередь
 while q.Any and (abs(newp - p) < 2) do newp := q.Dequeue; //всё не нужное выбрасываем
 if abs(newp - p) > 2 then p := newp; //если новое направление "поворот", то записываем его в p
end;
2,
Pascal
1
2
3
n += 3; 
SetLength(a,n);
for var f := 1 to 3 do a[n-f] := a[n - 4];
Массив тут удобнее. Змейка наращивается на 3 элемента в конце. Очередь удобна при наращивании на 1 элемент, а если более то у меня выходят танцы с бубнами.
0
 Аватар для Sun Serega
2355 / 1458 / 526
Регистрация: 07.04.2017
Сообщений: 4,798
04.10.2020, 23:08
1. lock q do не блокирует все обращения к q. lock в 1 потоке не даёт выполниться lock в другом потоке для того же объекта, пока блок первого lock не перестанет выполняться.

То есть блокировка нужна в обоих потоках.

2. Вместо этого надо запоминать число, на сколько хвост должен удлиниться. И вместо удлинение хвоста - не давать ему укорачиваться когда змея от него уползает. Добавлять несколько элементов которые друг на друга налазят - это однозначно костыль.
1
 Аватар для canadamoscow
1179 / 430 / 194
Регистрация: 23.03.2020
Сообщений: 1,021
Записей в блоге: 1
05.10.2020, 10:02
Змейка на основе Queue
Кликните здесь для просмотра всего текста

Pascal
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
uses graphWPF;
 
begin
  Window.Title := 'Змейка';
  window.SetSize(20 * 30 - 10, 20 * 30 - 10);
  Window.IsFixedSize := True; 
  var NewGame: boolean; 
  var q := new queue<integer>;//очередь для нажатых клавиш
  OnKeyDown := procedure (k: key) →
  lock q do //блокируем q от второго потока в теле программы во избежание получения мусора      
   case k of
    key.Left: q.Enqueue(1);
    Key.Right: q.Enqueue(2);
    Key.Up: q.Enqueue(8);
    Key.Down: q.Enqueue(9);
    Key.Escape: halt();
    Key.Enter: NewGame := true; //по нажатию Enter - новая игра
  end;
  repeat
    NewGame := false;
    Window.Clear;
    var (i, j) := (-1, 0); //координаты головы
    var n := 5; //длина змейки
    var p := 2; //направление следующего шага для головы
    var a := new queue<(integer,integer)>; //создаем массив индексов для звеньев змейки
    a.Enqueue((-1,0));//голова змейки в очередь
    var nn := 1; //для наращивания звеньев змейки с каждым шагом до длины n, вначале одно звено (голова)
    var (bi, bj) := Random2(2, 19); //координаты еды
    FillRectangle(bi * 30, bj * 30, 30, 30, Colors.DarkCyan); //вывод еды на экран
    repeat
      lock q do begin //блокируем q от второго потока OnKeyDown во избежание получения мусора      
         var newp := if q.Any then q.Dequeue else p; //перебираем очередь
         while q.Any and (abs(newp - p) < 2) do newp := q.Dequeue; //всё не нужное выбрасываем
         if abs(newp - p) > 2 then p := newp; //если новое направление "поворот", то записываем его в p
       end;
      case p of //меняем индекс для головы змейки в торону p
        1: i -= 1; //влево
        2: i += 1;//вправо
        8: j -= 1;//вверх
        9: j += 1;//вниз lock
      end;
      if i = -1 then i := 19 else if i = 20 then i := 0; //перескок от стенки до стенки в другой конец экрана
      if j = -1 then j := 19 else if j = 20 then j := 0;
      var XBOCT := a.Peek; //индекс хвоста (первый элемент очереди)
      if a.Contains((i, j)) and ( XBOCT <> (i, j)) then //проверка на столкновение головы с телом змейки
        begin FillRectangle(i * 30, j * 30, 30, 30, Colors.Magenta); break; end;
      a.Enqueue((i,j)); //новвый положение(индекс) головы в очередь
      if (i = bi) and (j = bj) then //поели? удлиняем змейку на три клетки
      begin 
        n += 3;
        (bi, bj) := Random2(0, 19); //новые координаты еды, которые..
        while a.Contains((bi, bj)) do (bi, bj) := Random2(0, 19); //..не совпадут с телом змейки
        FillRectangle(bi * 30, bj * 30, 30, 30, Colors.DarkCyan);//вывод еды на экран
      end;
      var pXBOCT: integer; //направление в котором нужно затирать клетку хвоста (след после хвоста)
      if abs(XBOCT.Item1 - a.ElementAt(1).Item1 + (XBOCT.Item2 - a.ElementAt(1).Item2) * 2 + 3) < 6 then//не перескчили в другой край экрана?
        pXBOCT := (XBOCT.Item1 - a.ElementAt(1).Item1 + (XBOCT.Item2 - a.ElementAt(1).Item2) * 2 + 3);
      for var f := 0 to 29 do //вывод головы и затирание хвоста
      begin
        case p of //рисуем плавный шаг головы в новой клетке
          1: FillRectangle(29 - f + i * 30, j * 30, 1, 30, Colors.Red);
          2: FillRectangle(i * 30 + f, j * 30, 1, 30, Colors.Red);
          8: FillRectangle(i * 30, 29 - f + j * 30, 30, 1, Colors.Red);
          9: FillRectangle(i * 30, j * 30 + f, 30, 1, Colors.Red);
        end; 
        if n-nn = 0 then case pXBOCT of //затираем плавно последнюю клетку хвоста
          4: FillRectangle(29 - f + XBOCT.Item1 * 30, XBOCT.Item2 * 30, 1, 30, Colors.White); //лево
          2: FillRectangle(XBOCT.Item1 * 30 + f, XBOCT.Item2 * 30, 1, 30, Colors.White); //право
          5: FillRectangle(XBOCT.Item1 * 30, 29 - f + XBOCT.Item2 * 30, 30, 1, Colors.White);//вверх
          1: FillRectangle(XBOCT.Item1 * 30, XBOCT.Item2 * 30 + f, 30, 1, Colors.White); //вниз
        end;     
        sleep(7);//скорость змейки
      end;
      if n-nn = 0 then a.Dequeue else nn += 1; //если змейку нужно нарастить после еды, то очередь не уменьшаем
    until NewGame;
    repeat sleep(100) until NewGame; //ждем нажатия Enter или Escape
  until false;
end.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
05.10.2020, 10:02
Помогаю со студенческими работами здесь

Игра Змейка (хвост змеи)
Немогу сообразить каким способом пришить змее хвост.Подкиньте пару идей. PS:грубо,страшно написано но я пока по другому не умею ) ...

Алгоритм игры "змейка". Как заставить двигаться хвост?
Подскажите плз, как заставить двигаться хвост змейки %) Голова бегает нормально, а вот хвост чтоит на месте. Покрайней мере заставил...

Сделать хвост в игре "Змейка" на Unity
Всем привет! Я учусь программировать на С# и попутно делаю игру(змейку) в Unity. Вообщем не могу сделать хвост змее. Кто может подсказать...

Игра "Змейка": чтобы змейка не съедала сама себя
Здравствуйте! Пишу змейку на VB 2010. Не получается составить условие того, что бы змейка не ползла в направлении обратному...

Голова хвост
Нужно просто поменять местами голову и хвост списка, вот, что я наделал: (defun transposition_first (x) (if(= x '()) '() ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru