LINUX.ORG.RU

Ответ на: комментарий от anonymous

Однако и без макросов програмки ничего выглядят...

У меня есть версия: лисп рулит по той же причине по какой рулит питон, а именно встроенные в язык типы данных высокого уровня + автоматическое управление памятью.

См. про EasySTL и D см. shootout про OCaml

И макросы здесь не причём. Ну да, сделали на макросах CLOS, ну молодцы, в других языках сделали объектную систему без макросов.

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

redvasily
()
Ответ на: комментарий от anonymous

>Имеется в виду ответ на вопрос на хуа макросы:)Програмка ниче так с макросами выглядит.

Как будто он не знал.

anonymous
()
Ответ на: комментарий от redvasily

>И макросы здесь не причём. Ну да, сделали на макросах CLOS, ну >молодцы, в других языках сделали объектную систему без макросов.

В "других языках" кроме объектной системы ничего не предлагается. А на макрах можно статический вывод типов сделать (делали как-то раз библиотеку поточных функторов, надстроили над CLOS еще один уровень с библиотекой TypeL). Потом опять же что-то вроде CELLS никак не сделать. В AllegroCL встраивается Prolog, на котором можно писать запросы к ООБД. Это уже одними библиотеками не осилить.

>Ну допустим используя макросы можно использотвать огрехи дизайнера >языка, напр. (loop ...), а можно сразу пользоваться языком в >котором дизайнеры не далали огрехов.

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

anonymous
()
Ответ на: комментарий от redvasily

Самый большой недостаток CL (и множества других Лиспов), это наличие чрезмерной свободы, язык мало ограничивает кодера. Поэтому написать ужасный неподдерживаемый код очень даже легко. Хотя я на CL и Scheme больше видел красивый код, видимо кривой код на Лиспе редко доживает до стороннего использования.

Неплохой выход из этой ситуации, небольшой группой из 2-3 человек создавать узкозаточенный DSL под задачу, который подхватят уже менее квалифицированные кадры и не смогут на нем делать бардак, а продуктивность их будет выше, чем если просто взять какой-то искусственно ограниченный язык (вроде Java). Но в отличие от DSL, который можно соорудить посредством lex/yacc, этим кодерам не надо будет на каждый DSL знакомиться с полностью новым языком, достаточно базовых знаний Лиспа + документация по особенностям конкретного DSL.

anonymous
()
Ответ на: комментарий от redvasily

> У меня есть версия: лисп рулит по...

И Ваша версия имеет право на жизнь ;) А если уточнить - для кого именно "лисп рулит" по указанным Вами причинам - так и версия вполне даже может оказаться верной :) Надеюсь, Вы на большее и не претендовали?

> Ну допустим используя макросы можно использотвать огрехи дизайнера языка, напр. (loop ...)

1. Вы хотели сказать не "использотвать огрехи", а "исправить огрехи"? :) И какой-же "огрех", по-вашему, исправляет loop? Уж не DO? :) И где я могу ознакомиться с факторами, определяющими "огрехи"?

2. Макры можно использовать много для чего. Но самое главное - их _можно_ использовать, и их удобно использовать. В отличие от большинства остальных языков ;)

> а можно сразу пользоваться языком в котором дизайнеры не далали огрехов.

Где, где это чудо "без огрехов"? :)

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

> Упс, не заметил, что definities используется не один раз - прошу прощения :)

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

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

> Самый большой недостаток CL (и множества других Лиспов), это наличие чрезмерной свободы, язык мало ограничивает кодера. Поэтому написать ужасный неподдерживаемый код очень даже легко. Хотя я на CL и Scheme больше видел красивый код, видимо кривой код на Лиспе редко доживает до стороннего использования.

Да нет, встречается. Особенно когда стараются минимизировать код "писательством" в стиле перловки - ужас 8-Е

> Неплохой выход из этой ситуации, небольшой группой из 2-3 человек создавать узкозаточенный DSL под задачу, который подхватят уже менее квалифицированные кадры и не смогут на нем делать бардак, а продуктивность их будет выше, чем если просто взять какой-то искусственно ограниченный язык (вроде Java). Но в отличие от DSL, который можно соорудить посредством lex/yacc, этим кодерам не надо будет на каждый DSL знакомиться с полностью новым языком, достаточно базовых знаний Лиспа + документация по особенностям конкретного DSL.

Может быть. Если "кодерам" будет доступен _только_ DSL - то уж лучше пусть это делает какой-нибудь "автомат-кодогенератор" ;) А если и DSL и остальной лисп - опять же так можно завернуть...

