Последние записи
- Windows 10 сменить администратора
- Рандомное слайдшоу
- Событие для произвольной области внутри TImage
- Удаление папки с файлами
- Распечатка файла
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
4th
Июл
Template CMS – маленькая и быстрая CMS
Разрешите представить сайтостроителям этого сообщества свою сиcтему управления сайтом Template CMS
Предназначение: сателлиты, домашние странички, мини сайты, сайты визитки.
Работа над CMS-кой еще ведется. Последняя рабочая версия 0.85
Template CMS 0.85 Основные возможности:
+ Простота установки, использования и обновления.
+ Удобный интерфейс администрирования.
+ Многоязычный интерфейс администрирования. (английский,русский,украинский +)
+ Минимальные требования к хостигу (без БД только PHP)
+ Ключевые слова и описание как для каждой страницы так и для всех.
+ Удобный редактор страниц (WYSIWYG – What You See Is What You Get ).
+ Создание бекапов сайта.
+ Смена тем оформления в один клик.
+ Легкость разработки и интеграции новых тем оформления.
+ Редактирование тем оформления прям из админки
+ Файловый менеджер с возможностью загрузки у правлением файлами на сервере.
+ Поддержка ЧПУ (с возможностью самому задавать расширения файлам .html . php etc…)
Сайт: http://templatecms.webdevart.ru/
Скриншоты: http://templatecms.webdevart.ru/galery
Сайты на этой CMS: http://templatecms.webdevart.ru/sites
Демо (0.85): http://templatecms.dtn.ru/admin.php
Пароль: demo
Ожидаемая обратная связь:
— Критика
— Предложения
— Слова поддержки
__________________
3rd
Июл
MASM и MASM32 – в чем различия?
Macro Assembler (MASM) — ассемблер для процессоров семейства x86. Создан компанией Microsoft для написания программ в операционной системы MS-DOS. Поддерживает разнообразие макросредств и структурированность программных идиом, включая конструкции высокого уровня для повторов, вызовов процедур и чередований. Продолжает развиваться и по сей день, последние версии включены в наборы DDK.
MASM32. Из интервью с создателем пакета MASM32 Стивеном Хатчессоном (Сидней, Австралия) – Как только с приходом Windows 95 стало необходимо создавать 32-х битные программы, я обнаружил, что инструментов для создания полезных и мощных программ сильно не хватает, и все большее распространение начали получать пакеты, облегчающие программирование для начинающих, но при этом, как правило, терялась большая часть возможностей, позволяющих писать выскокачественное программное обеспечение. Сначала я написал собственный редактор с помощью специализированного компилятора языка Бейсик, поскольку я был знаком с этим языком, и затем начал собирать информацию о создании ассемблерного пакета. Iczelion уже сделал кое-какую подготовительную работу, основываясь на том, что сделал ранее Стив Гибсон, и поскольку у меня был уже опыт в написании Windows-программ, я использовал некоторую часть из спроектированного Iczelion’ом, чтобы создать ранние версии MASM32. Главной идеей с самого начала было то, чтобы код на ассемблере было писать не труднее, чем на C, но чтобы он был более понятный и более мощный. Начиная с самых ранних версий MASM32, он разрабатывался при участии многих опытных программистов, которые хотели передать свой опыт следующему поколению программистов, и чтобы у них были подобающие инструменты, так же, как и у нас.
2nd
Июл
Игра Fortress 2. Создание лучшего бота – призовой фонд 5000 рублей!
Здравствуйте читатели нашего журнала. Сегодня мы хотим напомнить вам, что продолжается прием заявок на участие в конкурсе по созданию лучшего бота для игры в Fortress2 с денежным призом. Организатор конкурса – Форум программистов www.programmersforum.ru.
Игра Fortress 2. Создание лучшего бота – призовой фонд 5000 рублей!
Аблязов Руслан
by rpy3uH http://www.programmersforum.ru/member.php?u=11
* Комментарий автора
Для тех, кто не в курсе: бот представляет собой DLL с тремя экспортируемыми функциями. Документация по созданию бота находится в файле Fortress 2 Bot Specification
Скачать Fortress 2 build 2025 beta + Документация + исходник SimpleBot v1.0 http://programmersforum.ru/attachment.php?attachmentid=23688&d=1270876754
Скачать исходники SimpleBot v1.0 на С++ (CodeBlocks+MinGW) http://programmersforum.ru/attachment.php?attachmentid=23689&d=1270876964
Скачать документацию по созданию ботов http://pkonkurs.ru/wp-content/uploads/2010/06/Fortress-2-Bot-Specification.zip
Скачать исходник бота на С++ (CodeBlocks+MinGW) http://pkonkurs.ru/wp-content/uploads/2010/06/SimpleBotCpp.zip
Исходник бота на Delphi поставляется в комплекте с игрой.
Почему надо участвовать в этом конкурсе?
Во-первых, это интересно, вы можете поучаствовать в конкурсе, где не нужно загружать данные из текстового файла и сохранять их туда! Во-вторых, можно получить денежный приз, толстовку или футболку от клуба. В-третьих, вы получите опыт в создании ИИ для игры, и сможете сказать «Я разрабатывал бота для игры!»
Призы как денежные – 3000 рублей, так и сувениры от клуба на 2000 рублей. Конкурс расчитан на 2-4 месяца. Первая битва ботов состоится 15 июля 2010 года.
Ключевые понятия игры
Итак, вы хотите написать бота для этой игры, но не знаете как. Что пригодится для написания бота для игры:
1. Компилятор, который позволяет компилировать DLL файлы и разумеется знание языка этого компилятора
2. Знание правил игры
3. Знание, какие функции должны присутствовать в DLL, для того чтобы бот смог работать
С компилятором я думаю, проблем не будет он может быть любой, главное условие, чтобы он смог компилировать функции по соглашению stdcall. Сначала поясню как вообще происходит игра. играют двое, у каждого игрока есть база, есть три типа ресурсов, есть щит, есть проекты. Проекты бывают разные: атака вражеской базы, развитие своей базы, ремонт базы, шпионаж. Всего проектов 50. В начале игры игрок выбирает 15 проектов, которыми он будет играть. Потом игроки по очереди выбирают проекты, игрок может выбрать только тот проект, на который хватает ресурсов. Проигрывает то
т игрок, броня базы которого станет равной нулю.
Какова ее физика с точки зрения ботописателя? Читаем внимательно!
Мы выбираем двух ботов и нажимаем начать игру, ядро игры вызывает функции StartGame ботов участвующих в игре. Задача функции StartGame это выбор набора проектов, которыми будет играть бот, набор проектов надо сохранить в массиве, указатель на который будет передан функции StartGame. Проекты задаются числами (полный набор проектов указан в документации). После выбора проектов начинается игра. В ходе игры по очереди вызываются функции GetTurn каждого бота. В случае, если боту недоступен ни один проект, то функция GetTurn вызывается с нулевым указателем на массив доступных пр
оектов. В конце игры еще раз вызывается функция StartGame с нулевым указателем на массив проектов. Нулевой указатель на массив свидетельствует о том, что происходит уведомление бота о конце игры.
Количество ресурсов (энергия, металл, электроэлементы) зависит от количества объектов их добывающих (батареи, рудники, лаборатории). Количество батарей и рудников у врага можно уменьшить используя специальные шпионские-проекты. Внимание, нововведение в Fortress 2 : введено ограничение на количество лабораторий. По-умолчанию оно равно 5. Как только броня базы становится больше 50, к лимиту прибавляется одна лаборатория за каждые 5 единиц брони свыше 50. Например:
Base = 30, LabLimit = 5;
Base = 54, LabLimit = 5;
Base = 56, LabLimit = 6;
Base = 63, LabLimit = 7;
Base = 75, LabLimit = 8;
Base = 81, LabLimit = 9;
И т.д.
В случае использования проектов, которые увеличивают количество лабораторий и при этом уже достигнут лимит количества лабораторий, проект считается использованным (ресурсы расходуются), а количество лабораторий не изменяется.
Отличия от первой версии игры
1. Добавлены уведомления о пропуске хода и о конце игры и ее результатах
2. Бот может узнать имя противника (см. структуру TAdditionalGameInfo)
Возможности улучшения бота
Покажем, как можно изменить игру бота SimpleBot v1.1 в лучшую сторону, всего лишь добавив несколько строчек кода. Итак, приступим. Для разнообразия будем писать на C++. Что мы сделаем в первую очередь? Изменим набор проектов. Смотрим строку в коде, которая содержит список проектов [1, 2]:
const int Projects[MaxProjectsToPlayer] = {5, 6, 11, 13, 16, 18, 20, 28, 33, 34, 35, 44, 45, 46, 50};
Что тут можно изменить? В принципе можно тут изменить все, но заморачиваться мы не будем, просто удалим проект номер 50 и вставим (29) СуперАтака 2. En 16, Me 14, El 6 : Base-20, Shield-15. В итоге получаем такой список проектов:
const int Projects[MaxProjectsToPlayer] = {5, 6, 11, 13, 16, 18, 20, 28, 29, 33, 34, 35, 44, 45, 46};
Теперь смотрим функцию хода бота:
if (!aAvailProjects) return 0;
int OPP = GetOtherPlayer(aPlayerNumber);
if ((IsProjectAvail(20,aAvailProjects)) and
(aGame[aPlayerNumber].Base<25))
return 20;
if ((IsProjectAvail(18,aAvailProjects)) and
(aGame[aPlayerNumber].Base<20))
return 18;
if ((IsProjectAvail(16,aAvailProjects)) and
(aGame[aPlayerNumber].Shield<5))
return 16;
Первые две строки это проверка на уведомление о пропуске хода и получение индекса противника. Потом идет проверка доступности проектов 20, 18, 16:
(16) Ремонт 2. En 9, El 2 : SS+10
(18) Ремонт 4. Me 7, El 2 : SB+9
(20) Ремонт 6. Me 8, El 5 : SB+12
т.е. у бота приоритет : сначала проверить состояние базы, если состояние плохое выбираем ремонтный проект. изменять здесь ничего не будем. Смотрим далее. Далее идут при проверки и использование проектов увеличения количества батарей, рудников и лабораторий:
if (IsProjectAvail(34,aAvailProjects) and
(aGame[aPlayerNumber].Mines<3) and
(aGame[aPlayerNumber].Base>35) and
(aGame[aPlayerNumber].Shield>2))
return 34;
if (IsProjectAvail(33,aAvailProjects) and
(aGame[aPlayerNumber].Battery<4) and
(aGame[aPlayerNumber].Base>35) and
(aGame[aPlayerNumber].Shield>2))
return 33;
if (IsProjectAvail(35,aAvailProjects) and
(aGame[aPlayerNumber].Labs<3) and
(aGame[aPlayerNumber].Base>35) and
(aGame[aPlayerNumber].Shield>2))
return 35;
т.е. если состояние базы нормальное то можно увеличить количество батарей, рудников и лабораторий. Но как видно что количество батарей, рудников и лабораторий будет не больше 4,3,3 соответственно. Эти строчки мы менять не будем, добавим дополнительные строчки отвечающие за усиленное развитие базы
if (IsProjectAvail(34,aAvailProjects) and
(aGame[aPlayerNumber].Mines<6) and
(aGame[aPlayerNumber].Base>45) and
(aGame[aPlayerNumber].Shield>10))
return 34;
if (IsProjectAvail(33,aAvailProjects) and
(aGame[aPlayerNumber].Battery<7) and
(aGame[aPlayerNumber].Base>45) and
(aGame[aPlayerNumber].Shield>10))
return 33;
if (IsProjectAvail(35,aAvailProjects) and
(aGame[aPlayerNumber].Labs<5) and
(aGame[aPlayerNumber].Base>45) and
(aGame[aPlayerNumber].Shield>5))
return 35;
Теперь количество батарей, рудников и лабораторий будет увеличиваться до 7,6,5 соответственно. Развитие базы будет осуществляться только в том случае если состояние базы очень хорошее.
В набор проектов мы добавили проект номер 29, вопрос куда вставить его обработку чтобы не ухудшить игру бота. После проверок на развитие базы есть такие строки
if (IsProjectAvail(46,aAvailProjects)) return 46;
if (IsProjectAvail(28,aAvailProjects)) return 28;
в первую очередь обрабатывается наличие проекта номер 46 а потом 28. Вставим проверку проекта номер 29 между ними.
if (IsProjectAvail(46,aAvailProjects)) return 46;
if (IsProjectAvail(29,aAvailProjects)) return 29;
if (IsProjectAvail(28,aAvailProjects)) return 28;
Компилируем бота, запускаем игру, ставим 500 игр и смотрим результат (см. рисунок 1):
Результат очевиден, выигрыш в 84% игр. Но нет предела совершенству. Рассмотрим поведение бота… В начале, бот проверяет состояние базы и если оно плохое, то выбирает проект ремонта базы. Далее он проверяет условия начального развития базы (когда батарей, рудников и лабораторий совсем мало). Потом проверяет условия усиленного развития базы, и только потом атакующие проекты, и в самом конце если ни одно условие не выполнилось, то случайно выбирает проект.
Что можно изменить в первую очередь? Условия начального развития базы слишком жесткие: база должна быть не менее 35 единиц и щит должен быть не нулевой. Также слишком жесткие условия усиленного развития базы. Вот их нам и надо изменить. Вот что у меня получилось (в терминах Delphi):
if IsProjectAvail(BuildMineProject,aAvailProjects) and
(aGame[aPlayerNumber].Mines<3) and
(aGame[aPlayerNumber].Base>25) then
begin
Result:=BuildMineProject;
exit;
end;
if IsProjectAvail(BuildBatteryProject,aAvailProjects) and
(aGame[aPlayerNumber].Battery<4) and
(aGame[aPlayerNumber].Base>25) then
begin
Result:=BuildBatteryProject;
exit;
end;
if IsProjectAvail(BuildLabProject,aAvailProjects) and
(aGame[aPlayerNumber].Labs<3) and
(aGame[aPlayerNumber].Base>25) then
begin
Result:=BuildLabProject;
exit;
end;
if IsProjectAvail(BuildBatteryProject,aAvailProjects) and
(aGame[aPlayerNumber].Battery<7) and
(aGame[aPlayerNumber].Base>40) and
(aGame[aPlayerNumber].Shield>10) then
begin
Result:=BuildBatteryProject;
exit;
end;
if IsProjectAvail(BuildMineProject,aAvailProjects) and
(aGame[aPlayerNumber].Mines<6) and
(aGame[aPlayerNumber].Base>40) and
(aGame[aPlayerNumber].Shield>10) then
begin
Result:=BuildMineProject;
exit;
end;
if IsProjectAvail(BuildLabProject,aAvailProjects) and
(aGame[aPlayerNumber].Labs<5) and
(aGame[aPlayerNumber].Base>40) then
begin
Result:=BuildLabProject;
exit;
end;
Немного хотелось бы сказать про количество лабораторий. Их количество увеличивается только до 5, так как строительство больше пяти лабораторий требует дополнительного строительства базы. Вообще проекты спроектированы так, что на шпионские проекты надо много электроэллементов и если у вас мало электроэлементов вы не сможете использовать сильные шпионские проекты. Правильное развитие на лаборатории и использование шпионских проектов может стать решающим фактором в победе вашего бота.
Теперь посмотрим список проектов выбираемых ботом. Удалим 28 проект и добавим (31) СуперАтака 4. En 26, Me 16, El 10 : ->49 в итоге получаем такой список проектов:
const
STRATEGY:array[0..MaxProjectsToPLayer-1] of integer =
(
5, 6, 11, 13, 16, 18, 20, 28, 31, 33, 34, 35, 44, 45, 46
);
И вставим проверку использования 31 проекта перед всеми атакующими проектами, т.е. его наличие будет обрабатываться в первую очередь:
if IsProjectAvail(31,aAvailProjects) then
begin
Result:=31;
exit;
end;
if IsProjectAvail(46,aAvailProjects) then
begin
Result:=46;
exit;
end;
if IsProjectAvail(29,aAvailProjects) then
begin
Result:=29;
exit;
end;
Проверку наличия проектов 45 и 44 оставим без изменения, а вот в конце при случайном выборе проекта изменим число 15 на 8, таким образом, случайно будут выбираться только первые 8 проектов из списка доступных проектов, а именно проекты мелких атак и ремонта базы:
repeat
Result:=aAvailProjects^[random(8)];
until Result<>0;
Компилируем и смотрим результаты (см. рисунок 2):
Результат – выигрыш более 60% игр.
Ресурсы
. Скачать исходники SimpleBot v1.1. (C++) http://pkonkurs.ru/wp-content/uploads/2010/06/SimpleBotCpp_v11.zip
. Скачать Fortress 2 build 2026 + FortUI build 1004 http://pkonkurs.ru/wp-content/uploads/2010/06/Fortress-2-2026-+-FortUI-1004.zip
. Скачать Fortress 2 build 2026 beta + SimpleBot v1.2 http://pkonkurs.ru/wp-content/uploads/2010/06/Fortress-2-2026-+-FortUI-1004-+-SimpleBot-v1.2.zip
Статья из четвертого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
Под редакцией Сергея Бадло…
Обсудить на форуме — Игра Fortress 2. Создание лучшего бота – призовой фонд 5000 рублей!
2nd
Защита от спама в форумах phpBB2. САРТСНА
Все, так или иначе, сталкивались с капчей. САРТСНА (Completely Automated Public Turing test to tell Computers and Humans Apart) – полностью автоматизированный публичный тест Тьюринга для различения компьютеров и людей). Представляет собой компьютерный тест, используемый для того, чтобы определить, кем является пользователь системы: человеком или компьютером. В этой статье я хочу рассказать о двух методах защиты форума на базе движка phpBB2 от спамеров и их ботов…
Защита от спама в форумах phpBB2. САРТСНА
by Arigaro http://www.programmersforum.ru/member.php?u=19542
Технология САРТСНА была создана в 2000 году учеными из университета Карнеги-Меллона, и сегодня используется в Интернете практически повсеместно. Основная идея теста САРТСНА: предложить пользователю такую задачу, которую легко решает человек, но которую крайне трудно решить компьютеру. Как правило, это задачи на распознавание зрительных образов. Наиболее часто эта технология используется в различных Интернет-сервисах, в частности – хранилищах файловых архивов и форумах.
Уязвимости защиты САРТСНА
При недостаточной степени защиты скриптов спамбот может пройти тест САРТСНА и без распознавания картинок. В этом случае он либо подменяет идентификатор сессии, либо парсит информацию, содержащуюся на WEB странице и определяет то, что изображено на картинке. Если количество вариантов ответов невелико, спамбот может «угадать» ответ. Как правило, используется несколько параллельных потоков, благодаря чему скорость перебора зависит от полосы доступного канала. Кроме того, возможно и накопление базы вопросов и ответов, и рано или поздно вся она будет у него.
Существуют программы, распознающие конкретные реализации САРТСНА, к примеру PWNtcha. Да и никто не мешает спамеру подключать модули программ распознавания текста, тот же FineReader. Различают «сильную» (сильно размытая и не контрастная картинка) и «слабую» САРТСНА. Что же делать и как защититься от спамботов?
Методы защиты
Первое, что нужно сделать, чтобы прекратить автоматическую регистрацию ботов и массовый спам в темах – это закрыть возможность писать сообщение гостям, поставить картинку (капчу) на форму регистрации и установить активацию учетной записи по E-Mail. Рассмотрим подробнее…
1. Изменение картинки при регистрации на форумах phpBB2
В ходе эксплуатации форума быстро выясняется, что штатных методов для защиты не достаточно. Боты умеют регистрироваться, читать почту и, более того, спокойно распознают картинку, предоставляемую движком форума phpBB2. Если же изменить картинку на более сложную, то можно остановить подавляющее большинство автоматически регистрируемых ботов.
Для этого нужно проделать следующее. В папке <includes> форума изменить файл usercp_confirm.php:
. Удалить всю часть файла после строчки:
// output six seperate original pngs … first way is preferable!
или же строчки (в разных версия форума могут встречаться несколько отличные друг от друга комментарии)
// Thanks to DavidMJ for emulating zlib within the code
. и до конца файла. Вместо удаленной части вставить следующее:
// Изменение картинки в форме регистрации
// Автор мода: Arigato, 2006
list($usec, $sec) = explode(’ ‘, microtime());
mt_srand($sec * $usec);
$font = getcwd() . “/includes/font.ttf”;
$img = ImageCreate (320, 50);
$color = array();
$color[] = ImageColorAllocate ($img, 0, 0, 0);
$color[] = ImageColorAllocate ($img, 255, 0, 0);
$color[] = ImageColorAllocate ($img, 0, 255, 0);
$color[] = ImageColorAllocate ($img, 255, 255, 0);
$color[] = ImageColorAllocate ($img, 255, 0, 255);
$color[] = ImageColorAllocate ($img, 0, 255, 255);
$color[] = ImageColorAllocate ($img, 255, 255, 255);
$sx = ImageSX ($img) – 1;
$sy = ImageSY ($img) – 1;
$sc = count ($color) – 1;
// Фоновый шум:
for ($i = 0; $i < 1024; $i++)
{
$x = mt_rand (0, $sx);
$y = mt_rand (0, $sy);
$c = $color[mt_rand(1,$sc)];
ImageSetPixel ($img, $x, $y, $c);
}
// Вывод кода:
$xpos = mt_rand (8, 32);
$height = $sy – mt_rand (0, $sy / 4);
for ($i = 0; $i < strlen($code); $i++)
{
$angle = mt_rand (0, 30) – 15;
$size = mt_rand (0, + 32;
$ypos = $sy – mt_rand (8, $sy – $height – 8);
$c = $color[mt_rand(1,$sc)];
$rect = ImageTTFtext ($img, $size, $angle, $xpos, $ypos, $c, $font, $code[$i]);
$width = $rect[2] – $rect[0];
$height = $rect[1] – $rect[7];
$xpos += $width + mt_rand (4, 48);
}
// Передний шум:
for ($i = 0; $i < 256; $i++)
{
$x = mt_rand (0, $sx);
$y = mt_rand (0, $sy);
$c = $color[mt_rand(0,$sc)];
ImageSetPixel ($img, $x, $y, $c);
}
for ($i = 0; $i < mt_rand (2, 8); $i++)
{
$x1 = mt_rand (0, $sx);
$y1 = mt_rand (0, $sy);
$x2 = mt_rand (0, $sx);
$y2 = mt_rand (0, $sy);
$c = $color[mt_rand(0,$sc)];
ImageLine ($img, $x1, $y1, $x2, $y2, $c);
}
header (”Content-type: image/png”);
header (”Cache-control: no-cache, no-store”);
ImagePng ($img);
ImageDestroy ($img);
?>
Кроме этого нужно поместить в папку includes файл со шрифтом font.ttf, архив с которым можно скачать ниже. При желании можно использовать любой другой TrueType шрифт [1], содержащий латинские буквы и цифры. Как показал опыт применения данного метода на многих форумах, автоматическая регистрация ботов после такой модификации прекращается полностью (см. рисунок):
2. Разрешить отправлять личные сообщения только пользователям с 20 и более сообщениями
на форуме phpBB2 (защита от спама в личку). Да, сегодня уже и такой вид спама имеет место. Хотя он еще не получил большого распространения, о защите уже пора задуматься. Итак, что нужно делать…
Открыть файл privmsg.php и найти строчку:
if ( $mode == ‘newpm’ )
Добавить выше следующий код:
// НАЧАЛО: отправка личных сообщений только для пользователей с 20 сообщениями на форуме
// Автор мода: Arigato, 2007
if ( $mode == ‘post’ || $mode == ‘reply’ || $mode == ‘quote’ )
{
$mod_mes_count = 20;
if ( $userdata[‘user_posts’] < $mod_mes_count )
{
message_die(GENERAL_MESSAGE, “<b>$userdata[username]</b>, у Вас на форуме <b>$userdata[user_posts]</b> сообщений<br />
Отправлять личные сообщения Вы сможете, когда наберете <b>$mod_mes_count</b> или более сообщений на форуме”);
}
}
// КОНЕЦ: отправка личных сообщений только для пользователей с 20 сообщениями на форуме
Переменная $mod_mes_count определяет количество сообщений на форуме, после которого пользователю разрешается отправлять ЛС. Читать ЛС может любой пользователь. Предупреждение о запрете отправки ЛС выводится по-русски, многоязычность не поддерживается.
Заключение
Мы уже выяснили, как убрать основную уязвимость – фиксированный шрифт и фиксированное положение символов. Но, как всегда добавим «ложку дегтя». Дело в том, что сегодня получили распространение сервисы по типу CaptchaExchange Server. Эти сервисы направлены на «обход» картинок САРТСНА, путем ручного «человеческого» распознавания символов. Принцип работы основан на системе баллов, которые пользователь может заработать, распознавая в свободное время картинки для других пользователей. Набранные баллы пользователь может потратить позже, в любое удобное время, запустив программу автоматического скачивания файлов с файлообменного сервера или для регистраций. К сожалению и второй, рассмотренный нами, метод не дает 100% гарантию, но основная цель будет достигнута – это снижение нагрузки на сервис и относительное спокойствие пользователей.
Ресурсы
. Вариант шрифта для замены на форуме
http://www.programmersforum.ru/attachment.php?attachmentid=5029&d=1217234938
или http://programmersclub.ru/pro/pro4.zip
Статья из четвертого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
Обсудить на форуме — Защита от спама в форумах phpBB2. САРТСНА
2nd
Анимация в WEB на JavaScript
Здравствуйте! В этой статье я хотел бы рассказать о создании анимации на веб-страницах с использованием скриптового языка программирования JavaScript, далее JS. Статья ориентирована на новичков.
Анимация на WEB страницах
Алексей Шульга
by Levsha100 http://www.programmersforum.ru/member.php?u=19268
По правде говоря я не являюсь поклоником JS да и вэб-программирования тоже, но родина сказала «Надо!» Я немного отошел от темы нашего сайта, ибо работы над ним еще ведутся и это, видимо, будет еще долго. Поэтому было решено написать цикл статей по JS и различным интересным трюкам.
Шаблон
Для начала нам необходимо создать заготовку- то место, куда мы будем внедрять скрипты, Вот она:
<html>
<head>
<title>Тестовая страничка</title>
</head>
<body>
</body>
</html>
Это обыкновенная HTML-страничка, я сохранил ее под именем Test.html .
Встраивание JS-скрипта
Итак, шаблон у нас есть, и теперь мы можем смело пробовать оживлять страничку с помощью скриптов, добавить JS-скрипт можно двумя основными способами- добавлением его непосредственно в веб-страницу, либо вынести его в отдельный файл, для наглядности я выбрал первый способ. Добавим скрипт в секцию body, после чего она примет вид:
<body>
<script>
//Тут находится JS-код
</script>
</body>
Для проверки можно заменить за комментированную строку такой строкой:
alert(”Hello, world” );
Этот код выведет [модальное] окно с текстом “Hello, world”.
Добавление объектов
Прежде чем мы займемся анимацией нужно что бы было то, что будет анимироваться, поэтому займемся созданием анимируемых объектов- для примера возьмем квадратные DIV-вы со стороной 10 пикселей. Прежде чем создавать собственно объекты для них необходимо задать стиль, это делается с помощью CSS. Пример:
<head>
<title>Тестовая страничка</title>
<style type=”text/css”>
.obj1style{position:absolute; width:10; height:10; background-color: #00FF00}
</style>
</head>
Наиболее важным свойством является свойство position и именно его значение absolute -оно позволяет размещать объект, к которому применен данный стиль, в любой точке веб-страницы. Свойства width и height, как нетрудно догадаться, отвечают за высоты и ширину объекта соответственно. Цвет фона объекта- зеленый.
Теперь займемся собственно добавлением объектов, для этого необходимо заменить строку:
//Тут находится JS-код
на строки:
var obj_count=10; //Сколько у нас будет объектов
for (i=1;i<=obj_count;i++){ //Цикл от 1 до количества создаваемых объектов
document.write(’<div style=”left:’);
document.write(i*20+50);
document.write(’;top:50;”MsoBodyTextIndent” style=”margin-right: -2.75pt; text-indent: 0cm;”>
document.write(i);
document.write(’”>’+'</div>’);
//вот то самое место, именно тут мы вписываем в страницу 10 DIV-ов с классом obj1style идентификаторами с именами от obj1-1 до obj1-10. Все элементы располагаются на одной высоте, отступ от левой стороны страницы высчитывается по формуле i * 20 +50, где i-это номер элемента[1..10].
}
Вместо данного кода мы могли бы написать что-то вроде:
<div style=”left:70; top:50;” id=”obj1-1″></div>
…
<div style=”left:250; top:50;” id=”obj1-10″></div>
Но это неэффективно и некрасиво да и лень мне писать так много.
I like to move it или анимируем!
Самое интересное. Итак, для начала зададимся целью, что необходимо сделать. Я решил начать с простого – объекты будут летать в неком сосуде и при ударении об стенку они будут отскакивать
* Комментарий автора
кстати данную модель можно было бы назвать “Модель идеального газа”, ибо данная анимация действительно в некой степени моделирует поведение частиц идеального газа.
Для начала после строки:
var obj_count=10;
добавим следующий код:
var VX= new Array(obj_count);
var VY= new Array(obj_count);
document.write(’<div style=”position:absolute; left:45; top:40; width:300; height:300; background:#bbbbbb;” id=”Area”></div>’);
Первые две строки создают два массива длиной 10 элементов, которые хранят значение скорости для каждого объекта. Третья же строка размещает на страничке “сосуд”, в котором будут летать наши “молекулы”, тут, в принципе, я думаю все знакомо и просто. Далее после строк начальной инициализации:
document.write(’;top:50;” id=”obj1-’);
document.write(i);
document.write(’”>’+'</div>’);
добавляем код, который будет задавать случайную скорость для каждого объекта
VX=Math.round(Math.random()*6)-3; if(VX==0){VX=1;}
VY=Math.round(Math.random()*6)-3; if(VY==0){VY=1;}
Условия “if” нужны для того что бы не было нулевых скоростей, то есть что бы небыло неподвижных объектов. Теперь перейдем к самому сердцу нашего аниматора- функции Timer она периодически ( с интервалом 50мс вызывает функцию Animate, но о ней позже.
Функция выглядит так:
function Timer()
{
setTimeout( function(){Animate();setTimeout(arguments.callee, 50);}, 0);
}
Эта функция должна вызываться(стартовать) при загрузке страницы для того что бы обеспечить такую возможность мы подправим тег body, итоговый вид после изменений показан ниже:
<body onload=”Timer()”>
Вроде разобрались, пора браться за последнюю в данном уроке и самую массивную функцию – функцию Animate, вот полный ее текст:
function Animate()
{
for(i=1;i<=obj_count;i++){
document.getElementById(”obj1-”+i).style.left=parseInt(document.getElementById(”obj1-”+i).style.left)+VX;
document.getElementById(”obj1-”+i).style.top=parseInt(document.getElementById(”obj1-”+i).style.top)+VY;
if( parseInt(document.getElementById(”obj1-”+i).style.left) <= parseInt(document.getElementById(”Area”).style.left) ){
document.getElementById(”obj1-”+i).style.left=document.getElementById(”Area”).style.left;
VX*=-1;
}
if( parseInt(document.getElementById(”obj1-”+i).style.left)+10 >= parseInt(document.getElementById(”Area”).style.left)+parseInt(document.getElementById(”Area”).style.width) ){
document.getElementById(”obj1-”+i).style.left=parseInt(document.getElementById(”Area”).style.left)+parseInt(document.getElementById(”Area”).style.width)-10;
VX*=-1;
}
if( parseInt(document.getElementById(”obj1-”+i).style.top) <= parseInt(document.getElementById(”Area”).style.top) ){
document.getElementById(”obj1-”+i).style.top=document.getElementById(”Area”).style.top;
VY*=-1;
}
if( parseInt(document.getElementById(”obj1-”+i).style.top)+10 >= parseInt(document.getElementById(”Area”).style.top)+parseInt(document.getElementById(”Area”).style.height) ){
document.getElementById(”obj1-”+i).style.top=parseInt(document.getElementById(”Area”).style.top)+parseInt(document.getElementById(”Area”).style.height)-10;
VY*=-1;
}
}
}
Как она работает? Очень просто! В цикле мы пробегаем по всем элементам, при этом выполняем следующие действия:
1. Прибавляем к X координате объекта его горизонтальную скорость, которую берем из массива VX.
2. Прибавляем к Y координате объекта его вертикальную скорость, которую берем из массива VY.
3. Проверяем, не вышел ли левый край объекта за левый край сосуда, если вышел, то ставим объект на границу и инвертируем скорость. Т.е. если летел, к примеру, шарик и он вылетел за левую границу, то мы возвращаем шар на край сосуда и пинаем его в обратную сторону, так, что модуль его горизонтальной скорости не меняться- меняется только знак
4. Аналогично, только мы проверяем вылет за правую границу.
5. В принципе тоже самое, только здесь все происходить в вертикальной плоскости- мы определяем вылет за верхнюю границу и если таковой факт был инвертируем вертикальную составляющую скорости.
6. Аналогично действию №5, за исключением того, что проверка происходит на вылет за нижнюю грань.
Смело копируем функцию перед функцией Timer() и пробуем запустить нашу маленькую демонстрацию (см. рисунок).
Заключение
В этой статье я попытался объяснить базовые принципы анимации с помощью JavaScript. Если Вам что-то непонятно, то не расстраивайтесь в следующих уроках курса я на более интересных и практичных примерах покажу как делать практичные вещи, которые будет не стыдно поставить на свой сайт а пока экспериментируйте! Также хотелось бы написать статью о оптимизации кода, ибо наш вариант далеко не идеален, поэтому ждите.
Если возникнут какие-либо вопросы то обращайтесь на форум www.programmersforum.ru, либо пишите на почтовый ящик редакции. Я или кто-либо другой попытаемся Вам помочь.
Статья из четвертого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.
2nd
Рассылка. Выпуск 65.
От ведущего рассылки.
Добрый день. Сегодня почти юбилейный 65 выпуск рассылки клуба программистов. Основную часть материала сегодня составляют заметки журнала “ПРОграммист” с рубрики “интересно, но факт”. Так же отдельно хочу выделить статью о диалекте Лиспа – Sсheme. Ну, и как обычно, немного юмора.
1st
Июл
Введение в Sсheme. Часть 1
Краткое описание функционального языка программирования Sсheme. Рассчитано на программистов, имеющих навыки программирования в императивном стиле.
by Utkin
В 1970 году Гай Стил (Guy L. Steele) и Джеральд Сассман (Gerald Jay Sussman) из Массачусетского технологического института начали работу на новым языком программирования. Тогда Джеральд Сассман уже имел ученую степень, а его помощник Гай Стил являлся студентом данного института. В 1975 году работы были закончены и получили свое дальнейшее воплощение в принципах работы СБИС (в 1978 году) и CAD-системах. Идеи, положенные в эти работы, позже использовались для конструирования элементов космических аппаратов и проведения экспериментов в космосе (с использованием элементов искусственного интеллекта). В 1984 году большое количество версий в разных институтах заставило разработчиков выработать единый стандарт (при участии Массачусетского технологического института и университета Индианы). Такие серьезные сферы дали хороший старт языку, однако его распространение сдерживалось низкой скоростью интерпретации. В 90-х годах прошлого века были разработаны новые технологии компиляции, что позволило повысить эффективность Scheme путем компиляции в байт-код и машинные коды (хотя экспериментальные компиляторы со Scheme существовали и ранее). На данный момент производительность Scheme в целом выше, чем у Java (учитывая, что языки разных стилей, то такое сравнение условно).
Scheme («скиим»)
это функциональный язык программирования, диалект Лиспа. Особенности: разумный минимализм, интерактивность, однородность синтаксиса (лисповые списки), высокий уровень абстрагирования, возможность писать программы оторванные от конкретной платформы, «строгий» язык (требует придерживаться определенного стиля), позволяет использовать разные парадигмы программирования и много чего еще особенного.
В дальнейшем будем рассматривать язык на примере PLT Scheme. Данная среда выбрана не случайно (имеются десятки других). Она бесплатна, имеет широкое распространение, большой набор библиотек и позволяет компилировать программы в exe-файлы. Взять можно отсюда: http://www.plt-scheme.org/ IDE в PLT Scheme называется DrScheme, имеет минималистический вид, однако содержит практически все, что необходимо для работы программиста. Редактор имеет два окна – первое для записи программы, второе информационное и окно интерактивного режима – команды языка, введенные в него, исполняются немедленно.
Также в комплекте имеется MrEd – система для создания переносимого графического интерфейса пользователя. Далее будет следовать краткое описание языка, настолько, насколько это возможно в рамках статьи. Все примеры, приведенные ниже можно сразу опробовать в окне интерактивного режима.
Синтаксические элементы и что еще обязательно нужно знать
Прежде чем, начать описание синтаксических элементов следует обратить внимание на некоторые вещи. Все вычисления, в процедурах, аргументах всегда осуществляются слева направо. Язык имеет поддержку типов, однако, типизация скрытая (динамический контроль типов). Объекты (включая процедуры – сама программа также может являться объектом данных) имеют неразрушаемую природу, однако переполнение памяти не возникает за счет того, что объекты могут быть перезаписаны, в случае, если больше не будут участвовать в вычислительном процессе. На данный момент все реализации Scheme используют хвостовую рекурсию, это позволяет выделять на выполнение рекурсионных вызовов ограниченный размер памяти. Такие вызовы позволяют не использовать специализированные операции цикла (могут быть получены за счет автоматического преобразования хвостовой рекурсии в итерации). Все функции являются самостоятельными объектами (могут создаваться динамически, сохранены в структурах данных, возвращены как результаты функций и т.д.). Примером таких языков являются Common Lisp и ML. Параметры процедур всегда передаются по значению (в противовес Haskell, который позволяет откладывать вычисление параметра, до тех пор, пока он не потребуется явно).
Модель арифметических вычислений создана таким образом, чтобы максимально не зависеть от конкретных аппаратных платформ. В Scheme каждое целое число является рациональным, каждое рациональное число является реальным, а каждое реальное к тому же является еще и комплексным. Поэтому разница между различными типами чисел, возведенная в ранг абсолютизма в императивных языках, здесь не проявляется.
Программа является списком, элементы списка отделяются друг от друга пробелом, сам список заключен в скобки. Операции представляется списком, в котором символ операции (который, в сущности, является именем функции) всегда занимает первое место в списке (префиксная форма или польская нотация):
Пример.
(+ 2 2) Результатом будет 4.
(+ 2 (* 2 2)) Результатом будет 6.
Особенностью такой записи является тот факт, что операция может быть применена к неограниченному количеству входящих параметров, можно написать и (+ 2 2 2 2 2 2 2 2 2 2 2) (сравните 2 + 2). Это приводит к тому, что программы, написанные на Scheme, могут являться данными для других программ написанных на Scheme. Для функциональных языков программирования является традицией писать интерпретаторы/компиляторы с них на этих же языках программирования.
PLT Scheme не делает разницы между идентификаторами, набранными в разных регистрах. В тоже время правила образования идентификаторов может различаться для разных версий и реализаций языка, однако есть общее требование – идентификатор не должен начинаться с цифры. Примеры идентификаторов:
lambda
q
list->vector
soup
+
V17a
<=?
a34kTMNs
the-word-recursion-has-many-meanings
Для идентификаторов разрешено использовать символы. Можно использовать, например, такой идентификатор ——>, однако по соглашению фрагмент -> делит идентификатор на две части и говорит о преобразовании типа, например list->vector для функции может трактоваться как преобразование списка в вектор (элементы которого являются элементами списка). Помимо пробелов и переходов на новую строку допускается также использовать символы табуляции, все эти элементы обычно используются для улучшения восприятия текста программы и в качестве разделителей лексем языка.
Одним из важных понятий языка является понятие представления объектов. Если в программе, это всего лишь поток символов, то внутренне объект может представляться совершенно иным способом. Далее, представление объектов не обязательно уникально, так число 28 может быть представлено как #e28.000 или #x1c. Список (1 2) можно представить как (01 02) или (1. (2. ())) Здесь () является пустым списком. Однако, список (+ 1 2) не является эквивалентом числа 3, это список, состоящий из трех элементов (результат вычисления которого является числом 3). С одной стороны, это может путать на начальном этапе знакомства с языком, но с другой это источник его мощи, данные могут являться программой, программа может являться данными.
Переменные перед использованием должны быть объявлены: (define x 28) В данном случае мы определяем переменную х со значением 28. В Дальнейшем допускается неоднократное переопределение (например, (define x 38)).
Точка с запятой (;) служит для обозначения комментария, который продолжается до конца строки и является неисполняемым оператором языка. Поэтому комментарии посреди лексемы языка не допускаются.
Небольшой пример:
;;; процедура FACT вычисляет факториал
;;; из неотрицательного целого числа.
(define fact
(lambda (n)
(if (= n 0)
1 ;Base case: return 1
(* n (fact (- n 1))))))
Вызов факториала (fact 100) даст результат:
933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272
23758251185210916864000000000000000000000000
Это говорит о том, что строгий диапазон для чисел не установлен и ограничен только объемом памяти и Вашим временем (кстати, считает за вполне приемлемое время), на операции над ними (справедливо для целых чисел).
Существует соглашение, по которому предикаты (элементы, возвращающие значения Истина/Ложь) должны именоваться с вопросительным знаком на конце.
Ну и еще что нужно знать об основных синтаксических элементах: *. + — могут использоваться в идентификаторах (например, предыдущем примере мы могли бы обозначить идентификатор функции как fact+ или fact+1).
Одинарная кавычка (‘) используется для абсолютного значения, которое вычислять не требуется (допускается второе обозначение данной функции — quote). Например, имеется элемент списка (х) и имеется функция с аналогичным именем, чтобы в списке х не вычислялся, используется данная функция.
Чтобы было понятней, объявим такую функцию:
(define (prostoX x) ( quote x))
Вызовем ее
(prostoX 100) Результат будет х, а не 100
(quote a) Результат a
(quote #(a b c)) Результат #(a b c)
(quote (+ 1 2)) Результат (+ 1 2), а не 3
'(quote a) Результат (quote a)
Можно заставить Scheme вычислять частично, для этого используется запятая:
`(list ,(+ 1 2) 4) Результат (list 3 4), то есть выражение перед запятой (+1 2) было вычислено.
Более сложный пример
(let ((name 'a)) `(list ,name ',name)) Результат (list a (quote a))
Числовые, символьные, строковые и булевые константы «квотировать» не допускается.
Символ двойной кавычки (”) используется для ограничения строковых констант.
Символ обратного слеша (\) используется в строковых константах.
[ ] { } | Левые и правые квадратные скобки, изогнутые скобки и вертикальный штрих зарезервированы для возможных будущих расширений языка.
Символ шарп (#) используется для множества целей в зависимости от символа, который немедленно следует за этим:
- #t #f — обозначение булевых констант;
- # \ — вводит символьную константу;
- #( — вводит векторную константу;
- #e #i #b #o #d #x — используются для обозначения чисел.
Объявление процедур:
(lambda <formals> <body>)
<Formals> — список формальных параметров
<Body> — последовательность из одного или более выражений.
Лямбда-выражение считается процедурой, не имеющей имени. Результат(ы) последнего выражения в теле будет возвращен как результат(ы) вызова процедуры.
(lambda (x) (+ x x)) Есть описание процедуры без имени, имеющий один входящий параметр и возвращающий удвоенное значение переменной х.
((lambda (x) (+ x x)) 4) Результат 8 (последнее выражение, передано в процедуру)
Определим такую функцию
(define reverse-subtract
(lambda (x y) (- y x)))
Ее вызов с параметрами (reverse-subtract 7 10) Результат результат 3 (для последнего выражения происходит обмен параметров в списке). Таким образом, сначала определяется безымянная процедура с двумя входящими параметрами х и y. Ее задача вычитать из y x. Далее, ей просто присваивается имя reverse-subtract, которую мы и вызвали с параметрами 7 и 10. х получает значение 7, у соответственно 10, затем мы вычитаем из y x тело (- у х), то есть (- 10 7). Результатом будет 3.
Определим следующую функцию:
(define add4
(let ((x 4))
(lambda (y) (+ x y))))
Ее вызов с параметрами (add4 6) Результат 10. Обратите внимание – внутри функции определяется локальная переменная х, имеющая значение 4. Данная переменная существует только в рамках add4.
Lambda удобно использовать для образования хвостовой рекурсии – один из важнейших элементов функционального программирования. Для императивного программирования хвостовую рекурсию можно выразить через цикл. Также lambda в связке с define можно рассматривать как аналог механизма интерфейсов ООП.
Допускается и короткая форма функций, без использования процедур lambda: (define (имя параметры) (тело_функции)). Определим функцию возведения в квадрат: (define (square x) (* x x)). Вызовем ее (square 10), в результате получим 100. Вызовем ее еще раз (Square 10.5), в результате получим 110.25. Код может следовать сразу друг за другом без всяких приведений типов и никаких фокусов с параметризацией здесь не требуется совершенно. Хотелось бы на этом заострить внимание: то, что в последнее время привносится как новая веха ООП – параметризация, существует в функциональном программировании чуть ли не с момента его возникновения. Однако в функциональном программировании оно представлено на совершенно ином уровне.
Еще один момент, касающийся идентификаторов – в PLT Scheme все идентификаторы могут содержать дополнительные символы. Это значит, что вместо square можно смело определить функцию КВАДРАТ, и вообще можно переписать практически все ключевые элементы языка, используя национальный алфавит.
Условные выражения представляются в следующих формах:
(if <тест> <следствие> <альтернативный_вариант>)
Здесь все просто и аналогично другим языкам программирования:
(if (> 3 2) 'да 'нет) Результат да (обратите внимание на одинарные кавычки)
(if (> 2 3) 'да 'нет) Результат нет
(if (> 3 2)
(-3 2)
(+ 3 2)) Результат 1 (3 больше 2? Если да, то выполним (- 3 2), то есть получим в итоге 1).
Можно использовать также cond:
(cond ((> 3 2) 'больше)
((<3 2) 'меньше)) Результат больше
(cond ((> 3 3) 'больше)
((<3 3) 'меньше)
(else 'равно)) Результат равно
Общая форма: (cond выражение1 выражение2 … выражениеN), где выражение состоит из ((условие) (действие)). Ветвь else будет выполнена в случае, если ни одно из предыдущих условий не было выполнено. Cond аналогична множественному использованию if (изначально конструкции if не было, и все условия обсчитывали через cond). В качестве задания: попробуйте выразить if через использование cond.
Давайте рассмотрим такой фрагмент программы:
(define (PAIR (a b)
(lambda (msg)
(case msg ; конструкция case для каждого значения msg
; выполняет соответствующее действие
((first) a) ; если сообщение – символ first, возвратить a
((second) b))))
В зависимости от msg будет возвращено соответствующее значение, то есть фактически полностью соответствует case из императивных языков (таких как С++ или Дельфи). Case аналогично cond поддерживает else – ветвь которая будет обязательно выполнена в случае, если ни одна из предыдущих выполнена не была.
Можно составлять сложные условия за счет грамотного использования and и or:
(and (= 2 2) (> 2 1)) Результат #t (истина). 2=2 и 2>1? Истина
(and (= 2 2) (< 2 1)) Результат #f (ложь). 2=2 и 2<1? Ложь
(and 1 2 'c '(f g)) Результат (f g) (список не вычисляется из-за одинарных кавычек)
(and) Результат #t
(and (< 2 2) (= 2 2)) Результат #f
Выражения оцениваются слева направо до первого ложного утверждения. Если все утверждения верны, то возвращается последний входящий параметр функции (у нас это пример со списком (f g)). Если and не имеет входящих утверждений, будет возращено #t (истина).
(or (= 2 2) (> 2 1)) Результат #t
(or (= 2 2) (< 2 1)) Результат #t
(or #f #f #f) Результат #f
Выражения оцениваются слева направо до первого истинного утверждения (оставшиеся не рассматриваются). Если все выражения ложны, будет возвращено последнее из них. Теперь немного о присваивании переменных. Вообще-то, в чистом функциональном программировании переменных вообще существовать не должно, но подавляющее большинство функциональных языков программирования признают пользу существования переменных и вводят различные механизмы для их использования. Присваивание в PLT Scheme осуществляется таким образом:
(define x 2)
(set! x 4)
(+ x 1)
Результат 5. Ничто нам не мешает переопределить переменную x через define, но все же необходимо помнить, что define не эквивалентно set! (хотя в нашем случае и приводит к одному результату). Разница заключается в том, что define связывает идентификатор переменной с ее новым значением (предыдущее значение переменной будет уничтожено в результате сборки мусора), а set! присваивает значение уже существующей. Вообще, следует учитывать, что имя переменной и ее значения связаны не напрямую между собой. В частности, это проявляется в том, что переменная может существовать по имени, без значения (проявляется, например, при операции quote). При этом нет точных рамок между именем переменной и именем функции. И через define имя переменной можно переопределить как имя функции.
Теперь рассмотрим более подробно конструкцию let. Собственно у нее ее два родственника let* и letrec с тем же синтаксисом (let ((определение_переменной1) (определение_переменнойN)) (тело)). Разница в них только в уровнях видимости связанных ими переменных. Это позволяет строить блочные структуры на манер принятый в структурном программировании. Короткая форма такова: (let (определение переменной) выражение), где определение переменной выглядит все в том же списочном стиле (переменная значение).
(lambda <formals> <body>)
<Formals> — список формальных параметров
<Body> — последовательность из одного или более выражений.
Лямбда-выражение считается процедурой, не имеющей имени. Результат(ы) последнего выражения в теле будет возвращен как результат(ы) вызова процедуры.
(lambda (x) (+ x x)) Есть описание процедуры без имени, имеющий один входящий параметр и возвращающий удвоенное значение переменной х.
((lambda (x) (+ x x)) 4) Результат 8 (последнее выражение, передано в процедуру)
Определим такую функцию
(define reverse-subtract
(lambda (x y) (- y x)))
Ее вызов с параметрами (reverse-subtract 7 10) Результат результат 3 (для последнего выражения происходит обмен параметров в списке). Таким образом, сначала определяется безымянная процедура с двумя входящими параметрами х и y. Ее задача вычитать из y x. Далее, ей просто присваивается имя reverse-subtract, которую мы и вызвали с параметрами 7 и 10. х получает значение 7, у соответственно 10, затем мы вычитаем из y x тело (- у х), то есть (- 10 7). Результатом будет 3.
Определим следующую функцию:
(define add4
(let ((x 4))
(lambda (y) (+ x y))))
Ее вызов с параметрами (add4 6) Результат 10. Обратите внимание – внутри функции определяется локальная переменная х, имеющая значение 4. Данная переменная существует только в рамках add4.
Lambda удобно использовать для образования хвостовой рекурсии – один из важнейших элементов функционального программирования. Для императивного программирования хвостовую рекурсию можно выразить через цикл. Также lambda в связке с define можно рассматривать как аналог механизма интерфейсов ООП.
Допускается и короткая форма функций, без использования процедур lambda: (define (имя параметры) (тело_функции)). Определим функцию возведения в квадрат: (define (square x) (* x x)). Вызовем ее (square 10), в результате получим 100. Вызовем ее еще раз (Square 10.5), в результате получим 110.25. Код может следовать сразу друг за другом без всяких приведений типов и никаких фокусов с параметризацией здесь не требуется совершенно. Хотелось бы на этом заострить внимание: то, что в последнее время привносится как новая веха ООП – параметризация, существует в функциональном программировании чуть ли не с момента его возникновения. Однако в функциональном программировании оно представлено на совершенно ином уровне.
Еще один момент, касающийся идентификаторов – в PLT Scheme все идентификаторы могут содержать дополнительные символы. Это значит, что вместо square можно смело определить функцию КВАДРАТ, и вообще можно переписать практически все ключевые элементы языка, используя национальный алфавит.
Условные выражения представляются в следующих формах:
(if <тест> <следствие> <альтернативный_вариант>)
Здесь все просто и аналогично другим языкам программирования:
(if (> 3 2) 'да 'нет) Результат да (обратите внимание на одинарные кавычки)
(if (> 2 3) 'да 'нет) Результат нет
(if (> 3 2)
(-3 2)
(+ 3 2)) Результат 1 (3 больше 2? Если да, то выполним (- 3 2), то есть получим в итоге 1).
Можно использовать также cond:
(cond ((> 3 2) 'больше)
((<3 2) 'меньше)) Результат больше
(cond ((> 3 3) 'больше)
((<3 3) 'меньше)
(else 'равно)) Результат равно
Общая форма: (cond выражение1 выражение2 … выражениеN), где выражение состоит из ((условие) (действие)). Ветвь else будет выполнена в случае, если ни одно из предыдущих условий не было выполнено. Cond аналогична множественному использованию if (изначально конструкции if не было, и все условия обсчитывали через cond). В качестве задания: попробуйте выразить if через использование cond.
Давайте рассмотрим такой фрагмент программы:
(define (PAIR (a b)
(lambda (msg)
(case msg ; конструкция case для каждого значения msg
; выполняет соответствующее действие
((first) a) ; если сообщение – символ first, возвратить a
((second) b))))
В зависимости от msg будет возвращено соответствующее значение, то есть фактически полностью соответствует case из императивных языков (таких как С++ или Дельфи). Case аналогично cond поддерживает else – ветвь которая будет обязательно выполнена в случае, если ни одна из предыдущих выполнена не была.
Можно составлять сложные условия за счет грамотного использования and и or:
(and (= 2 2) (> 2 1)) Результат #t (истина). 2=2 и 2>1? Истина
(and (= 2 2) (< 2 1)) Результат #f (ложь). 2=2 и 2<1? Ложь
(and 1 2 'c '(f g)) Результат (f g) (список не вычисляется из-за одинарных кавычек)
(and) Результат #t
(and (< 2 2) (= 2 2)) Результат #f
Выражения оцениваются слева направо до первого ложного утверждения. Если все утверждения верны, то возвращается последний входящий параметр функции (у нас это пример со списком (f g)). Если and не имеет входящих утверждений, будет возращено #t (истина).
(or (= 2 2) (> 2 1)) Результат #t
(or (= 2 2) (< 2 1)) Результат #t
(or #f #f #f) Результат #f
Выражения оцениваются слева направо до первого истинного утверждения (оставшиеся не рассматриваются). Если все выражения ложны, будет возвращено последнее из них. Теперь немного о присваивании переменных. Вообще-то, в чистом функциональном программировании переменных вообще существовать не должно, но подавляющее большинство функциональных языков программирования признают пользу существования переменных и вводят различные механизмы для их использования. Присваивание в PLT Scheme осуществляется таким образом:
(define x 2)
(set! x 4)
(+ x 1)[/c
(let ((x 2)) (* x 2)) Результат 4. Создаем переменную х=2, умножаем на 2 и передаем значение. Сам х при выходе из данного выражения будет разрушен. Let позволяет создавать сколько угодно переменных, действие которых будет распространяться исключительно на тело определения (при этом в рамках одного определения не допускается использовать несколько переменных с одинаковыми идентификаторами).
(let ((x 2) (y 3))
(* x y)) Результат 6
(let ((x 2) (y 3))
(let ((x 7)
(z (+ x y)))
(* z x)))
Результат 35. В первом блоке определим х=2, у=3, переходим к исполнению тела let. Создадим второй х со значением 7, затем определяем еще одну переменную второго блока z, которая будет равна x+y (число 5) первого блока (поскольку х второго блока имеет силу только в теле второго блока, но не на этапе определения переменных этого же блока). Приступаем к исполнению тела второго блока – умножаем 5 (в данном случае, переменная z) на 7 (переменная х второго блока). Результат 35.
Как видно из примера, допускается неограниченная глубина вложенности let, внутри каждого определения допускается свободное повторение идентификаторов по отношению к другим let. В Scheme let часто используется как аналог программных скобок ({-}, begin-end) императивных языков программирования. Как правило, let используется чаще родственных ей let* и letrec.
Рассмотрим пример с let*
(let ((x 2) (y 3))
(let* ((x 7)
(z (+ x y)))
(* z x)))
Результат 70. В первом блоке определим х=2 и у=3. Далее конструкция let* определяет переменную х=7, действие которой распространяется на все определения переменных справа и на тело let*, таким образом, z=7 (новый х)+3 (у из первого блока)=10. Приступаем к выполнению тела let* - z (число 10) умножаем на х блока let* (число 7). Результат 70.
Что касается letrec, ее особенность в том, что переменная получает свое значение не мгновенно, а в момент, когда она будет необходима (соответственно в теле переменная может получать разные значения в зависимости от того выражения, каким она должна инициализироваться). Это удобно в случае многочисленных рекурсионных вызовов.
(letrec ((even?
(lambda (n)
(if (zero? n)
#t
(odd? (- n 1)))))
(odd?
(lambda (n)
(if (zero? n)
#f
(even? (- n 1))))))
(even? 88))
Данный пример определяет четность числа (#t, если четное). Как видно из примера, even? может вычисляться в зависимости от входящего числа через рекурсию. Еще один момент – если Вы заметили, то even? это должна быть переменная или функция, имеющая булевый тип, а 88 есть число (в рамках Scheme – не важно какое, считайте, что все числа есть комплексные величины). Здесь видна работа letrec, для тела вычисляется even? определенная не как переменная, а как функция (через lambda). Letrec часто используют для получения значения переменной через рекурсионные вызовы. Эта конструкция имеет один подводный камень – поскольку все параметры передаются по значению, должны существовать однозначные условия для получения результата. Никаких двусмысленностей в letrec быть не должно (могут возникнуть, в частности, при комбинациях родственников letrec, let и let*).
Одной из важных особенностью функциональных языков программирования является концепция функций – иными словами процедуры в обычном понимании в функциональном программировании быть не должно. Выражения и функции получают параметры и передают результат. Однако на практике часто возникают ситуации, когда результат либо не требуется, либо не определен, либо просто не имеет смысла. Самым простым примером является вывод информации на экран. Какой результат может в данном случае получить функция вывода сообщения на экран? В тоже время отсутствие результата (либо возникновение ситуации, когда результат работы функции определить невозможно) может привести программу к краху – следующая функция не сможет получить входящий параметр (либо не сможет определить что это за параметр). Явление, при котором функция проявляет себя каким-либо образом помимо передачи результата, называется побочными эффектами (явлениями). В чистом функциональном программировании побочных явлений быть не должно в принципе (например, побочным эффектом является присваивание переменной какого-либо значения, создание объектов без их непосредственной передачи (так себя ведет define), ввод и вывод данных и т.д.). Специально для решения подобных проблем существует конструкция (begin (выражение1) … (выражениеN)), все вычисления в которой осуществляются последовательно и строго слева направо. Особенностью данной конструкции является результат – он всегда будет возвращен для последнего выражения.
Пример:
(define x 0)
(begin (set! x 5)
(+ x 1)) Результат 6 (5+1)
(begin (display "4 plus 1 equals ")
(display (+ 4 1))) Результат 5 (4+1), проигнорировав результаты вывода на экран посредством display (при этом сама строка будет напечатана). Begin также удобно использовать при создании законченных блоков, содержащих несколько выражений (например в If или cond) как замена let, с той лишь разницей, что для данного блока новых переменных не создается (соответственно и не разрушаются).
Рассмотрим итерации. Хотя хвостовая рекурсия может быть преобразована в цикл (при правильном ее составлении), циклы в Scheme существуют также и в общей форме. Один из них:
(do ((<переменная1> <инициализатор_переменной1> <шаг_приращения1>)
...)
(<тест> <выражение> ...)
<операторы_языка> ...)
Сразу стоит обратить внимание, на то, что приращивать можно не одну переменную и условие для выхода из цикла тоже может быть не одно.
(do ((vec (make-vector 5))
(i 0 (+ i 1)))
((= i 5) vec)
(vector-set! vec i i)) Результат вектор #(0 1 2 3 4), здесь создается вектор и переменная i
(let ((x '(1 3 5 7 9)))
(do ((x x (cdr x))
(sum 0 (+ sum (car x))))
((null? x) sum)))
Результат 25, проводиться подсчет списка. Здесь создается две переменные х (обратите внимание, переменная цикла инициализируется переменной, объявленной через let) и sum.
Также если рассмотреть конструкцию let более внимательно, то можно обнаружить, что с помощью нее также можно формировать итеративные процессы. Для этого определяемую переменную можно представить как функцию (через ее инициализатор) и вызывать ее для каждого упоминания в теле let (через условные операторы cond или if).
Несмотря на то, что все параметры в функции передаются по значению, есть возможность отложить вычисление параметров до момента их действительного использования. Плюсов от этого как минимум два: первое – это увеличение скорости вычислений (при грамотном использовании) и второе – решение задач, которые нельзя вычислить обычным способом. Увеличение скорости возможно, в случае, если в функцию передается несколько параметров и часть из них напрямую влияет на логику работы функции. Допустим, первый параметр функции однозначно говорит о том, что результат ее работы известен (например, частный случай), и в дальнейшем ничего вычислять в рамках данной функции не требуется. Если передавать все параметры по значению, то в момент входа в функцию, должны быть известны все параметры, значит, все выражения должны быть вычислены. Даже если как в нашем абстрактном примере эти параметры для получения результата не понадобятся. Можно конечно и посчитать, но не следует забывать, что в функциональном программировании рекурсия обычное дело, а это либо чистая рекурсия, либо итеративный процесс, и то и другое медленно. Поэтому прирост скорости может достигать больших величин (а до недавнего времени в функциональном программировании это был очень актуальный вопрос). Что касается дополнительных возможностей, продолжим рассмотрение все того же примера. Что если выполнение одного или нескольких параметров невозможно в конкретный момент вычислительного процесса? Допустим, в выражении происходит деление на нуль. Решить такую задачу обычным способом невозможно. Однако, есть математические выкладки, говорящие о том, что функция имеет решение (потому что ее результат в данном случае зависит от другого параметра, например общий коэффициент, который в данный момент равен нулю, тогда результат функции также будет равен нулю независимо от остальных параметров). Если отложить на некоторое время вычисление остальных параметров и работать с тем, что влияет на логику вычислений, то функция способна вернуть корректный результат, даже если вычисление остальных параметров может привести к фатальной ошибке.
В Scheme отложить вычисление можно через (delay (выражение)). Выражение вычислено не будет до конструкции force (синтаксис аналогичен). Force требует немедленного вычисления выражения (обычно используется в связке с delay).
Как видите, между delay и force может находиться произвольное число выражений, лишь бы p по-прежнему оставалось актуальным (то есть в нашем случае force должно наступить в рамках let, иначе после p перестанет существовать). На самом деле пользоваться delay и force легко, главное чтобы каждое обращение к не вычисленному параметру сопровождалось force.
Подобно многим языкам программирования Scheme поддерживает макроопределения (макросы), позволяющие образовывать новые типы выражений. Можно переопределить большинство стандартных конструкций, с помощью уже известной нам (define новое_имя наименование_конструкции). При этом конструкция под старым именем тоже сохраняется. Возьмем наш факториал:
Теперь fact можно вызывать как под старым именем, так и под именем mmm. Scheme обладает мощными средствами для образования новых возможностей языка на основе макроопределения ключевых слов (не просто синтаксическая замена), но в связи со сложностью и большим объемом материала мы далее макросы рассматривать не будем. Если есть желание, то описание работы с макросами можно найти в большой и подробной справке по PLT Scheme (справочная система называется Help Desk).
И традиционная строчка кода:
Список сокращенных обозначений и терминов, использованных в статье
СБИС – сверхбольшие интегральные схемы.
CAD - Computer Aided Design - компьютерная поддержка конструирования, предполагает объемное и плоское геометрическое моделирование, инженерный анализ на расчётных моделях высокого уровня, оценку проектных решений, получение чертежей.
Java – язык программирования.
Цикл – разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций. Также циклом может называться любая многократно исполняемая последовательность инструкций, организованная любым способом (например, с помощью условного перехода).
Продолжение следует ...
Обсудить на форуме – Введение в Sсheme. Часть 1
Статья из четвёртого выпуска журнала "ПРОграммист".
30th
Июн
Cамые старые батарейки
Cамые старые батарейки? Любопытную загадку задали ученым небольшие глиняные сосуды, отысканные археологами после 2-й мировой при раскопках старого античного городка Селевкия (на местности Ирака). Вазы любопытны тем, что в их отлично сохранились встроенные медные цилиндры со стальными сердечниками. Для пайки цилиндров употреблялся сплав свинца и олова в той же пропорции, что применяется и в современной электротехнике. Из предположения, что это остатки электролитических частей батареи, были изготовлены экспериментальные модели и залиты электролитом (медным купоросом). На клеммах появилось напряжение около 6 вольт. Для чего шумеры употребляли эти источники тока (возраст селевкийских ваз насчитывает 2000 лет) ученым узнать так и не удалось. Однако разумно предположить, что раз существовали источники электроэнергии, а ведь при соединении их в батареи можно получить сколь угодно высокое напряжение, то должны были существовать устройства и приборы, использующие электрический ток.
Это заметка с четвертого выпуска журнала “ПРОграммист”.
Скачать этот выпуск можно по ссылке.
Ознакомиться со всеми номерами журнала.
Облако меток
css реестр ассемблер timer SaveToFile ShellExecute программы массив советы word MySQL SQL ListView pos random компоненты дата LoadFromFile form база данных сеть html php RichEdit indy строки Win Api tstringlist Image мысли макросы Edit ListBox office C/C++ memo графика StringGrid canvas поиск файл Pascal форма Файлы интернет Microsoft Office Excel excel winapi журнал ПРОграммист DelphiКупить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)