LINUX.ORG.RU

Pascal полноэкранная программа в терминале

 


1

1

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

program ClearScreen;
uses crt, sysutils;

const
  width = 12;
  height = 12;
  delay = 100;

var
  x, y, i, j : Integer;
  ch : Char;
  x_coord, y_coord : Integer;

procedure DrawGrid(x, y : Integer);
begin
  for i := 0 to 9 do
  begin
    for j := 0 to 9 do
    begin
      gotoxy(x + i, y + j);
      write('*');
    end;
  end;
end;

procedure MoveGrid(var x, y : Integer);
var
  dirX, dirY : Integer;
begin
  dirX := 1;
  dirY := 1;
  x_coord:= x;
  y_coord:= y;
  while not keypressed do
  begin
    for i := 0 to 9 do
    begin
      gotoxy(x_coord + i, y_coord);
      write('#');
      sleep(delay);
      gotoxy(x_coord + i, y_coord);
      write('*');
    end;
    for i := 0 to 9 do
    begin
      gotoxy(x_coord + 9, y_coord + i);
      write('#');
      sleep(delay);
      gotoxy(x_coord + 9, y_coord + i);
      write('*');
    end;
    for i := 9 downto 0 do
    begin
      gotoxy(x_coord + i, y_coord + 9);
      write('#');
      sleep(delay);
      gotoxy(x_coord + i, y_coord + 9);
      write('*');
    end;
    for i := 9 downto 0 do
    begin
      gotoxy(x_coord, y_coord + i);
      write('#');
      sleep(delay);
      gotoxy(x_coord, y_coord + i);
      write('*');
    end;

    if (x_coord = 0) or (y_coord = 0) or (x_coord = width-10) or (y_coord = height-10) then
    begin
      if (x_coord = width-10) then
        dirX := -1;
      if (x_coord = 0) then
        dirX := 1;
      if (y_coord = height-10) then
        dirY := -1;
      if (y_coord = 0) then
        dirY := 1;
    end;
    x_coord := x_coord + dirX;
    y_coord := y_coord + dirY;
    gotoxy(1,1);
    writeln('X:', x, ' Y:', y);
  end;
end;

begin
  clrscr;
  x := (ScreenWidth div 2) - 5;
  y := (ScreenHeight div 2) - 5;
  repeat
    DrawGrid(x, y);
    MoveGrid(x, y);
    ch := readkey;
  until ord(ch) <> 0;
  clrscr;
end.

1. Не стоит злоупотреблять глобальными переменными.

2. Достаточно не добегать до нижнего правого символа, чтобы не было прокрутки.

3. Вместо магических чисел (9) стоит использовать именованные константы.

4. Нажатие клавиши проверяется раз за 40*delay. Если нужна быстрая реакция, проверки нужны чаще ;)

bormant ★★★★★
()
Последнее исправление: bormant (всего исправлений: 2)
Ответ на: комментарий от bormant

Советы 1 и 3 конечно очень актуальны для одностраничной проги (нет). Тут скорее не очень понятно зачем вообще что-то выделено в отдельные процедуры было.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

1. Для скрытия курсора в линуксе используй termios, как-то так:

uses linux,stdio;

var
  old_attr, attr:termios;

begin
  tcgetattr(0, old_attr);
  tcgetattr(0, attr);
  attr.c_cc[VMIN] := 1;
  attr.c_cc[VTIME] := 0;
  attr.c_lflag := attr.c_lflag and not (ECHO or ICANON);
  tcsetattr(0, TCSAFLUSH, attr);

  // Твои дела ...

  tcsetattr(0, TCSAFLUSH, old_attr);
end

(взято отсюда: https://studfile.net/preview/584598/page:104/)

2. Для быстрой остановки замени циклы «for» на «while» и добавь условие с нажатием клавиши. Либо вставь «if keypressed then break;».

Novator ★★★★★
()
Ответ на: комментарий от firkax

Тут скорее не очень понятно зачем вообще что-то выделено в отдельные процедуры было.

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

hobbit ★★★★★
()

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

Так не смещайте. Удалите пересчет координат в конце MoveGrid().

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

Завершайте анимацию по нажатии клавиши сразу.

uses Crt, SysUtils;

const
  Width = 12;
  Height = 12;
  Delay = 100;
  GridWidth = 10;
  GridHeight = 10;
  GridBack = '*';
  GridRunner = '#';

procedure DrawGrid(x, y: Integer);
var
  i, j: Integer;
begin
  for i := 0 to GridHeight - 1 do begin
    GotoXY(x, y + i);
    for j := 0 to GridWidth - 1 do
      Write(GridBack);
  end;
end;

procedure MoveGrid(x, y: Integer);

  procedure Animate;
  var
    i: Integer;
  begin
    for i := 0 to GridWidth - 1 do begin
      GotoXY(x + i, y);
      Write(GridRunner);
      GotoXY(x + i, y);
      Sleep(Delay);
      Write(GridBack);
      if KeyPressed then Exit;
    end;
    for i := 0 to GridHeight - 1 do begin
      GotoXY(x + GridWidth - 1, y + i);
      Write(GridRunner);
      GotoXY(x + GridWidth - 1, y + i);
      Sleep(Delay);
      Write(GridBack);
      if KeyPressed then Exit;
    end;
    for i := GridWidth - 1 downto 0 do begin
      GotoXY(x + i, y + GridHeight - 1);
      Write(GridRunner);
      GotoXY(x + i, y + GridHeight - 1);
      Sleep(Delay);
      Write(GridBack);
      if KeyPressed then Exit;
    end;
    for i := GridHeight - 1 downto 0 do begin
      GotoXY(x, y + i);
      Write(GridRunner);
      GotoXY(x, y + i);
      Sleep(Delay);
      Write(GridBack);
      if KeyPressed then Exit;
    end;
  end;

begin
  while not KeyPressed do begin
    GotoXY(1, 1); Write('X:', x, ' Y:', y);
    Animate;
  end;
  if ReadKey = #0 then ReadKey;
end;

var
  x, y: Integer;
begin
  ClrScr;
  x := (ScreenWidth - GridWidth) div 2;
  y := (ScreenHeight - GridHeight) div 2;
  DrawGrid(x, y);
  MoveGrid(x, y);
  ClrScr;
end.

bormant ★★★★★
()
Последнее исправление: bormant (всего исправлений: 2)

Она рисует арену звёздочек и по контуру ходит символ решётка

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

dmitry237 ★★★
()
Ответ на: комментарий от bormant

GotoXY(x, y + i);

Что из себя представляет «арена», прямоугольник из звездочек, 10 знаков в ширину и 10 в высоту?

Я синтаксис паскаля не знаю от слова совсем, можно простыми словами? Мне нужен лишь сценарий словами.

Откуда здесь x и y, откуда эти параметры, координаты курсора, вызываются функцией GotoXY(x,y), я без понятия.

dmitry237 ★★★
()
Ответ на: комментарий от dmitry237

Что из себя представляет «арена», прямоугольник из звездочек, 10 знаков в ширину и 10 в высоту?

Да.

Откуда здесь x и y, откуда эти параметры, координаты курсора, вызываются функцией GotoXY(x,y), я без понятия.

x, y координаты курсора я без понятия где понятие ваше потерялось откуда куда бежало где искать нашлось когда где зачем чаем горячим напоить шишками еловыми не закидывать костер тушить по пионерски надо не греть одеяла тёплые на экране из верхнего левого угла x горизонтально вправо вниз вертикально y считаются на одну единицу один шаг курсора как будто шагает если бы мог ходить сюда-туда сам по себе по команде.

bormant ★★★★★
()
Ответ на: комментарий от bormant

верхнего левого угла x

Значит, что 0,0, это координаты по умолчанию для х и y. Откуда мне это знать?

я без понятия где понятие ваше потерялось

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

Понял, спасибо за изложение в произвольном виде. Можно было бы в двух фразах, без костров по-пионерски.

dmitry237 ★★★
()
Ответ на: комментарий от dmitry237

Там x,y - координаты «опорной точки» на экране, от которой вниз на GridHeight и вправо на GridWidth заполняется прямоугольник. Они не (0, 0) их в начале программы считают как центр экрана с учётом ширины/высоты самого прямоугольника (и тут же садятся в лужу при попытке пересчёта координат, ибо не попадают в задуманные x [0, heigt] и y [0, width], а проверки на строгое равенство «забора», а не на выход за пределы «зоны»).

В процитированной части фрагмент следует принципу наименьшего удивления, его сложно прочитать как-то иначе, нежели
для i от 0 до ВысотаСетки делай начни
пойди_XY x, y+i;
для j от 0 до ШиринаСетки делай
пиши *
закончи

bormant ★★★★★
()
Последнее исправление: bormant (всего исправлений: 2)
Ответ на: комментарий от bormant

для i от 0 до ВысотаСетки делай начни

Вы, извиняюсь, можете рассказать, ЧТО делает эта программа? Мне не нужен алгоритм ни в каком виде. Это же так просто рассказать обычным языком. Я изначально просто спросил, что такое «арена», так бы и сказали, что это 10 строк по 10 колонок звездочек, расположенных в центре хоста консоли. ВСЁ.

Как я понял. Есть, «арена» символов *, например 10х10, символ решетки # бесконечно «обходит» эту арену по контуру до тех пор пока пользователь не нажал клавишу. Правильно?

dmitry237 ★★★
()
Ответ на: комментарий от dmitry237

Есть, «арена» символов *, например 10х10, символ решетки # бесконечно «обходит» эту арену по контуру до тех пор пока пользователь не нажал клавишу. Правильно?

Всё так.
В исходном варианте задумка была чуть шире - после «обхода» «арена» должна была смещаться по диагонали, отражаясь от стенок воображаемого прямоугольника Width x Height, но из-за ошибок 1) в начальном положении и/или в 2) способе проверки условий, а также 3) из-за отсутствия стирания контура прежнего положения и 4) отложенной проверки нажатия клавиши вело себя мягко говоря странно.

bormant ★★★★★
()