Самый простой пример назад продолжений в Схеме без явной мутации

Если не мошенничество важнее самой игры, постарайтесь создать и представить свою игру так, чтобы она выглядела как решение математической задачи. Таким образом, сервер передаст экземпляр проблемы клиенту (пример A: шахматная доска, которая должна быть выиграна за 3 хода, пример B: случайно сгенерированный уровень с геометрической чертой), и пользователь должен будет решить ее и отправить обратно решение (пример A: выигрышные ходы, пример b: точные метки времени и интенсивность прыжков, чтобы избежать препятствий)

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

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

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

Конечно, этот подход требует много дополнительной работы: больше экземпляров игр (в идеале бесконечных и неповторяющихся), генерация на стороне сервера, проверка представлений на стороне сервера, ограничение времени и т. Д.

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

6
задан Paul Hollingsworth 11 June 2009 в 21:35
поделиться

3 ответа

Я не знаю, самый простой ли это, но вот пример использования обратных продолжений без какого-либо вызова set! или аналогичного:

(apply
  (lambda (k i) (if (> i 5) i (k (list k (* 2 i)))))
  (call/cc (lambda (k) (list k 1))))

Это должно оценить на 8 .

Немного интереснее:

(apply
  (lambda (k i n) (if (= i 0) n (k (list k (- i 1) (* i n)))))
  (call/cc (lambda (k) (list k 6 1))))

, который вычисляет 6! (то есть, он должен оценивать как 720 ).

Вы даже можете сделать то же самое с let * :

(let* ((ka (call/cc (lambda (k) `(,k 1)))) (k (car ka)) (a (cadr ka)))
      (if (< a 5) (k `(,k ,(* 2 a))) a))

(Чувак, подсветка синтаксиса stackoverflow на схеме сильно не работает.)

8
ответ дан 10 December 2019 в 00:43
поделиться

Вот лучшее, что я придумал:

AssertEqual(Eval("((call/cc (lambda (k) k)) (lambda (x) 5))", 5);

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

А, еще я придумал это как хороший пример модульного теста:

AssertEqual(Eval("((call/cc call/cc) (lambda (x) 5))", 5);

Я согласен с Джейкобом Б - я не думаю, что это так полезно без изменяемого состояния ... но было бы по-прежнему интересоваться контрпримером.

0
ответ дан 10 December 2019 в 00:43
поделиться

Думаю, вы правы - без мутации обратные продолжения не делают ничего такого, чего не могут делать прямые продолжения.

2
ответ дан 10 December 2019 в 00:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: