(я уже не знаю что мне и куда (кого?) посылать чтобы привести решение к
задаче про "рефери", поэтому это решение напишу здесь. А дальше сами разбиретёсь куда это всё и как. Моё дело -- послать.)
(вообще по-моему последние сообщения -- не в тему. В том смысле что выделять их надо отсюда)
Анализ задачи:
Понятно, что "обычный стек", "R-стек" из постановки задачи -- не более чем метафоры. Использовать R-стек на самом деле, думаю нет острой необходимости.
На самом деле нет необходимости не только в двух стеках, но даже и в одном стеке. По сути, всё "состояние игры" описывается одним числом -- от нуля до десяти. Поражения засчитывается тому у кого число-состояние станет равно нулю или десяти. В таком представлении это уместнее называть "перетягиванием каната", только если команда повалится назад, она тоже проигрывает.
Далее рисуем схемку взаимодействия -- это будет эдакий треугольник. Нужно однозначно определить взаимодействие:
1. От бойца к рефери поступают сигналы -- ходы.
2. От рефери к бойцу с периодичностью поступает информация об игре.
Оба вида делаем словами в модулях бойцов:
Код:
move ( -- flag )
Боец делает "ход", это слово вызывается из тела рефери, затем он (рефери) по результатам изменяет состояние игры, делает проверки на поражение, и так далее..
Код:
board ( state -- )
Рефери вызывает это слово, чтобы уведомить бойца об обстановке. Боец, у себя, анализирует состояние игры и соответствующим образом подправляет свои внутренние структуры данных (при их наличии), чтобы привести их в актуальному виду, готовясь при следующем вызове move дать более правильный по обстановке "ход".
Само собой, что для тестирования "рефери" нужно писать и "бойцов" тоже. Но так как это сейчас лишь побочная задача и никак не прописывается, делаем их насколько возможно тупыми -- по move будет выдаваться псевдослучайное логическое значение, board ничего делать не будет (кроме поглощения значения со стека, само собой).
Я начал писать и достаточно быстро что-то написал. Но код мне резко не понравился. И тут меня осенил свет -- я вдруг понял что ООП тут более чем красиво сделает. Сказано -- сделано. Сел, переписал с объектами.
Это, кстати была первая программа моя с ООП на Форте. Вообще. Тут я не полностью уверен кто это так хорош оказался: я, или ООП, или движок ООП, но программа заработала с пол-пинка, с первого запуска.
На радостях от моего "просветления" и полпинковой послушности программы я даже и отладки не делал особой.
Так как религия и прочие тараканы в головах (не мои) не велят мне дать спокойно архив с тремя файлами, я даю вам возможность поработать мышкой самому, вставляя и копируя содержимое и имена трёх файлов:
Сам рефери:
"referee2.f"Код:
REQUIRE KEEP ~profit/lib/bac4th.f
REQUIRE NOT ~profit/lib/logic.f
REQUIRE FOR ~profit/lib/for-next.f
REQUIRE CLASS: ~day/joop/oop.f
: in-the-red-corner S" joe louis.f" ;
: in-the-blue-corner S" mike tyson.f" ;
VARIABLE game
: change-game ( move -- ) IF game 1+! ELSE -1 game +! THEN ;
: lost? ( -- lost? ) 5 game @ - ABS 5 = ; \ или =0 или =10
VARIABLE moves-made
: send-updates? ( -- send? ) moves-made DUP 1+! @ 5 MOD 0= ;
: show-game ( -- ) CR ." [" game @ FOR ." ." NEXT ." |" 10 game @ - FOR ." ." NEXT ." ]" ;
CLASS: fighter <SUPER Object
2 CELLS VAR name
CELL VAR lastMove
CELL VAR predMove
CELL VAR move-xt
CELL VAR board-xt
: :move move-xt @ EXECUTE ;
: :board board-xt @ EXECUTE ;
: :init 123 lastMove ! 123 predMove ! ;
: :free name @ FREE THROW ;
: :set ( addr u -- ) \ закачка методов из файла
WARNING KEEP WARNING 0!
2DUP HEAP-COPY OVER name 2! \ имя сохраняем
INCLUDED
S" move" SFIND IF move-xt ! ELSE 2DROP THEN
S" board" SFIND IF board-xt ! ELSE 2DROP THEN ;
: :print ( -- ) name 2@ CR TYPE SPACE ;
: :lost ( -- ) own :print ." lost!" ;
: :dsc ( -- ) own :print ." disqualified!" ;
: :check-moves ( move -- dsc? ) lastMove @ = lastMove @ predMove @ = AND ;
: :record-move ( move -- ) lastMove @ predMove ! lastMove ! ;
: :make-move ( -- game-over? ) own :move ( move )
own :print DUP IF ." +" ELSE ." -" THEN
DUP own :check-moves IF own :dsc DROP TRUE EXIT THEN
DUP own :record-move
change-game
lost? DUP IF own :lost THEN ;
;CLASS
<< :move
<< :board
<< :set
<< :lost
<< :make-move
fighter :new VALUE red
in-the-red-corner red :set
fighter :new VALUE blue
in-the-blue-corner blue :set
: check-game show-game send-updates? IF game @ red :board game @ blue :board THEN ;
: let-rumble-start
moves-made 0!
5 game !
show-game
\ Судья бросает монетку, кому делать первый ход:
32 CHOOSE 15 >
IF red blue ELSE blue red THEN TO blue TO red
\ если надо меняем местами -- у красных есть право первого хода
BEGIN
red :make-move IF EXIT THEN
check-game
blue :make-move IF EXIT THEN
check-game
AGAIN ;
STARTLOG
let-rumble-start
И два простейших бота:
"joe louis.f"Код:
REQUIRE RANDOM lib/ext/rnd.f
REQUIRE NOT ~profit/lib/logic.f
MODULE: louis
123 ->VARIABLE r2
123 ->VARIABLE r3
\ тут должны быть мозги
\ память и прочие анализы
\ но их нет.. (пока?)
EXPORT
: move ( -- flag ) 32 CHOOSE 15 > DUP r3 @ = OVER r2 @ = AND IF NOT THEN DUP r2 @ r3 ! r2 ! ;
: board ( state -- ) DROP ;
;MODULE
\ Луис работает случайными ударами. Но обязательно следит чтобы не дисквалифицироваться.
"mike tyson.f"Код:
REQUIRE NOT ~profit/lib/logic.f
MODULE: tyson
\ тут должны быть мозги
\ память и прочие анализы
\ но их нет.. (пока?)
VARIABLE r
r 0!
EXPORT
: move ( -- flag ) r @ NOT DUP r ! ;
: board ( state -- ) DROP ;
;MODULE
\ Тайсон работает: "качелями", правой-левой, правой-левой. Поэтому он дисквалицироваться не может по определению.
Точно так же низзя никаким образом показывать лик проро.. э-э.. работу программы. Поэтому чтобы примерно увидеть что делается в ней, вы должны её запустить (уже после того как создадите-скопируете-вставите-сохраните, и так -- три раза).
Как я говорил, глюки возможны, так как программа почти не отлаживалась. Возможно что-то вылезет при попытках написать ботов.
Хых.. Почитал
in4 и понял что, может быть, нужно добавлять ещё один вид взаимодействия -- для уведомления бота о ходах противника. Впрочем может этого и не надо из-за того что тут появляется простая тактика "компенсирования".