Кресты / Говнокод #27990 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
#include <iostream>
using namespace std;
void Brezenhem(char **z, int x0, int y0, int x1, int y1)
{
  int A, B, sign;
  A = y1 - y0;
  B = x0 - x1;
  if (abs(A) > abs(B)) sign = 1;
  else sign = -1;
  int signa, signb;
  if (A < 0) signa = -1;
  else signa = 1;
  if (B < 0) signb = -1;
  else signb = 1;
  int f = 0;
  z[y0][x0] = '*';
  int x = x0, y = y0;
  if (sign == -1) 
  {
    do {
      f += A*signa;
      if (f > 0)
      {
        f -= B*signb;
        y += signa;
      }
      x -= signb;
      z[y][x] = '*';
    } while (x != x1 || y != y1);
  }
  else
  {
    do {
      f += B*signb;
      if (f > 0) {
        f -= A*signa;
        x -= signb;
      }
      y += signa;
      z[y][x] = '*';
    } while (x != x1 || y != y1);
  }
}
int main()
{
  const int SIZE = 25; // размер поля
  int x1, x2, y1, y2;
  char **z;
  z = new char*[SIZE];
  for (int i = 0; i < SIZE; i++) 
  {
    z[i] = new char[SIZE];
    for (int j = 0; j < SIZE; j++)
      z[i][j] = '-';
  }
  cout << "x1 = ";     cin >> x1;
  cout << "y1 = ";     cin >> y1;
  cout << "x2 = ";     cin >> x2;
  cout << "y2 = ";    cin >> y2;
  Brezenhem(z, x1, y1, x2, y2);
  for (int i = 0; i < SIZE; i++) 
  {
    for (int j = 0; j < SIZE; j++)
      cout << z[i][j];
    cout << endl;
  }
  cin.get(); cin.get();
  return 0;
}

https://prog-cpp.ru/brezenham/

спойлер: автор тян

Запостил: digitalEugene digitalEugene, (Updated )