От этих скобочек действительно может тошнить, если ты не понимаешь что они тебе дают. Т.е. тупо набивать монотонный код в стиле FoxPro/dBase на лиспе, не задумываясь об оптимизации _собственного труда_ - большей пытки для лиспера наверное и быть не может ;)

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

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

А код где? :)

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

Человеческим языком. Попробую. CELLS - это библиотека, позволяющая определять классы, у которых есть вычисляемые поля. Прямая аналогия -электронная таблица, изменяем одну клеточку, меняются зависимые клетки. Мы определяем модель, пишем код, спокойно вплетая в него ссылки на другие клетки, далее CELLS при необходимости инициирует пересчет полей, так чтобы в нем участвовали только зависимые клетки. Вообще там не обязательно делать клетку именно полем какого-то класса, но так просто удобнее. Такое скорее всего можно сделать без макр, но пользоваться будет очень гиморно и будет тормозить.

anonymous
()
Ответ на: комментарий от yyk

> Вы хотели сказать не "использотвать огрехи", а "исправить огрехи"? :) И какой-же "огрех", по-вашему, исправляет loop? Уж не DO? :)

Угу. Всё так.

> Где, где это чудо "без огрехов"? :)

Это провокация. Нискажууу...

redvasily
()
Ответ на: комментарий от yyk

> Вот несколько сокращённая версия read-world:

Спасибо, приму.

> Хотя мне совсем непонятна система координат с 1, а не с 0. Имхо, ещё несколько можно было упростить программу :)

Исключительно в целях отладки. Стандартный принтер оптимизирует вывод комплексных чисел с нулевой мнимой частью, и координаты становятся трудночитаемыми. Сейчас, когда версия уже готова, можно и переделать под 0. А где упростится?

> Далее: (not (null x)) равносильно самому x, если только тебе не надо приципиально получить T вместо конкретного значения.

А это правильно? Я сам долгое время использовал для проверок не булевые значение. А потом в учебнике нашел, что правильно писать (null x). (not (null x)) видимо получилось в результате эволюции. Может быть, исправлю.

> Глобальные переменные - это зло ;-)

Небольшой трюк для оптимизации кода. В сетевой версии глобальных переменных уже нет. Кстати, извиняюсь, что сам не ковырял код на Питоне и Окамле (в данном случае я выступаю в роли чукчи-писателя :-), там мир представлен глобально или локально? Как насчет "разделения миров" для пользователей, которое тут упоминалось?

Сетевая версия уже почти готова. Но она мощнее заданной спецификации. В частности, добавлена команда reload-world, которая сбрасывает мир в исходное состояние, у пользователя есть возможность за один прием ввести целую цепочку команд (программу), а также в любой точке применить метакоманду autocollect, аналогичная запуску робота, который соберет все предметы в точку текущего положения героя. Если герой находится на выходе, то autocollect автоматически решает задачу. Минус в том, что при этом не трассируются промежуточные действия робота. Правильно было бы ввести возможность задания подпрограмм и параметр trace-level для программ и метакоманды auto, который позволит выполнять демонстрировать промежуточные состояния мира с заданной точностью. Пока что приделал отдельный вызов робота с дополнительным параметром trace-level, который позволит детализировать действия робота на трех уровнях -- "показать только результат", "показать порядок сбора предметов" и "показать все шаги" (уровень детализации определяется подпрограммами. Наконец, реализована метакоманда quit, которая позволяет корректно завершить работу клиента.

Интересно, насколько сложно реализовать все это в других языках? Я к тому, что на задаче такого уровня Лисп только начинает проявлять свою силу. То есть, предложенный DSL команд в оригинальной постановке оказался слишком примитивен.

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

> > Вы хотели сказать не "использотвать огрехи", а "исправить огрехи"? :) И какой-же "огрех", по-вашему, исправляет loop? Уж не DO? :)

> Угу. Всё так.

Неа, не согласен (с тем, что DO - огрех). Но спорить не буду, так как определение огреха не получил. Мало того, кое-где DO реализован через LOOP :)

> Это провокация. Нискажууу...

Т.е. его нет? ;)

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

> А код где? :)

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

К сожалению, сегодня вряд-ли допишу -- иду на тайную сходку питонистов. Может быть, завтра. И так до 4 утра курил доку по сокетам. Честно говоря, сделаны они там кривовато. Одна особенность чтения сокета на сервере и на клиенте стоила мне 3 часов экспериментов.

И вообще, общее впечатление, что неформатный ввод в Лиспе сосет нипадецки. Вечером покажу куски кода -- может, я чего не понял?

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

Вот один из примерчиков, сейчас еще найду менее лохматый:

(in-package :cells)

(defmodel computer ()
  ((hear :cell :ephemeral :accessor hear :initform (c-in nil))
   (salutation :initarg :salutation :accessor salutation :initform "hello")
   (response :initform nil :initarg :response
	             :unchanged-if Сstring= :accessor response)))

(def-c-output response ()
  (when new-value
    (format t "~&hear: ~a~%respond: ~a" (hear self) new-value)))

(defun hello-world ()
  (cell-reset)
  (let ((system (make-instance 'computer
                 :response (c? (let ((r (case (hear self)
                                          (:knock-knock "who's there?")
                                          (:world (concatenate 'string
                                                     (salutation self)
                                                    ", "
                                                    (string (hear self))))
                                          ((nil) "<silence>"))))
                                 (if (string= r .cache)
                                     (format nil "i said, \"~a\"" r)
                                   r))))))
    (format t "~&to-be initialization complete")
    (setf (hear system) :knock-knock)
    (setf (hear system) :knock-knock)
    (setf (hear system) :world)
    (setf (salutation system) "hiya")
    (values)))

#+test
(hello-world)

#| output

hear: nil
respond: <silence>
hear: knock-knock
respond: who's there?
hear: knock-knock
respond: i said, "who's there?"
hear: world
respond: hello, world

|#

anonymous
()
Ответ на: комментарий от redvasily

Вот отсюда: http://bc.tech.coop/blog/030911.html Примерчик:

(defmodel motor () ((status :cell t :initarg :status :accessor status :initform nil) (fuel-pump :cell t :initarg :fuel-pump :accessor fuel-pump :initform (c? (ecase (^status) (:on :open) (:off :closed)))) (temp :cell t :initarg :temp :accessor temp :initform (cv 0))))

(def-c-echo status ((self motor)) (trc "motor status changing from" old-value :to new-value))

(def-c-echo fuel-pump ((self motor)) (trc "motor fuel-pump changing from" old-value :to new-value))

(def-c-echo temp ((self motor)) (trc "motor temperature changing from" old-value :to new-value))

(defparameter *motor1* (to-be (make-instance 'motor :status (c? (let ((filtered-temp (^temp self (fsensitivity 0.05)))) (if (< filtered-temp 100) :on :off))))))

(dotimes (x 2) (dotimes (y 10) (let ((newtemp (+ 99 x (random 0.04) -.02))) (setf (temp *motor1*) newtemp))))

This produces the following results:

0> motor temperature changing from NIL :TO 0 0> motor temperature changing from 0 :TO 98.99401 0> motor temperature changing from 98.99401 :TO 99.01954 [snipped 8 intermediate readings] 0> motor temperature changing from 99.00016 :TO 100.00181 0> motor status changing from :ON :TO :OFF 0> motor fuel-pump changing from :OPEN :TO :CLOSED 0> motor temperature changing from 100.00181 :TO 100.0177 0> motor temperature changing from 100.0177 :TO 99.98742 0> motor temperature changing from 99.98742 :TO 99.99313 [snipped 6 intermediate readings]

anonymous
()
Ответ на: комментарий от redvasily

Пардон. Забыл про форматирование:

(defmodel motor ()
  ((status :cell t :initarg :status :accessor status :initform nil)
   (fuel-pump :cell t :initarg :fuel-pump :accessor fuel-pump 
	      :initform (c? (ecase (^status) (:on :open) (:off :closed))))
   (temp :cell t :initarg :temp :accessor temp :initform (cv 0))))


(def-c-echo status ((self motor))
  (trc "motor status changing from" old-value :to new-value))

(def-c-echo fuel-pump ((self motor))
  (trc "motor fuel-pump changing from" old-value :to new-value))

(def-c-echo temp ((self motor))
  (trc "motor temperature changing from" old-value :to new-value))


(defparameter *motor1* (to-be (make-instance 'motor 
		 :status (c? (let ((filtered-temp (^temp self (fsensitivity 0.05))))
			       (if (< filtered-temp 100) :on :off))))))

(dotimes (x 2)
  (dotimes (y 10)
    (let ((newtemp (+ 99 x (random 0.04) -.02))) 
      (setf (temp *motor1*) newtemp))))


This produces the following results: 

0> motor temperature changing from NIL :TO 0 
0> motor temperature changing from 0 :TO 98.99401 
0> motor temperature changing from 98.99401 :TO 99.01954 
[snipped 8 intermediate readings] 
0> motor temperature changing from 99.00016 :TO 100.00181 
0> motor status changing from :ON :TO :OFF 
0> motor fuel-pump changing from :OPEN :TO :CLOSED 
0> motor temperature changing from 100.00181 :TO 100.0177 
0> motor temperature changing from 100.0177 :TO 99.98742 
0> motor temperature changing from 99.98742 :TO 99.99313 
[snipped 6 intermediate readings]

anonymous
()
Ответ на: комментарий от eugine_kosenko

> А где упростится?

Возможно анализ значений кое-где можно будет упростить. Но будем уже смотреть в новой версии :)

> А это правильно? Я сам долгое время использовал для проверок не булевые значение. А потом в учебнике нашел, что правильно писать (null x). (not (null x)) видимо получилось в результате эволюции. Может быть, исправлю.

Ну, в самом начале может и полезно пользоваться такими методами. А на практике чаще всего так не делают. Более того, IF-ы с одним выражением, имхо, лучше менять на when/unless :)

> Интересно, насколько сложно реализовать все это в других языках? Я к тому, что на задаче такого уровня Лисп только начинает проявлять свою силу. То есть, предложенный DSL команд в оригинальной постановке оказался слишком примитивен.

Ну, можешь проделать с оппонентами "злую шутку" - решить заданную задачу, а потом предоставить "слегка доработанный" вариант (как в первой задачке было с добавлением БД) и попросить реализовать такую функциональность :)

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

