1. Pascal / Говнокод #12107

    +99

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    Procedure TForm1.CreateObjects(Column, Row: Integer); // Процедура создания кнопок (ячеек).
    Var
      i, j, iLeft, iTop, iRow : Integer; // Переменные, отвечающие за расположение ячеек на форме. (Кроме iRow, она содержит номер ячейки по горизонтали.)
      SpeedButton : array of TSpeedButton; // Собственно, сам массив с ячейками.
      cColumn : Char; // Номер ячейки по вертикали.
      iMine : ShortInt; // Дополнительная переменная кол-ва бомб на поле.
    BEGIN
    {Присваиваем начальные значения переменным. :7:}
      iLeft := 0; // Начальная позиция по горизонтали.
      iTop := 5; // Начальная позиция по вертикали.
      iRow := 1; // Номер ячейки по горизонтали.
      iMine := MineCount; // Кол-во мин на поле.
      cColumn := 'A'; // Номер ячейки по вертикали.
      SetLength(SpeedButton, Row+1); // Массив с ячейками.
    {------------------------------------------ :7:}
    
    {Создаём новые списки. :8:}
      FObjectList := TObjectList.Create; // Список с объектами.
      Form2.FMineList := TStringList.Create(); // Список с номерами мин на поле.
    {--------------------- :8:}
    
    {Главный цикл создания игрового поля :9:}
      For i := 1 to Column do // Запускаем цикл создания по вертикали.
       Begin
        For j:=1 to Row do // Теперь тоже самое по горизонтали.
         bEgin
           SpeedButton[j] := TSpeedButton.Create(Self); // Создаём очередную ячейку на поле.
           SpeedButton[j].Parent := GamePanel; // Этим параметром указываем, что ячейка принадлежит первой форме.
           SpeedButton[j].Top := iTop; // Задаём расположение ячейки по вертикали.
           SpeedButton[j].Name := cColumn + IntToStr(iRow); // Задаём имя ячейки.
           SpeedButton[j].Flat := True; // Используем св-во кнопок не отображаться на рисунке.
           SpeedButton[j].Font.Color := clBlue; // Делаем цвет текста синим.
           SpeedButton[j].Font.Style := [fsBold]; // Делаем шрифт жирным.
           SpeedButton[j].OnClick := SpeedButton1.OnClick; // Указываем, какая процедура будет вызываться при клике на ячейку.
           SpeedButton[j].OnMouseDown := SpeedButton1.OnMouseDown; // Указываем, какая процедура будет вызываться при нажатии на ячейку.
           SpeedButton[j].Left := iLeft+8; // Задаём расположение ячейки по горизонтали, смещая её на 8 пикселей вправо.
           {Устанавливаем бомбу в ячейку. :10:}
             If (iMine <> 0) and (SpeedButton[j].Name <> 'A1') then // Если кол-во бомб не превышено, то...
              beGin
               Randomize; // Генерируем список ПСЧ.
               SpeedButton[j].Tag := Random(2); // Случайным образом задаём, будет ли бомба находится в ячейке.
               If SpeedButton[j].Tag = 1 then
                begin
                 Form2.FMineList.Add(SpeedButton[j].Name); // Добавляем новую запись в массив бомб.
                 Dec(iMine); // Уменьшаем счетчик мин на единицу.
                end;
              enD;
           {----------------------------- :10:}
             FObjectList.Add(SpeedButton[j]);// Добавляем новую запись в массив ячеек.
             iLeft := iLeft + 24; //Увеличиваем расстояние между ячейками.
             If iRow = Row then iRow := 1 // Если номер следующей ячейки по горизонтали неправильный, то меняем его на 1.
              Else Inc(iRow); // Иначе увеличиваем номер.
         eNd;
        cColumn := Char(Ord(cColumn) + 1); // Увеличиваем номер ячейки по вертикали.
        iTop := iTop + 24; // Увеличиваем положение ячейки по вертикали.
        iLeft := 0; // Обнуляем позицию ячейки по горизонтали.
       End;
    {----------------------------------- :9:}
    
      ImageList1.GetBitmap(0, (FindComponent('A1') as TSpeedButton).Glyph); // Загружаем спрайт в первую ячейку.
      Form2.FMineList.SaveToFile('OUTPUT.TXT'); // Сохраняем расположение мин в файл.
      MineCountLabel.Caption := IntToStr(Form2.FMineList.Count); // Показываем колво мин на поле.
    END;
    
    Function TForm1.CheckMove(X,Y : ShortString): Boolean; // Функция проверки валидности ячейки. Она должна находится рядом с текущей.
    Var
     iXod, iAlf : Integer; // Вспомогательные переменные.
    BEGIN
     result := false; // Презумпция вины :)
     iXod := Abs(StrToInt(Y) - StrToInt(dPos.yInt)); // Получаем расстояние до текущей ячейки по горизонтали.
     iAlf := Abs(Ord(dPos.xChr) - Ord(X[1])); // Получаем расстояние до текущей ячейки по вертикали.
     If ((iXod <= 1) and (iAlf <= 1)) and ((iXod <> 0) or (iAlf <> 0)) then result := true; // И если оно не больше одного, то разрешаем ход.
    END;
    
    Procedure TForm1.SpeedButton1Click(Sender: TObject); // Главная процедура нажатия на кнопку(ячейку).
    Var
      i : Integer; // Счётчик цикла.
      cObject : TSpeedButton; // Сам объект.
      Str, j : String; // Вспомогательная переменная имени ячейки.
      Count : Integer; // Вспомогательная переменная. (стр. 160)
    BEGIN
    {Подготавливаем переменные :1:}
      cObject := TSpeedButton(Sender); // Получаем ячейку, на которую кликнули.
      Str := cObject.Name; // Присваиваем вспомогательной переменной имя задействованной ячейки.
      dClick.xAlf := Str[1]; // Присваиваем переменной первый символ задействованной ячейки по вертикали.
      dClick.yFlt := Copy(Str, 2, Length(Str)); // Получаем номер ячейки по горизонтали.
    {------------------------- :1:}
    ...

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

    Запостил: Govnocoder#0xFF, 12 Ноября 2012

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

    • А, через Name передавать. Тоже нормально. В WinSight лулзы можно словить.
      Ответить
    • > // Процедура создания кнопок (ячеек).
      Блин, я думал что они вручную аккуратно разложены на форме... Цикл создания кнопок уменьшает градус говнокодности данного говокода :(

      > Randomize
      А вот Randomize перед каждым random'ом это то еще говнецо... Особенно если ГПСЧ инициализируется временем с точностью до мс...
      Ответить
      • Именно, мне тогда так и не удалось сделать нормальный ГПСЧ для минного поля. Приходилось играть почти на одинаковых полях. А цикл там потому, что игрок может сам настраивать количество клеток на поле.
        Ответить
    • Почти все переменные нормально названы за мелким исключением TForm1.
      bEgin~eNd //м-м даже так.

      Вообще очень настроженно отношусь к коду в котором каждая строка раскомментирована. Но тут ничего смертельного. Так, мелочи.
      Совсем не такое говно как рекламировали.
      Ответить
      • Я еще xAlf и yFlt не понял как переводятся. x и y то понятно, а вот что такое alf и flt?
        Ответить
        • > alf
          Alf сокращено от Alfavit. То есть координата клетки по вертикали. Flt координата по горизонтали. Это дополнительные значения координат.
          Ответить
          • > Alf сокращено от Alfavit.
            Резонно.

            > Flt координата по горизонтали.
            А можно английское слово, от которого это порождено?
            Ответить
            • Оно ни от чего не порождено. Я как щас помню откуда взялось "flt". Это как alf, только числовой. Тогда мне почему-то в голову взбрела первая ассоциация с числами - float. Ну я взял первую букву из этого слова и вставил её заместо первой из "alf". Вот так-то!
              Ответить
      • Так значит каковы основные претензии? TForm1, Rondomize?
        Ответить
        • Там еще бульщит
          >X,Y : ShortString
          Зачем координаты строками?
          >iLeft := iLeft + 24
          >SpeedButton[j].Left := iLeft+8;
          Я такое в своё время тоже писал. Сейчас бы наверное вынес 8 в константу и танцевал от неё.
          Помню в VB была херь TwipsPerPixel или как-то так. В дельфях тоже должно быть такое, 8 - это ж не пиксели? Вот от неё бы и мерял.
          Ответить
          • > Зачем координаты строками?
            Сейчас уже не вспомню почему выбрал строки вместо чисел. Наверное, тогда мне показалось что так "компактней". Думаете есть смысл переписать под числа?
            С меджик намберами тоже всё понятно.
            Ответить
            • >Думаете есть смысл переписать под числа?
              Я бы не стал. Работает - не трогай.
              Тупая работа вроде этой не принесет пользы.
              Ответить
              • 8 и 24 это размер обычной SpeedButton. ТЗ в чём измеряется положение, а по-моему в пикселях.
                Ответить
          • DBU может?
            Ответить
            • Dialog Base Unit? А что с ним не так?
              Ответить
              • Показалось. Если в дельфях и есть какая-то независимая от расширения экрана система координат, то я не осилил ее нагуглить.

                Майкрософтовская системная венгерка жжот, кстати.
                Ответить
            • Deutsche Bundesstiftung Umwelt?
              Ответить
        • Странно кстати. В обычном сапере можно ходить куда угодно, а здесь только в соседнюю к открытым клеточку?
          Ответить
          • Тут мы играет человечком, который ходит только на соседние клетки.
            Ответить
            • Аа. А если мины выстроятся в цепочку и не дадут ему пройти?

              P.S. И интересно бы узнать что означают alf и flt?
              Ответить
              • У него есть инвентарь, там куча ништяков, от детектора мин, до бутылки водки, которую можно пить.
                Ответить
                • > У него есть инвентарь, там куча ништяков, от детектора мин, до бутылки водки, которую можно пить.
                  А можно грабитьминировать корованы?
                  Ответить
                  • Корованы я не запилил, но крафтинг и прокачка есть. Даже звуковое сопровождение присутствует!
                    Ответить
                    • Так лучше выложи сиё шпиливо на ргхост - интересно заценить.
                      А то в коде говна я не вижу.
                      Ответить
                    • Хм, а что и из чего он крафтит, если на поле лежат только мины?

                      P.S. Присоединяюсь к предыдущему оратору с просьбой выложить куда-нибудь прогу.
                      Ответить
    • > Сохраняем расположение мин в файл
      Сапёр с сейвами это читерство!
      Ответить
      • Это же дебуг-версия, она никогда не была зарелизена.
        Ответить
      • Если сейв делается только при закрытии приложения и подрыве - то нет.
        Ответить
    • показать все, что скрытоПо мне так любой код на делфи выглядит как говно.
      Ответить
      • Даже такого пасцалененавистника как я не тошнит ни от кода, ни даже от одно- джвух- пробельных отступов.
        Ответить
      • http://rghost.ru/41530524/image.png
        Ответить
    • Dec(iMine); // Уменьшаем счетчик мин на единицу.

      Лучше вообще без комментариев, чем с такими.
      Ответить
      • От нечего делать я тогда каждую строчку прокомментировал. Даже:
        result := false; // Презумпция вины :)
        Ответить
        • Ладно. Это в любом случае лучше чем Javadoc.
          Ответить
    • // комментарий // комментарий
      Ответить
      • Переправа переправа, берег левый берег правый. Почему-то напомнило.
        Ответить
    • Я правильно понял, что мины будут кучковаться с одного края?
      Ответить
      • только если заказать кол-во мин < кол-ва клеток × ½
        Ответить
        • Да, ещё есть вероятность того, что нужное число мин не расставится.
          Ответить
      • Да. Надо переписать алгоритм разбрасывания мин. Есть идеи?
        Ответить
        • Кидаешь в первый 10 клеток, потом
          for i := 1 to 10 do
          swap(i, random(i+1,100));
          Ответить
          • Этот алгоритм не масштабируется до 0ля клеток. У Fai масштабируется.
            Ответить
            • Да и с ростом числа клеток на поле тоже. Так алгоритмы не записывают. Записывать в общем виде алгоритмы надо.
              Ответить
            • А для -3+4j клеток?
              Ответить
              • Да даже для 9ти клеток не масштабируется в таком виде.
                Ответить
          • С большой вероятностью в первых 10ти клетках не будет бомб, особенно с ростом поля.
            Ответить
            • Мы с равной вероятностью получим любое из C(n,k) расположений мин.
              Учи матан, гумно.
              Ответить
          • Правка:
            for i := 1 to 10 do
            swap(i, random(i,100));
            то есть клетку можно поменять с самой собой.
            Иначе не сойдётся даже количество различных выхлопов ГСЧ за n итераций, будет (n-1)*(n-2)*...*(n-k)=C(n-1,k-1). А надо C(n,k)

            Нет, это не C(n,k). Короче, если все мины разные, то число их расположений будет n*(n-1)*...(n-k+1)=n!/(n-k)! . И алгоритм мой тоже имеет столько же выходов в зависимости от результатов ГСЧ.
            Чтобы доказать равномерность, надо доказать, что для каждого расположения мин существует выход алгоритма, дающий это расположение
            Ответить
            • Так как количество расположений равно количеству выходов алгоритма, то из существования выхода для каждого расположения следует то, что этот выход единственный. Тогда равномерность очевидна.
              Ответить
              • Доказывать существование выхода, дающего данное расположение, юудем по индукции. База: мин ноль, доказывать нечего.
                Переход:
                берём любое расположение k мин на поле из n клеток. Берём выход алгоритма k-1 мины для поля из n-1 клеток, который даёт нужное распложение для мин с номерами 2,3,4...k, такой выход существует по индукционному предположению.
                Смотрим, какая клетка после данной перестановки переставилась туда, куда мы хотим поставить мину 1.
                Тогда берём, ставим мину 1 на место этой клетки, делаем перестановку для (k-1) на (n-1), получаем нужную перестановку
                чтд
                Ответить
                • Вообщем тебе понравился этот алгоритм, тк легко доказывается по индукции?
                  Ответить
                  • Съеби в биореактор, быдлокодишка, убей себя об стенку, как Томми.
                    Ответить
                    • Откуда такой батхерт? Подруга не даёт чтоли? Рассказывай если хочешь, может мы тебе посоветуем.
                      Ответить
                      • Учи матан или иди на метан.
                        Ответить
                        • Какой ещё матан? Это то что ты рассказываешь? Это простейшие вещи. Основы. Если для тебя это матан - иди на метан.
                          Ответить
            • >Короче, если все мины разные
              Ответить
            • Только при реализации твоего алгоритма заметил:
              > random(i,100)
              С каких пор рандом принимает несколько аргументов? Или ты свою ф-ю писал? У меня не компилится короче.
              Ответить
              • Или ты RandomRange имел ввиду?
                Ответить
                • Ну блин, это псевдокод же.
                  Если бы я написал Random(cell_count-i+1)+i, то что, было бы понятнее?
                  Ответить
                  • Поправь меня, если где неправ.
                    1. Кидаем в первые N клеток бомбы (единицы):
                    For i := 1 to MinesCount do
                      MineArray[i] := 1;

                    2. Проходимся по всему массиву и каждый элемент меняем местами с другим случайным элементом:
                    For i := 1 to High(MineArray)-1 do Swap(i, RandomRange(1,LengthOfArray));
                    Ответить
                    • > 2. RandomRange(1,LengthOfArray))
                      Как можно быть таким невнимательным
                      Ответить
                      • Дошло:
                        For i := 1 to High(MineArray)-1 do Swap(i, Random(LengthOfArray-i+1)+i);
                        Ответить
                        • Да.
                          Кстати, это всё для случая нумерации от 1, ну ты понял. Так паскальнее ^^

                          > High(MineArray)
                          > LengthOfArray

                          Ты определись
                          Ответить
                          • > Ты определись
                            Использую переменную, вызывать лишний раз функцию ни к чему.
                            > случая нумерации от 1
                            А если юзать i := 0, какие подводные камни?
                            Ответить
                            • > Использую переменную, вызывать лишний раз функцию ни к чему.

                              У тебя фигня в алгоритме же. В двух местах, в которых должна быть одна и та же сущность, я вижу разные вещи.


                              Что за High(), она же только для динмассива возвращает число используемых элементов. А в динмассиве с нуля начинается.

                              > А если юзать i := 0, какие подводные камни

                              Нумерацию сдвинуть трудно?
                              Так, сколько тебе лет, каков твой стаж?
                              Ответить
                              • Я исправил. У меня везде LengthOfArray вместо High.
                                > она же только для динмассива
                                MineArray у меня динамический массив.
                                В общем, спасибо. Всё работает как надо.
                                > Так, сколько тебе лет, каков твой стаж?
                                Нискажу.
                                Ответить
                                • > MineArray у меня динамический массив.

                                  И при этом ты так спокойно пошёл писать алгоритм, явно предназначенный для нумерации от 1?!
                                  Ответить
                                  • Ну да, его длина всегда будет > 2 элементов. Что не так?
                                    Ответить
                                    • Херню несёшь.
                                      Ладно, подскажу, как вообще правильно надо действовать для любых индексов начала и конца:
                                      for i := Low(a) to Pred(High(a)) do
                                        Swap(i, i+random(High(a)+1-i));
                                      Ответить
                                    • Короче, вот код. Или ты меня щас посылаешь на йух, или объясняешь что не так:
                                      Var
                                       MineArray : array of Byte;
                                      ...
                                      Procedure TMainForm.generateRandomArea(MinesCount: Integer = 20);
                                      Var
                                        i,j,LengthOfArray : Integer;
                                      
                                      Procedure SwapEx(a,b:integer);
                                      Begin
                                       MineArray[a] := MineArray[a] - MineArray[b];
                                       MineArray[b] := MineArray[a] + MineArray[b];
                                       MineArray[a] := MineArray[b] - MineArray[a];
                                      End;
                                      
                                      BEGIN
                                       LengthOfArray := High(MineArray);
                                       For j := 0 to MinesCount-1 do  MineArray[j] := 1;
                                      
                                        For i := 0 to LengthOfArray-1 do SwapEx(i, Random(LengthOfArray-i+1)+i)
                                      END;
                                      Ответить
                                      • 1. SwapEx перепиши нормально, без этой хуйни, мы не на устной олимпиаде по информатике.
                                        2. Почему LengthOfArray хранит не длину, а верхний индекс? Назови нормально. LastIndex типа там.
                                        Логика цикла перестановок правильная.

                                        И ещё, я раньше тоже индексировал массивы от 0 до Length-1, а потом Ада меня отучила от этого.
                                        Ответить
                                        • > SwapEx перепиши нормально
                                          Я тут заметил кое-что. Если использовать 1й вариант SwapEx (как в моём коде выше), то кол-во мин будет каждый раз варьироваться от 17 до 20. А если переписать:
                                          Procedure SwapEx(a,b:integer);
                                          Var p: integer;
                                          begin
                                            p :=  MineArray[a];
                                            MineArray[a] :=  MineArray[b];
                                            MineArray[b] := p;
                                          End;

                                          то всё норм. Почему так?
                                          Ответить
                                          • Потому что ты пиздец, про подвобные камни кулхацкерного метода обмена значений учат на 1м курсе.

                                            Вот есть у тебя код
                                            a:=a-b;
                                            b:=a+b;
                                            a:=b-a;
                                            а теперь представь, что a и b являются ссылками на один и тот же адрес. После первой же строки они обе обнуляются.
                                            Про индексы аналогично.
                                            Про xor вместо +- аналогично.
                                            Ответить
                                            • не ссерьтесь, девочки
                                              вы оба занимаетесь преждевременной оптимизацией
                                              да еще и на паскале
                                              Ответить
                                              • обоснуй
                                                Ответить
                                                • ты померил профилировщиком? тормозит? нет? тогда ты занимаешься преждевременной оптимизацией
                                                  Ответить
                                                  • Кроме профилировщика есть ещё такая штука, как оценка алгоритмической сложности.
                                                    Ответить
                                                    • Это ты хочешь повышения до капитана?
                                                      Ответить
                                                      • Это я тонко намекаю на то, что чтобы отличить говно от неговна, не обязательно иметь под рукой специальные программы.
                                                        Ответить
                                                • От обоснуя слышу!
                                                  Ответить
                                          • Вот молодежь пошла... нет, чтобы подебажить процедуру на разных примерах, самому разобраться, что же в ней не так... порадоваться тому, что сам справился с проблемой. Нет, надо запостить нубовопрос на форум и ждать пока мамочка Тарас расскажет что же тут не так.

                                            > Потому что ты пиздец
                                            Два чаю этому сэру.
                                            Ответить
          • Я так и не понял:
            > Кидаешь в первый 10 клеток
            Куда конкретно кидать?
            Ответить
        • 1. Заполняешь всё поле минами
          2. Если мин больше чем нужно - удаляешь случайную.
          3. Если ровно столько сколько нужно - выходишь из цикла.
          4. В противном случае переходишь на шаг 2.

          Плюс алгоритма в простоте и том, что для входных данных только одно условие - число мин должно быть неотрицательным числом.
          Ответить
          • > 2. Если мин больше чем нужно - удаляешь случайную.
            А как правильно брать случайные числа? Тут выше говорили что Randomize преде Random`ом говно.
            Ответить
            • Randomize нужно вызывать один раз при старте проги. Дальше тупо Random'ы по необходимости.
              Ответить
              • Randomize инициализирует ГСЧ текущим временем. Random выдаёт случайное число и переводит ГСЧ в новое состояние
                Ответить
                • Я что-то написал не так?
                  Ответить
                • Тарас, сходи лучше код Роджера Хуя в соседнем топике почитай, я его немножко деобфусцировал.
                  Ответить
            • > Randomize преде Random`ом говно.

              Random сам по себе говно, ищи вихрь мерсена, а то как же играть в сапёра, без равномерного распределения мин?
              Ответить
              • Подозреваю что рандом нечто подобное и использует. Вот правда не люблю рандомы с глобальным состоянием.
                А вот твистер из крестов с локальным состоянием в объекте или рандом в Хаскеле - норм
                Ответить
                • > Подозреваю что рандом нечто подобное и использует.
                  Не стоит подозревать. Там какой-нибудь тупейший конгруэнтный генератор в духе:
                  seed := seed * 1005001 + 12345;
                  result := seed mod max;
                  Если есть желание - загляни в исходники делфевого RTL, благо они открыты.
                  Ответить
                  • А в сишечке/крестах также в rand?
                    Ответить
                  • А подумать?
                    То, что ты сказал, выдаст период длины max
                    Ответить
                    • Константы взяты от балды. Лень открывать википедию и брать правильные.
                      Ответить
                      • Я не про константы. А про способ получения результата по сиду.
                        Ответить
                        • Да я и первую то строку криво написал. Там должен еще стоять модуль не кратный двум. Иначе оно и до max не дотянет.

                          И к тому же я забыл, как правильно преобразовывают генератор чисел от 0 до N в генератор от 0 до M ;(

                          Помню, что что-то типа буферной переменной, из которой делением извлекаются случайные числа нужного размера, а когда битов остается мало - в нее набиваются новые, взятые из генератора.
                          Ответить
                          • > И к тому же я забыл, как правильно преобразовывают генератор чисел от 0 до N в генератор от 0 до M ;(

                            Не поверишь
                            Seed*M/N

                            В Паскале именно так и делается, так как там N=2^32, то делается mul, потому возвращается содержимое edx.
                            В сишке возвращаются старшие 16 бит сида, поэтому rand()%n не зацикливается слишком быстро.
                            Ответить
                            • > Seed*M/N
                              Ну да, согласен, для конгруэнтного говногенератора такой способ более чем адекватен.

                              Но распределение получается чуть-чуть перекошенным. Если N не делится на M, то некоторые числа выпадают немного чаще остальных.

                              Портить хорошие генераторы типа вихря мерсена таким преобразованием нехорошо, поэтому я и пытался вспомнить как это делается с равномерным распределением (см. статью ниже).
                              Ответить
                              • Да, random(3), например, будет выдавать одно число примерно на одну миллиардную чаще (или реже), чем другие.
                                Ответить
                                • А random(100500), например, будет выдавать примерно 700 чисел на две стотысячных реже чем другие...
                                  Ответить
                                • А в random(1005494) почти половина чисел (если быть точным - 502422 штуки) будут выпадать на 0.00023 чаще чем другие.
                                  Ответить
                        • Вот нашел статейку о кошерной генерации чисел в заданном диапазоне:

                          http://mathforum.org/library/drmath/view/65653.html
                          Ответить
                          • Hi GVNKD,

                            The method does work, but... с какого для тасования колоды карт перестало хватать линейного конгруэнтного PNRG mod RANGE_MAX + RANGE_MIN?
                            Ответить
                            • > тасования колоды
                              Сначала прочитал как тарасования колоды
                              Ответить
                            • > с какого для тасования колоды карт перестало хватать линейного конгруэнтного PNRG mod RANGE_MAX + RANGE_MIN
                              С того дня как всякие онлайн казино должны проходить сертификацию на труъ рандомность. Вот и приходится покупать аппаратные источники труъ рандома, и использовать такие методы...
                              Ответить
                              • > онлайн казино
                                ждем некогда созданную мною игрушку Сапёр онлайн, с мультиплеем и на бабки
                                Ответить
                              • > покупать аппаратные источники
                                Вроде как можно собрать самому даже. Нужен только АЦП, шумящий диод и контроллер. Для серьёзных применений не годится, конечно.
                                Кроме того, можно насолить впрок. Получил сорок гигабайт чистой энтропии и выбирай себе. Главное - не попадаться с этим правоохренителям на глаза.
                                Ответить
                                • > Вроде как можно собрать самому даже.
                                  Ну если надо было бы проходить сертификацию - я бы все-таки купил готовый.

                                  P.S. Хотел одно время спаять такой генератор на стабилитроне - ни один стабилитрон шуметь не захотел ;(
                                  Ответить
                            • К слову о тарасовании колоды карт и линейном конгруэнтном ГПСЧ: http://ru.pokerstrategy.com/forum/thread.php?threadid=155416.

                              Здесь как раз описан частный случай алгоритма, который приводил выше Тарас (ка пример правильного алгоритма). А так же описаны последствия хренового тасования: Авторы рассказывают, что написали программу, которая рассчитывала полный расклад, увидев первые пять карт, за одну секунду. А для покера это само собой эпик фейл.
                              Ответить
                              • В начале он описал очевидные нубские ошибки.
                                Если их исправить, то рассказ в конце станет невероятным, т.к. нет реальной возможности узнать сколько было в LSB таймера на момент старта и сколько раундов RNG выполнилось до начала анализа.
                                Ответить
                                • > сколько раундов RNG выполнилось до начала анализа.
                                  На самом деле даже если пофиксить те баги, и оставить стандартный конгруэнтный PRNG, то проблема останется.

                                  Перед началом алгоритма сид может находится в одном из 2^32 состояний, а
                                  4млрд вариантов это не такое уж большое число. Это намного меньше, чем 52!.

                                  Да, в точности угадать расклад уже не удастся. Если мы играем колодой из 52 карт, то 5 карт попадут нам на руки одним из 311875200 способов. Поделим 2^32 на это число, и получим в районе 14 раскладов. Для ускорения вычислений можно составить таблицу, пусть она и будет весить гигабайты, зато поиск будет мгновенным.

                                  Итого - посмотрев на полученные карты, и не зная начального состояния генератора, мы получаем примерно 14 вариантов расклада. А это очень неплохой чит для такой игры как покер.
                                  Ответить
          • Мой рабочий и эффективный алгоритм даже не плюсанули, а эту квадратичную парашу плюсанули.
            Ответить
            • Ай, не плачь, не плачь, не плачь,
              Я куплю тебе калач.
              Если будешь плакать -
              Куплю худой лапоть!
              Ответить
            • Мой тоже рабочий, при этом простой и даёт хорошее распределение. KISS, помнишь?
              Ответить
              • Твой нихуя не простой.
                У тебя быдлоалгоритм, он тормозит, он долго пишется.
                Мой алгоритм быстро работает, быстро пишется, даёт идеальное распределение, но чтобы это понять, нужен матан.
                Это как сортировка перебором и квиксорт.
                Ответить
                • Я не знаю, какой долбоёб проминусовал, но тут КИСС применять - это пиздец.
                  Это всё равно что удалять плохие элементы из массива по одному (со сдвигом хвоста), потому что это просто и понятно. А на просьбу сделать нормально (через проход с двумя итераторами) говорить, что это сложно и нарушает КИСС.
                  Я так понимаю, у быдлокодеров появился новый флаг?
                  Раньше они писали говно, потому что "Дейкстра сказал не оптимизировать", теперь они пишут говно, потому что "в Википедии написано не усложнять".
                  Какую идиому не придумай, а быдлокодер её всё равно в качестве отмазки применит.
                  Ответить
                  • > какой долбоёб проминусовал
                    Нейтрализовал.

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

                    > Мой алгоритм быстро работает, быстро пишется
                    Да, я посмотрел твой алгоритм, действительно задумка хорошая. И он даже проще.

                    P.S. А людей незнакомых с ходу быдлокодерами называть перестань..

                    P.P.S. По-поводу "квадратичности" твой алгоритм отрабатывает n операций, где n - необходимое количество мин, а мой - (m-n), где n - количество мин, а m - площадь поля.

                    Таким образом, если нужно разместить 90 мин на поле в 100 клеток, мой алгоритм будет быстрее.

                    А если необходимо раместить 1 мину на поле в 1000 клеток - тут твой лидер.
                    Ответить
                    • > P.P.S. По-поводу "квадратичности" твой алгоритм отрабатывает n операций, где n - необходимое количество мин,

                      Расскажи, как ты делаешь операцию "убрать случайную мину".

                      > P.S. А людей незнакомых с ходу быдлокодерами называть перестань..

                      Я тебя быдлокодером не называл, я сказал только, что у тебя быдлоалгоритм, и что быдлокодеры любую идиому применят в качестве оправдания своему быдлокоду.
                      Ответить
                      • > Расскажи, как ты делаешь операцию "убрать случайную мину".
                        Ну например так:
                        1. Заводим дополнительный массив, в который в начале алгоритма помещаем координаты всех мин;
                        2. Генерируем случайное число, используем его как индекс в массиве, получаем координаты мины которую надо удалить;
                        3. Берем последний элемент массива и переставляем его на место только что поюзанного;
                        4. ???
                        5. Удаление мин за О(1) при O(n) памяти, PROFIT
                        Ответить
                        • Ну это да, но мне интереснее, как Fai собрался реализовывать.
                          Ответить
                        • > 1. Заводим дополнительный массив, в который в начале алгоритма помещаем координаты всех мин;
                          Т.е. сначала массив будет полностью забит единицами (бомбами), или как? И такой массив у меня уже есть, ничего заводить не надо.
                          Ответить
                          • Да, и в итоге приходим к моему же алгоритму, но с другого конца.
                            Ответить
                            • Твой алгоритм это кстати генерация перестановки последовательности (1,1,...,1,0,0,...,0), в которой k единиц и n-k нулей, из которого выкинута бесполезная перетасовка хвоста нулей.
                              Ответить
                          • Забей на это квадратичное говно, Тарас привел хороший алгоритм:
                            http://govnokod.ru/12107#comment160674

                            > Куда конкретно кидать?
                            Хм. Очень странный вопрос. Как-нибудь нумеруете все клетки поля по порядку. В первые K клеток помещаете мины...

                            P.S. А если все-таки хочется поюзать алгоритм Fai - его лучше немного перевернуть:

                            1. Инициализируем само поле нулями, а дополнительный массив координатами всех клеток:
                            field = {{0, 0}, {0, 0}}
                            free = {(1,1), (1,2), (2,1), (2,2)}
                            freecnt = 4

                            2. Для каждой мины
                            2.1. Генерируем случайное число rnd в диапазоне 1 . .freecnt (например 3)
                            2.2. free[rnd] покажет координаты клетки, в данном случае (2,1), помещаем в нее мину:
                            field = {{0, 0}, {1, 0}}
                            2.3. Переставляем free[freecnt] на место free[rnd], уменьшаем freecnt на единицу

                            P.P.S. Код приводить не буду из образовательных целей.
                            Ответить
            • >а эту квадратичную парашу плюсанули
              Зависть плохое чувство.
              И алгоритм Fai не квадратичный (но n в О(n) побольше).
              Ответить
              • > 2. Если мин больше чем нужно - удаляешь случайную.

                Расскажи мне про эту часть подробнее.

                > 3. Если ровно столько сколько нужно - выходишь из цикла.
                > цикла
                Ответить
            • Твой первоначальный алгоритм не только плюсанули, но даже реализовали:
              http://ideone.com/dWAorT
              Ответить
          • > выходишь из цикла
            > Плюс алгоритма
            Плюс в том, что оригинальный баг починен и мины теперь кучкуются с другого края :-)
            Ответить

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