Комментарии (99) RSS

  • Меня тут больше всего смешение крестов и сишки напрягает, на самом деле. Ну возьми ты вектор, раз на крестах пишешь, зачем все эти утечки с ручными new...

    А идея алгоритма вроде норм освоена.
    Ответить
  • > спойлер: автор тян
    Поздравляю, digitalEugene!
    Ответить
    • Мдааа, сюда то это зачем? Мало того что друзья узнали, так теперь ещё пол страны. Эй сладкая попка) если ты читаешь выложи сюда его профиль вк и тел, коминг аут нужен человеку, поможем всей страной)
      Ответить
  • Хреновый алгоритм, он всегда на первом шаге увеличивает обе координаты

    -*-----------------------
    --**********************-
    -------------------------
    Ответить
  • В deltaX (тут B) перепутаны местами x0 и x1, из-за этого пишем x -= signb, но y += signA
    Ответить
  • пофиксил
    https://ideone.com/Ndovg3
    void Brezenhem(char **z, int x0, int y0, int x1, int y1)
    {
      int A, B, sign;
      A = y1 - y0;
      B = x1 - x0;
      if (abs(A) > abs(B)) sign = 1;
      else sign = -1;
      int signa, signb;
      if (A < 0) signa = -1;
      else signa = 1;
      if (B < 0) signb = -1;
      else signb = 1;
      A = abs(A);
      B = abs(B);
      int f = 0;
      int x = x0, y = y0;
      if (sign == -1) 
      {
        do {
          z[y][x] = '*';
          f += A + 1;
          if (f >= B + 1) {
            f -= B + 1;
            y += signa;
          }
          x += signb;
        } while (x != x1 + signb);
      }
      else
      {
        do {
          z[y][x] = '*';
          f += B + 1;
          if (f >= A + 1) {
            f -= A + 1;
            x += signb;
          }
          y += signa;
        } while (y != y1 + signa);
      }
    }
    Кодстайл соблядён.
    Ответить
  • Перевёл на "Си":
    #include <stdio.h>
    #include <stdlib.h>
    
    void Brezenhem(int size, char z[][size], int x0, int y0, int x1, int y1)
    {
      int A, B, sign;
      A = y1 - y0;
      B = x1 - x0;
      if (abs(A) > abs(B)) sign = 1;
      else sign = -1;
      int signa, signb;
      if (A < 0) signa = -1;
      else signa = 1;
      if (B < 0) signb = -1;
      else signb = 1;
      A = abs(A) + 1;
      B = abs(B) + 1;
      int f = 0;
      int x = x0, y = y0;
      if (sign == -1) 
      {
        do {
          z[y][x] = '*';
          f += A;
          if (f >= B) {
            f -= B;
            y += signa;
          }
          x += signb;
        } while (x != x1 + signb);
      }
      else
      {
        do {
          z[y][x] = '*';
          f += B;
          if (f >= A) {
            f -= A;
            x += signb;
          }
          y += signa;
        } while (y != y1 + signa);
      }
    }
    int main()
    {
      #define SIZE 25 // размер поля
      int x1, x2, y1, y2;
      char z[SIZE][SIZE];
      for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
          z[i][j] = '-';
        }
      }
      printf("x1 = ");
      scanf("%d", &x1);
      printf("y1 = ");
      scanf("%d", &y1);
      printf("x2 = ");
      scanf("%d", &x2);
      printf("y2 = ");
      scanf("%d", &y2);
      Brezenhem(SIZE, z, x1, y1, x2, y2);
      for (int i = 0; i < SIZE; i++) 
      {
        for (int j = 0; j < SIZE; j++)
          putchar(z[i][j]);
        puts("");
      }
      return 0;
    }
    https://ideone.com/bThnq2

    > void Brezenhem(int size, char z[][size], int x0, int y0, int x1, int y1)
    Именно поэтому я за "Си"
    Ответить
      • Долго искал нормальный вореант, устал, остановился на этом:
        #include <stdio.h>
        #include <stdlib.h>
        
        void Brezenhem(int size, char z[][size], int x0, int y0, int x1, int y1)
        {
          int A, B, sign;
          A = y1 - y0;
          B = x1 - x0;
          if (abs(A) > abs(B)) sign = 1;
          else sign = -1;
          int signa, signb;
          if (A < 0) signa = -1;
          else signa = 1;
          if (B < 0) signb = -1;
          else signb = 1;
          A = abs(A) + 1;
          B = abs(B) + 1;
          int f = 0;
          int x = x0, y = y0;
          if (sign == -1) 
          {
            do {
              z[y][x] = '*';
              f += A;
              if (f >= B) {
                f -= B;
                y += signa;
              }
              x += signb;
            } while (x != x1 + signb);
          }
          else
          {
            do {
              z[y][x] = '*';
              f += B;
              if (f >= A) {
                f -= A;
                x += signb;
              }
              y += signa;
            } while (y != y1 + signa);
          }
        }
        int main()
        {
          int size, x0, y0, x1, y1;
          printf("Size: ");
          scanf("%d", &size);
          printf("Size: ");
          scanf("%d", &x0);
          printf("Size: ");
          scanf("%d", &y0);
          printf("Size: ");
          scanf("%d", &x1);
          printf("Size: ");
          scanf("%d", &y1);
          char z[size][size];
          Brezenhem(size, z, x0, y0, x1, y1);
          for (int i = 0; i < size; i++)
          {
            printf("%c", z[i][0]);
          }
          return 0;
        }
        Ответить
          • #include <stdio.h>
            #include <stdlib.h>
            
            void Bresenham(int size, char z[][size], int x0, int y0, int x1, int y1)
            {
                int dx = abs(x1-x0),
                    dy = abs(y1-y0),
                    d = dx+dy;
                int i, j, ii = dx-1, jj = dy-1;
                if (d==0) {
                    int r = dy / 2;
                    for (i=y0; i<=y1; i++)
                        Bresenham_x(size, z, x0+i, x0+y1, i, r, &j);
                }
                else if (d>0) {
                    int s = dx / 2;
                    for (i=x0; i<=x1; i++)
                        Bresenham_y(size, z, i, y0+i, i, s, &j);
                }
                else if (d<0) {
                    int s = -dy / 2;
                    for (i=x0; i<=x1; i++)
                        Bresenham_y(size, z, i, y0+i, i, s, &j);
                }
            }
            
            int main()
            {
                int size, i, j, k, n, m, i0, i1, j0, j1;
                int x0, y0, x1, y1, x[1][size], y[1][size], a;
                char z[size][size];
            
                scanf("%d", &size);
                for (i=0; i<size; i++)
                    for (j=0; j<size; j++)
                        scanf("%c", &z[i][j]);
            
                Bresenham(size, z, x0, y0, x1, y1);
                printf("n=%d m=%d\n", n, m);
                a = x[0][0];
                for (i=1; i<=n; i++) {
                    if (i<=m) {
                            x[i][0] = x0+i-1;
                        y[i][0] = a;
                    }
                    else
                        x[i][0] = x1+i-1;
                    for (j=1; j<=i; j++) {
                        x[i][j] = x[i][j-1]+y[i][j-1];
                        y[i][j] = a;
                    }
                    a = x[i][n-1];
                }
                for (i=0; i<size; i++) {
                    for (j=0; j<size; j++)
                        printf("%c", z[i][j]);
                    printf("\n");
                }
                return 0;
            }
            Ответить
  • Все 90-е люди такой хуйней в играх косые линии рисовали
    Ответить
    • Не все. Некоторые полагались на стандартную библиотеку (если игра не совсем рилтаймовая и пирфоманс не нужен, либо если картинка составлялась из готовых спрайтов).
      Ответить
        • Да вроде другого ничего не было. Но это не надо было реализовывать, если полагаешься на готовую либу.

          Я вспомнил «Бейсик» на «Агате», в котором не было оператора CIRCLE, и окружность приходилось реализовывать самому. А синус эта гадость вычисляла невыносимо медленно, поэтому итерироваться по углу было нельзя.
          Ответить
          • Круг ведь тоже можно рисовать подобием брезенхейма.
            Ответить
          • > невыносимо медлено

            Ну представь как вычислять разложение в ряд (!) когда у тебя нету фпу (!), нету умножения (!) и даже складывать мантиссу приходится восьмибитными кусочками (!).

            Я помню у меня калькулятор тоже задумывался над синусами.
            Ответить
            • З.Ы. С другой стороны, конкретно синус можно и fixed'ами посчитать.

              CORDIC или как там его.
              Ответить
            • Используя признак Даламбера (см. статью Степенные ряды. Область сходимости ряда), легко проверить, что ряд сходится при любом «икс»: А что значит вообще «сходится»? По смыслу глагола – что-то куда-то идёт.
              Ответить
            • Именно по этому я за "таблитса синусов"
              Ответить
            • И правда, у 6502 из арифметики только сложение и вычитание. Ну ещё логические операции и сдвиги. Всё.

              Умножение и деление даже целых питухов разработчикам Бейсика пришлось пилить самостоятельно.

              А реализация плавающего — целое искусство.

              Регистры:
              A — аккумулятор, 8 бит;
              X, Y — индексные регистры, 8 бит;
              PC — счетчик команд, 16 бит;
              S — указатель стека, 8 бит;
              P — регистр состояния;

              Пи здесь.
              Ответить
            • У калькуляторов вообще всё интересно.

              Машинные регистры обычно четырёхбитные. Но их не видно даже на программируемых микрокалькуляторах. Их от пользователя скрывает микрокод.

              Аккумулятор X (который прибит к экрану) и «стековые регистры» — это, по всей вероятности, массивы из четырёхбитовых ячеек. То есть микрокод собирает из массива ячеек «макрорегистр».

              Числа обычно представлены как BCD. Одна четырёхбитовая ячейка — одна десятичная цифра. То есть на 8-разрядном микрокалькуляторе один «макрорегистр» состоит из восьми четырёхбитовых ячеек под мантиссу + несколько ячеек для хранения порядка и знака. При выводе на экран конвертировать число не нужно, представление уже готово. Ну почти готово. Нужно проверить порядок, если он небольшой, то вывести только мантиссу с нужным положением запятой, а если порядок огромный, то поставить запятую после первого знака мантиссы и вывести порядок.

              Погуглил...

              «Одно число с 8-разрядной мантиссой и 2-х разрядным порядком занимает 14 тетрад»

              Всё ещё интереснее:
              https://m.vk.com/@thntofff-vnedrenie-v-arhitekturu-sovetskih-programmiruemyh-kalkulyato

              Четырёхбитовые ячейки являются частью гигантского регистра.

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

              Для восьмиразрядного калькулятора хватит четырёх слагаемых формулы Тейлора. Пятое слагаемое уже выйдет за пределы разрядности.
              Ответить
                • Ничем. Разве что в данном примере не нужно вычислять критерий остановки. Количество членов можно зафиксировать.
                  Ответить
                  • Ну ряды довольно часто обрубают до фиксированной длины, смирившись с погрешностью в каких-то случаях и лишними вычислениями в других.
                    Ответить
                    • Нет, надо будет почитать.

                      Возможно, реализации каких-то частных случаев я уже видел...
                      Ответить
                    • Похоже, что калькуляторы как раз через CORDIC всё считают.
                      Ответить
          • > А синус эта гадость вычисляла невыносимо медленно, поэтому итерироваться по углу было нельзя.

            Для этой задачи синус нахуй не нужен
            https://wandbox.org/permlink/41wG3PdPotIwauSt

            Ну и да, можно по формуле y = sqrt((a-x)^2+(b-y)^2) найти кучу точек, и их соединить отрезками через брезенхейм
            Ответить
              • Именно через квадратный корень я и считал, когда мои одноклассники считали через синус.

                Про обход по двум координатам не думал. Интересно. Квадрат считается быстрее корня. Хотя на больших размерах уже наверное будет не очень быстро.

                Ещё есть вариант через дифференциальные уравнения:
                (x - a)dx + (y - b)dy = 0. Но тут будут накапливаться погрешности и результат может оказаться заметно неровным.
                Ответить
                • А зачем вообще корни, синусы?

                  Для заполенного круга они не нужны.
                  If ((x*x)+(y*y) <= r*r) Then
                     Pset(x,y);
                  End If

                  А для незаполненного там тоже есть итеративный алгоритм без корней.
                  Ответить
                • > Квадрат считается быстрее корня.

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

                  А если специальной таблицы поиска для квадратных корней нет, но есть таблица поиска для квадратов, для нахождения квадратного корня можно по ней ебнуть двоичным поиском, это конечно будет медленней
                  Ответить
                    • > На что получили ответ:
                      >> под квадрат надо в два раза больше бит под результат

                      > А под корень надо в два раза больше строчек в таблице.

                      Смотря с какой точностью какой интервал. Таблицу квадратов и корней еще можно всякими хитровыебаными методами зожимать. Можно еще воспользоваться формулой sqrt(a*b) = sqrt(a)*sqrt(b) из которой вытекает sqrt(a*2^(2*b)) = (2^b)*sqrt(a)

                      ну т.е. если надо посчитать квадратный корень из 70, используя инты, но получить сколько-то знаков после запятой, можно посчитать квадратный корень из 70 * pow(2, 2*n), и тогда будет n знаков после запятой
                      Ответить
                      • Можно сделать "логарифмическую линейку" и считать всё через логарифмы и экспоненты.

                        З.Ы. Блин, мы так CORDIC изобретём скоро.
                        Ответить
            • > соединить отрезками через брезенхейм

              Можно тупее: соединить вертикальными отрезками зеркальные точки:
              y1 = b + sqrt(r^2 - (x-a)^2)
              и
              y2 = b - sqrt(r^2 - (x- a)^2)

              Получим залитый круг.

              А если нужна окружность, сверху наложить круг чуть поменьше.

              Вот если нужно сохранять фон, тогда сложнее. Хотя всё равно брезенхейм не нужен. Просто берём единицу в качестве шага по x.
              Ответить
            • > отрезками

              Да там можно напрямую брезенхеймить. Алгоритм то довольно универсальный, любую f(x, y) = 0 можно обводить если получается быстро вычислить значение f в соседних точках.
              Ответить
      • Я полагался на uses graph и egavga.bgi, и у меня всё жутко тормозило, и я срал кирпичами, пока мне не объяснили старшие товарищи про геймлпуп, и как надо срать в память видеоадаптера, и флипать потом эту память

        хуй знает что можно написать на uses graph;
        Поле чудес?
        Ответить
        • Шахматы вполне норм получаются. Ну и что-нибудь ещё пошаговое и не графонистое.
          Ответить
          • Dwarf Fortress. На 486 как раз год генерации будет равен году реальному.
            Ответить
            • Там же буквы графонием рисуются, как бы не opengl...

              Хотя вроде был реально текстовый режим для игры по ssh.
              Ответить
          • Я Арканоид делал, работало норм. Затирал шарик чёрным, сдвигал координаты и рисовал новый.

            Правда не на 486-м, но мне кажется и на нём бы не тормозило.
            Ответить
            • Да много было игрушек на uses graph, которые на 486 работали сносно. Всё-таки 486 побыстрее предыдущих поколений.

              Шутер от первого лица а ля Дум, где нужно весь кадр перерисовывать, на uses graph не сделаешь, а вот игры с неподвижным фоном — вполне.
              Ответить
              • P.S. Я помню компьютерный класс из 386, где единственную машину 486 называли графической станцией, потому что на ней фоторедактор почти не тормозил.
                Ответить
        • vgafpga.bin небось нужен был чтобы плавно скроллить primary sruface (или как оно тогда называлось)
          Ответить
  • > автор тян

    Елена Вставская (Константинова), 1978-го года издания, Челябинск, доцент ЮУрГУ, замужем?
    Ответить
  • прикол в том что в отзывах к этой статье на сайте пишут:

    Спасибо, Елена, за понятное объяснение и элегантный код, очень всё упаковано, а ведь есть 8 вариантов знаков и отношений модулей A и B.

    и это явно не троллинг. судя по всему это те самые программисты по блок-схемам.
    Ответить
  • Кстати, важный вопрос. Куда пропала HACmEHbKA?
    Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8