>А как оно работает, вычисляется при обращении или при изменении >объекта, указанного в формуле?

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

anonymous
()
Ответ на: комментарий от eugine_kosenko

> там мир представлен глобально или локально?

Т.к. у меня мозг намерво искалечен ООП, то у меня world это или 
атрибут у объекта класса Server или локальная переменная в классе 
Robot

> Как насчет "разделения миров" для пользователей, которое тут 
> упоминалось?

Имхо излишнее. Нафиг, городить ещё user-id, session-id  и т.д.

> Интересно, насколько сложно реализовать все это в других языках? Я 
> к тому, что на задаче такого уровня Лисп только начинает проявлять 
> свою силу. То есть, предложенный DSL команд в оригинальной 
> постановке оказался слишком примитивен.

Ну простая оказалась задача, сам не ожидал, что всё окажется настолько просто. Но зато написал быстро :-)

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

Мне даже совсем несложно добавить autocollect, т.к. программа у меня 
написана как завещал ugoday по методолгоии СВН (сверху вниз наискосок)
и цикл сбора предметов у робота выглядит так:

while True:
    world = self.server.read_world()
    items = [i for i in world.items if i != world.entry]
            
    if not items:
        break
            
    self.moveTo(items[0])
    self.performAction('pickup')
    self.moveTo(world.entry)
    self.performAction('drop')

Можно на сервере при получении команды автоколлект, создвать робота,
и аналогично делать метод moveTo к предмету и обратно

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

Правильно ли я понимаю - робот не видит всего мира целиком, только текущие свободные направления ?

anonymous
()
Ответ на: комментарий от eugine_kosenko

Как тебе такой вариант доработок?

1. Добавляется комманда perform_actions(), принимающая список комманд, и возвращает список состояний мира _после_ исполнения этих комманд.

2. Добавляется комманда autocollect() которая стаскивает все предметы с карты в текущее положение персонажа.

3. Добавляется комманда move_to(x, y) перемещает персонажа в положение x, y и возвращает список промежуточных состояний мира.

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

>Робот видит весь мир сразу

В первоначальной задаче вроде бы было, что он видит только часть (???)

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

> Пардон. Забыл про форматирование:

Я так понимаю, что здесь просто вызываются функции при изменении атрибутов класса, собственно вычисления атрибутов не происходит, так?

Ты не мог бы пояснить что здесь и где происходит, а то боюсь неправильно пойму, и буду спорить совсем не с тем, что надо :-)

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

>Я так понимаю, что здесь просто вызываются функции при изменении >атрибутов класса, собственно вычисления атрибутов не происходит, >так?

Здесь пример простой очень. В цикле задается температура двигателя. Если температура больше 100.0 градусов, то двигатель выключается (status меняется на OFF), при этом задвижка топливного насоса закрывается. Как только температура снизится, двигатель снова запускается, при этом задвижка топливного насоса открывается.

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

>В "других языках" кроме объектной системы ничего не предлагается. А на >макрах можно статический вывод типов сделать (делали как-то раз >библиотеку поточных функторов, надстроили над CLOS еще один уровень с >библиотекой TypeL). Потом опять же что-то вроде CELLS никак не сделать. >В AllegroCL встраивается Prolog, на котором можно писать запросы к >ООБД. Это уже одними библиотеками не осилить.

если не секрет, где это таким занимаются?

anonymous
()

Итак, друзья. Я тоже решил поучавствовать в LOR-contest :)
Язык программирования - питон (т.е. на питоне теперь две версии).

Все исходники и тестовые данные в одном архиве:
http://rapidshare.com/files/486930/lor_contest--2006-oct--SmART.tar.bz2.html

Фишки:
------
- для асинхронной передачи данных использован модуль async_io собственного
  изготовления (присутствует в архиве); во многом это аналог стандартных
  asyncore&asynchat;
- сервер однопоточный (используется техника мультиплексирования);
- сервер поддерживает сколь угодно много клиентов одновременно;
- у каждого клиента свой собственный отдельный новенький мир ;) 
- клиентом для человека (hclient) могут служить: telnet, nc, sock, etc.
  поскольку сервер сразу возвращает данные в том виде как требует
  спецификация;
- на любую команду сервер отвечает либо "OK\n", либо "ERROR: описание\n";
- сервер: 74 строки (без пустых и комментариев);
- клиент: 70 строк (без пустых и комментариев);

Тестовые данные:
---------------
world1.txt:
##########
#  # $ # #
#$ #     .
#     #  #
##########

world2.txt:
#######  ##########
# # $ #  #        ###
# # ######  #$$#   $#
#    #      ####  ###
# ######  ###     #
# # $     #   #####
# #$  ##  #  ##
# #####  ##   #########
#            ##     $$#
### #######  #    $####
  # #     #    #####
  # ###   ######
  #   .
  #####

world3.txt:
         ####   ##         ##           ######
        #    ###  ####    #  #         #      #
        #             #   #   #  ####  #  ####
   ##  #   #####  #    ###   #  #    #  #  #
 ##  ##  ##    #  #          #  #   #    # #
#       #    ##  #           #   #   ####  #
 # ###  # ###   #     ###     ###         #
#   ##  #     ##     #####          ###  #
 #  ##   #####   ##  ######    ##  #   ##
  # ###        #####  #####   ####  #       ###
  #   #   #   #######    ##  ######  #   ###   #
   ##    # #  ##########   #  ######  ###    #  #
     ####   #  ###########  #  ######     ##### #
            #   ########  #  #    ############  #
          ##     ##        #  ##    ########## #
      ####        ##  ###   #   #    ###  #### #
   ###            ########  ####           ##  #
  #          #   ########          #       ## #
 #  ###     #######  ##   ##      # #    #### #
#  #####   #########     ####  ###  #   #####  #
#   ######  #   $ #### #######################  #
 #     #### #  ###############################  #
  #        ###     ######         #######      #
 #  # ####   #####        #######         #####
  ## #    #.#     ########       #########

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

Текст сервера и клиента:

adv_server.py:
#!/usr/bin/python
# -*- coding: cp1251 -*-
"""
Краткое описание:       сервер просейшей игры в стиле adventure
                        (в рамках LOR-contest "Фраза о лиспе...")
Автор:                  SmART [isee@inbox.ru]
Последнее изменение:    24 октября 2006

"""
from copy import deepcopy
import sys, async_io

class   Acceptor( async_io.TCP_Acceptor ):      # класс - TCP-аксептор
        def __init__( self, reactor, addr, source ):
                async_io.TCP_Acceptor.__init__( self, reactor, addr )
                self.world = w = []
                self.items = 0
                for n,s in enumerate( source ):
                        w.append( list(s) )
                        self.items += s.count('$')
                        try:    self.exit = s.index('.'), n
                        except: pass

        def handle_accept( self, t, conn, addr ):
                Connection( self.reactor, conn, deepcopy( self.world ), self.items, self.exit )

class   Connection( async_io.TCP_Connection ):  # класс - соедниение с клиентом
        def __init__( self, reactor, conn, world, items, pos ):
                async_io.TCP_Connection.__init__( self, reactor, conn )
                self.world = world
                self.items = items
                self.pocket = None
                self.x, self.y = x,y = pos
                self.dirty = deepcopy( world )
                self.dirty[y][x] = '@'
                self.moves = {'north':(0,-1),'south':(0,1),'east':(1,0),'west':(-1,0)}
                self.send('; Wellcome to the dark dungeon.\n'
                          '; Available commands: world, north,'
                          ' south, east, west, pickup, drop\n')

        def handle_message( self, t, msg ):
                moves = self.moves
                world, dirty = self.world, self.dirty
                x,y = self.x, self.y
                floor = world[y][x]
                send = self.send
                if moves.has_key( msg ):
                        dx,dy = moves[ msg ]
                        nx,ny = x+dx, y+dy
                        if  len(world) > ny >= 0 and nx >=0 \
                        and world[ny][nx] not in '#\n':
                                dirty[y][x] = floor
                                dirty[ny][nx] = '@'
                                self.x, self.y = nx,ny
                        else:
                                send('ERROR: illegal move\n')
                                return
                elif msg == 'pickup':
                        if not self.pocket and floor == '$':
                                world[y][x] = ' '
                                self.pocket = '$'
                        else:
                                send('ERROR: can not pickup\n')
                                return
                elif msg == 'drop':
                        if self.pocket and floor != '$':
                                self.pocket = None
                                if floor == '.':
                                        self.items -= 1
                                        if not self.items:  send('You win!\n', True)
                                else:   world[y][x] = '$'
                        else:
                                send('ERROR: can not drop\n')
                                return
                elif msg == 'world':
                        for row in self.dirty:  send( ''.join( row ) )
                else:
                        send('ERROR: unknown command\n')
                        return
                send('OK\n')
                
if __name__ == '__main__':
        if len( sys.argv ) != 3:
                print 'Usage: adv_server.py <world.txt> <port>'
                sys.exit(1)
        reactor = async_io.Reactor()
        Acceptor( reactor, ':%s' % sys.argv[2], file( sys.argv[1] ) )
        reactor.run()


adv_client.py:
#!/usr/bin/python -O
# -*- coding: cp1251 -*-
"""
Краткое описание:       робот-клиент для просейшей игры в стиле adventure
                        (в рамках LOR-contest "Фраза о лиспе...")
Автор:                  SmART [isee@inbox.ru]
Последнее изменение:    24 октября 2006

"""
from copy import deepcopy
import sys, async_io

class   Connector( async_io.TCP_Connector ):    # класс - TCP-коннектор
        def handle_connect( self, t, conn ):
                Connection( self.reactor, conn )

class   Connection( async_io.TCP_Connection ):  # класс - соединение с сервером игры
        def __init__( self, reactor, conn ):
                async_io.TCP_Connection.__init__( self, reactor, conn )
                self.world = []
                self.items = []
                self.exit = self.wavemap = None
                self.send('world\n')
                self.handle_message = self.import_world
        
        def import_world( self, t, msg ):
                print msg
                msg = msg.split(';',1)[0]
                if not msg:  return
                elif msg == 'OK':
                        self.wave_alg()
                        for x,y in self.items:  self.record_path( x, y )
                        self.handle_message = self.dummy
                        return
                x,y = 0, len( self.world )
                self.world.append( list( msg ) )
                for tmp in msg.split('$')[:-1]:
                        x += len(tmp)
                        self.items.append( (x,y) )
                        x += 1
                try:    self.exit = msg.index('@'), y
                except: pass

        def dummy( self, t, msg ):  print msg

        def wave_alg( self ):
                """ волновой алгоритм """
                self.wavemap = wavemap = deepcopy( self.world )
                x,y = self.exit
                wavemap[y][x] = 0
                max_y = len( wavemap ) - 1
                to_check = [ (x,y,1) ]
                unvisited = (' ','$')
                while to_check:
                        x,y,val = to_check.pop(0)
                        cases = ((x,y-1,y>0), (x,y+1,y<max_y),
                                 (x-1,y,x>0), (x+1,y,x<len(wavemap[y])-1))
                        for x,y,cond in cases:
                                try:    floor = wavemap[y][x]
                                except: continue
                                if cond and floor in unvisited:
                                        wavemap[y][x] = val
                                        to_check.append( (x,y,val+1) )
        
        def record_path( self, x, y ):
                wavemap = self.wavemap
                cmds = [ ('','pickup\n') ]
                val = wavemap[y][x]
                while val != 0:
                        cases = ((x,y-1,('north\n','south\n')), (x,y+1,('south\n','north\n')),
                                 (x-1,y,('west\n','east\n')),   (x+1,y,('east\n','west\n')))
                        for x,y,cmd in cases:
                                if wavemap[y][x] < val:
                                        cmds.append( cmd )
                                        break
                        val = wavemap[y][x]
                cmds.append( ('drop\n', '') )
                self.send( 'world\n'.join( [cmd[1] for cmd in cmds[::-1]] ) )
                self.send( 'world\n'.join( [cmd[0] for cmd in cmds[:]] ) )
                
if __name__ == '__main__':
        if len( sys.argv ) != 2:
                print 'Usage: adv_client.py <host>:<port>'
                sys.exit(1)
        reactor = async_io.Reactor()
        Connector( reactor, sys.argv[1] )
        reactor.run()

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

Да, ещё збыл упомянуть, что сервер спокойно хавает целые серии команд
(и от нескольких клиентов тоже). А робот-клиент эту возможность активно
эксплуатирует.

realsmart
()
Ответ на: комментарий от anonymous

>если не секрет, где это таким занимаются?

Контора небольшая, малоизвестная пока.

anonymous
()
Ответ на: комментарий от realsmart

Жжошь.

Карты откуда взял?

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

Заодно соптимизировал поиск.

Что за пакет async_io? Не могу найти.

Ты всегда ифы/елзы в одну строку пишешь, или специально для контеста?

З.Ы. По непробельным символам ты всех уделал :-)

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

>Карты откуда взял? Нарисовал за 3 минуты.

>Что за пакет async_io? Не могу найти. Он есть в архиве на рапидшаре (async_io.py). Смотри выше ссылку.

>Ты всегда ифы/елзы в одну строку пишешь, или специально для контеста? Только если операция однострочная, например: if a: return

А вот, например, длинные 'bla-bla-bla....' разбиваю на несколько строк. Так что не специально.

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

realsmart
()
Ответ на: комментарий от anonymous

> Рано еще тыкать, лисповерсии можно считать еще нет.

Будем считать, что теперь есть:

Параметр                        | Лисп 1 | Лисп 2| Питон | Окамл
----------------------------------------------------------------
Общая длина                     |   1158 |  1778 |  1462 |  1627
Смысловая длина                 |    331 |   552 |   604 |   603
Общий тезаурус                  |    160 |   210 |   195 |   164
Смысловой тезаурус              |     85 |   126 |   154 |   113
Общая насыщенность (в %)        |     29 |    31 |    41 |    37
Насыщенность тезауруса (в %)    |     53 |    60 |    79 |    69
Общая выразительность (в %)     |     14 |    12 |    13 |    10
Смысловая выразительность (в %) |     26 |    23 |    25 |    19

То есть, в конечном итоге получилось и в самом деле не ахти. Правда,
во-первых, тут еще не оптимизирован ввод-вывод (в том числе, не учтены
замечания yyk, попробую улучшить в следующей версии), во-вторых,
произошло серьезное "распухание" за счет многократного использования
дополнительного параметра "world" (IMHO, решается за счет классов), и
в-третьих, как я уже упомянул, у второй лисп-программы функционал
выше, чем у всех остальных. Многоуровневой трассировки, к сожалению не
получилось, но есть понятие подпрограмм, которые выполняются целиком,
а после каждой подпрограммы выводится состояние мира. Робот всегда
выводит состояние пошагово, а пользователь может регулировать
детальность вывода в программе. Наконец, делаем поправку на то, что я
новичок в Лиспе. Будем посмотреть, что предложат труъ лисперы.

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

Я обломился разъединять программу на три файла, так как у них много
общих частей. После загрузки всей программы сервер можно вызвать
командой (advserver "world.dat" 7766), клиент -- (hclient "localhost"
7766). Робот вызывается из человеческого клиента командой autoclean.

Мнэ, с исходником получается слишком много. Текст исходника смотрим здесь:

http://aroks.kiev.ua/pub/wiki/ProgrammaLabirinta

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

> Ну и, само собой, Евгений, ждём мега-ультра-анализ :)

Блин, я уже не успеваю. Мне ведь еще иногда жить и работать нужно.

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

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

И в-третьих, по мере реализации стойко всплывали воспоминания о "космическом лабиринте", в который мы играли еще в конце 80-х на олимпиадных сборах по математике. В начале 90-х пытались с товарищем сделать версию на Паскале под "Искру-1030" (тогдашние XT-шки), но быстро обломались. В том лабиринте клад только один, зато содержание карты неизвестно, его нужно нарисовать, а каждый шаг персонажа сопровождается целой серией активных действий со стороны лабиринта. В общем, было интересно, но в машинной реализации довольно таки сложно. Мы не смогли даже решить задачу валидации карт (т.е., доказательства того, что в заданном лабиринте задача вообще решается), а без этого случайная генерация карты просто бессмысленна.

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

> Вот несколько сокращённая версия read-world

Total length                                         1750
Meaning length                                        545
Total thesaurus                                       210
Meaning thesaurus                                     126
Total saturation (%)                                   31
Thesaurus saturation (%)                               60
Total expressiveness (%)                               12
Meaning expressiveness (%)                             23

То есть, это все мелочи. Нужно что-то более радикальное. Кстати, я
подозреваю, что переусердствовал с функциями в волновом алгоритме. Может
быть, некоторые из них можно подставить...

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

> Вот несколько сокращённая версия read-world

Евгений, в следующей версии анализа (если она будет :) прошу включить в таблицу и вторую питон-программу. Вам ведь не сложно один раз запустить свой анализатор? Я, можно сказать, начал учавствовать, чтобы посмотреть на эти циферки. А тут такой облом.

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

> Я, можно сказать, начал учавствовать, чтобы посмотреть на эти циферки. А тут такой облом.

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

Постараюсь сделать вечером, на крайний случай -- в субботу.

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

> Как-то оно там крововато выглядит... (кто-то чать буковок съел)

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

> Добавь туда файл с архивом

Добавил

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

Для программы realsmart (*) (24.10.2006 18:59:45)

Total length 1257 Meaning length 530 Total thesaurus 150 Meaning thesaurus 107 Total saturation (%) 42 Thesaurus saturation (%) 71 Total expressiveness (%) 12 Meaning expressiveness (%) 20

Очень даже неплохо, если она в самом деле делает то, что описано. Вопрос: она поддерживает уровни трассировки и сложные команды (подпрограммы)? Пока можно считать ее абсолютным лидером.

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

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

Total length                                         1257
Meaning length                                        530
Total thesaurus                                       150
Meaning thesaurus                                     107
Total saturation (%)                                   42
Thesaurus saturation (%)                               71
Total expressiveness (%)                               12
Meaning expressiveness (%)                             20

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

> Добавил

Ок, посмотрел. Есть несколько предложений, но пока "чисто косметических" - никаких изменений в алгоритме. В виде diff-ов :)

1. Об этом я уже писал
-(defun inside-interval-p (interval value)
-  (and
-       (>= value (car interval))
-       (<= value (cdr interval))))
-
-(defun inside-world-p (world point)
-  (and
-       (inside-interval-p (cons 1 (bound-x world)) (realpart point))
-       (inside-interval-p (cons 1 (bound-y world)) (imagpart point))))
-
 (defun wallp (world point)
-  (or
-       (not (inside-world-p world point))
-       (member point (wall-points world))))
+  (or (not (and (>= (realpart point) 1) (<= (realpart point) (bound-x world))
+               (>= (imagpart point) 1) (<= (imagpart point) (bound-y world))))
+      (member point (wall-points world))))

Не уверен, что в этой части что-то понадобится менять, поэтому просто
"свернул" пару функций :)

2. Раскрыть в объявлении констант pairlis - помимо экономии слова,
имхо, нагляднее

-(defconstant directions
-  (pairlis
-       `(#c(1 0) #c(-1 0) #c(0 -1) #c(0 1))
-       '(go-east go-west go-north go-south)))
+(defconstant +directions+ '((#c(0 1)  . go-south)
+                           (#c(0 -1) . go-north)
+                           (#c(-1 0) . go-west)
+                           (#c(1 0)  . go-east)))

и

-(defconstant command-reversion
-  (pairlis
-       '(go-east go-west go-north go-south pickup-thing drop-thing)
-       '(go-west go-east go-south go-north drop-thing pickup-thing)))
+(defconstant command-reversion '((go-east . go-west)
+                                (go-west . go-east)
+                                (go-north . go-south)
+                                (go-south . go-north)
+                                (pickup-thing . drop-thing)
+                                (drop-thing . pickup-thing))

3. Мелкие исправления

 (defun path-program (path)
-  (if (null (cdr path))
-        ()
-        (cons (direction (car path) (cadr path)) (path-program (cdr path)))))
+  (when (cdr path)
+    (cons (direction (car path) (cadr path)) (path-program (cdr path)))))

-  (cond
-       ((hero-carries-thing-p world)
-        (setf (hero-carries-thing-p world) nil)
-        (push (hero-point world) (thing-points world)))))
+  (when (hero-carries-thing-p world)
+    (setf (hero-carries-thing-p world) nil)
+    (push (hero-point world) (thing-points world))))

-  (progn
-        (format stream "~S~%" command)
-        (force-output stream)))
+  (format stream "~S~%" command)
+  (force-output stream))

4. Многострочные setf

-                       (setq entry-point (complex x y))
-                       (setq hero-point (complex x y))))
+                       (setf entry-point (complex x y)
+                             hero-point (complex x y))))

-        (setf (hero-carries-thing-p world) t)
-        (setf
-         (thing-points world)
-         (remove (hero-point world) (thing-points world) :count 1)))))
+        (setf (hero-carries-thing-p world) t
+              (thing-points world) (remove (hero-point world) (thing-points world) :count 1)))))

5. От одного eval можно легко избавиться (но это как раз увеличивает код)

-(mapcar
- #'eval
- (mapcar
-  #'(lambda (pair)
-               `(defun ,(cdr pair) (world) (go-step world ,(car pair))))
-  directions))
+
+(defmacro def-commands (directions)
+  `(progn
+     ,@(mapcar #'(lambda (pair)
+                  `(defun ,(cdr pair) (world) (go-step world ,(car pair))))
+              directions)))
+
+(def-commands #.+directions+)

Серьёзнее проанализирую потом.

yyk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.