УДК 004.4’24
ЯЗЫК ДЕТАЛИЗАЦИИ КАРКАСА ПРОГРАММНЫХ КОМПОНЕНТОВ ПОДДЕРЖКИ ЗАНЯТИЙ ЛИНГВИСТИЧЕСКОЙ НАПРАВЛЕННОСТИ
С.В. Гусс
Для каркаса программных компонентов поддержки занятий лингвистической направленности предлагается предметно-ориентированный язык детализации, позволяющий повысить эффективность разработки и сопровождения конечной программной системы.
Введение
В предлагаемой работе речь пойдёт о предметно-ориентированном языке (DSL - Domain-Specific Language), специфичном для определённой предметной области (домена) и практическим вопросам его развития и применения в реальных проектах. Такие языки создаются в контексте предметноориентированного проектирования (DDD - Domain-Driven Design). Это проектирование представляет собой подход к решению проблем, который применим тогда, когда одна и та же особенная проблема появляется и повторяется вновь и вновь (от одной члена семейства близких по функциональности программных продуктов к другому). С каждым проявлением данной проблемы выявляется её характер и методики управления ею (методика может быть представлена в виде обобщённой модели). Этот подход к проектированию особо эффективен вместе с использованием другого, более общего подхода к разработке приложений, подхода с использованием моделей (MDD - Model-Driven Development). Он позволяет в процессе проектирования пользоваться терминами той предметной области, для которой разрабатывается приложение, и предполагает создание двух взаимосвязанных компонентов в рамках построения конечного приложения. Первый компонент - фиксированная часть, которая может быть представлена, в зависимости от масштаба и формы проблемы, каркасом, программной платформой, интерпретатором или каким-нибудь прикладным программным интерфейсом (API). Разрабатывается такой компонент в рамках стандартного подхода к проектированию, в рамках используемой организации процесса разработки (будь то формальный процесс, либо на основе гибких методологий), с ручным кодированием и тестированием (например, с предварительным
Copyright © 2011 С.В. Гусс
Омский государственный университет им. Ф.М. Достоевского E-mail: [email protected]
написанием модульных тестов). Второй компонент - переменная часть, программный код которой претерпевает изменения при переходе от одного члена программного семейства к другому. Предметно-ориентированный язык работает с переменной частью, учитывая характеристики и специфику фиксированной. Одно из возможных воплощений предметно-ориентированного языка - визуальный инструмент моделирования в рамках программной среды разработки, предлагающий средства составления моделей и способный порождать программный код на основе этих моделей.
В данной работе предлагается описание предметно-ориентированного языка, работающего с каркасом программных компонентов поддержки занятий лингвистической направленности. Язык представлен в рамках так называемого рецепта детализации, где суть применения языка излагается в виде примеров программного кода. Рецепт детализации иногда называется рецептурным справочником и служит альтернативой формальной документации разработчика.
1. Предшествующие работы
Представленная в статье информация основана на исследованиях в области проектирования программных средств и составлена на базе ряда предшествующих ей научных и научно-практических работ различного характера. Эти работы близки по тематике к исследованиям автора статьи и тем или иным образом оказали влияние на ход его мысли. Их можно разделить на две категории. К первой категории относятся статьи и отчёты, опубликованные в научно-практических и научно-методических журналах, посвящённых вопросам образования и его автоматизации, методам программной инженерии и новым информационным технологиям. Ко второй категории работ можно отнести научно-популярные издания и монографии, из которых можно почерпнуть ряд идей, принципов, подходов и укоренившихся в практике методов и методик.
К первой категории можно отнести ряд исследовательских работ автора статьи [1-7]. Эти работы делятся на три группы.
К первой группе относятся исследования, затрагивающие концептуальные вопросы создания программных систем учебного назначения лингвистической направленности [1,2]. В этих работах даётся описание области электронного обучения с применением компьютерных игр. С позиции педагога игровые программные системы учебного назначения являются инструментами, которые помогают саморазвитию вовлечённого в процесс ученика и развивают реакцию для поиска решений на поставленную задачу. Их можно использовать как дополнительное средство для контроля знаний, как средство проверки усвоения материала. С позиции разработчика они состоят из ряда подсистем. К этим подсистемам относят подсистему управления пользователями, обучения, обслуживания, взаимодействия с учениками, безопасности, коммуникации, учебного материала, психофизиологического сопровождения. Вся обучающая система в целом имеет своих пользователей. К ним относятся ученик, учитель, методист, администратор и т.д. Они запускаются в рамках специальных технических устройств, таких как рабочие станции и мобильные системы.
Ко второй группе [2-5] относятся исследования практического характера, имеющие отношение к вопросу создания обучающих игровых систем. В них описаны процессы создания реальных приложений, часть из которых использовалась на практике в процессе обучения и проверки знаний студентов. На базе проведённых исследований был накоплен программный задел повторного использования для будущих разработок. В работах [4,5] представлена модель (на разных уровнях абстракции) каркаса программных компонентов поддержки занятий лингвистической направленности. В данной же статье представлен предметно-ориентированный язык, который работает с реализованной моделью каркаса.
К третьей группе относятся работы [6,7], в которых проводится анализ и обобщение подходов и приёмов разработки, подходящих для предметной области игровых обучающих программных систем.
К первой категории можно также отнести ряд близких по тематике работ [8-11]. Они представлены исследованиями А. Фуртадо (Andre W.B. Furtado), А. Сантоса (Andre Santos) и другими. Их работы связаны, прежде всего, с исследованием и разработкой предметно-ориентированных языков моделирования, предметно-ориентированным проектированием в целом, а также семейством программных систем. Направление исследований - развитие и адаптация концепции фабрик программного обеспечения для создания игровых программных систем, однако значительный акцент делается на представление игрового процесса в графической форме. К этой же категории можно отнести работы [12,13] отечественных исследователей А.С. Куракина и О. А. Шаболиной. Они имеют дело с исследованием практической стороны процесса разработки. В первом случае представлен процесс создания системы обучения для корпоративного сектора и проанализирован ряд проблем, встающих на этом пути. Во втором случае представлено альтернативное использование обучающих систем, предлагается обучать учеников методам и процессам создания программных средств на основе разработки игровых программных систем. Нечто подобное представлено также в работе [14], где в процессе создания компьютерных игр предлагается развивать не только программистские навыки.
Вторая категория представлена работами [15-24] общего характера, содержащими описание принципов и методик проектирования и разработки программных средств. В работах [15-17] представлено описание процессов и этапов жизненного цикла программных систем. В работе [15] излагаются основы гибких технологий моделирования (Agile modeling), их применение в рамках организации процессов экстремального подхода (extreme Programming) к программированию и унифицированного подхода. Работа [16] устанавливает связь между практически ставшим стандартом в разработке объектно-ориентированных систем унифицированным языком моделирования (UML -Unified Modeling Language) и унифицированным процессом (UP - Unified Process). Работа [17] отечественного исследователя В.В. Липаева характеризует инженерный подход к созданию программных средств, в котором учитываются и оцениваются такие характеристики, как трудоёмкость, длительность, производство на единицу размера программной продукции, средняя производи-
тельность труда, прототипы проектов, сложность, размер, наличие повторноиспользуемых компонентов и т.д. Работы [18-24] связаны с такими направлениями, как предметно-ориентированное проектирование и моделирование, повторное использование компонентов программных систем. Особо следует выделить работу Э. Эванса (Eric Evans), предлагающего специалисту предметной области и инженеру-разработчику «единый язык, на котором они могли бы разговаривать друг с другом» [22].
2. Модель предметной области
2.1. Каркас
Диаграмма классов каркаса представлена на рис. 1.
PlayerQuestionsCatcher
Class
В Properties Items Э Methods Add
f-----------------------------
GamePuzzlaStatesCatcher
Class
Э Properties ^ Items Э Methods Add
^ Questions
TfmeCatcher S)
Class
T
Э Properties
Ш Items
S Methods
Add
у
WordPuzzle
Class
Э Properties w Сотри IsoryCondition I? InitialCondition Secret
^ IfT
IS
StapsStatlstics w
Class
GameManager
Class
♦ GameCompetent
B Methods
MakeGameStep StartGame S Events
/ QuestionProcessed
GameCompetent
Class
a Methods
-Ф VerifyQuestion
Рис. 1. Диаграмма классов каркаса Основные члены каркаса представлены в следующих колонках. Использу-
емые термины предметной области (взяты в кавычки) разъясняются в разделе «Словарь предметной области» далее в статье.
Пространство имён С8Ес1иса1:юп.АОЬРСЕгате\уогк:
Класс
public class Alphabet - работа с «алфавитом» заданного «языка»:
public class CompetitorRole «ролью» «соперника»
работа с
public class GameCompetent - класс объектов, имеющих доступ к управлению элементами «процесса решения» «задачи-головоломки»
public class GameManager : GameCompetent - класс объектов, управляющих «процессом решения»
public enum GameProcessState - «состояние процесса решения» «задачи-головоломки»
public enum GamePuzzleState - «состояние решения задачи». Имеет место в контексте метода GetAnswerLogic класса CustomizableGetAnswerStrategy (листинг 2, далее по тексту)
public enum LanguageOfParticipants -заданный «язык»
public enum Question VerificationResult «результат обработки вопроса». Имеет место в контексте метода VerifyQuestionLogic класса CustomizableVerifyQuestionStrategy (листинг 2, далее по тексту)
Составляющие
- public Alphabet(LanguageOfParticipants language, bool useUpperCase) -конструктор, необходимо задать требуемый «язык» и указать тип выдачи литер - в верхнем или нижнем регистре;
- public List<string> Characters {get;} - элемент доступа к «алфавиту» «языка»;
- public GamePuzzleState GetAnswer(string[] question, out string answer, GameRules gameRules) - получить ответ от «соперника», хранящего «задачу-головоломку» на «вопрос» «игрока». Выполняется логикой каркаса во время вызова метода PlayerRole.MakeStep();
- public IGetAnswerStrategy AnswerStrategy {set; get;} - интерфейс класса, реализующего стратегию получения «ответа» на «вопрос»;
- public PlayerRole Player {set; get;} - «игрок», ассоциированный с «соперником»;
- public WordPuzzle Puzzle {set; get;} - лингвистическая «задача-головоломка»;
- public UmpireRole Umpire {set; get;} - «судья», ассоциированный с «соперником»;
- public GameCompetent(LanguageOfParticipants language) - конструктор, требует задания языка;
- public Alphabet CharacterSet {set; get;} - набор «литер» алфавита;
- public CompetitorRole Competitor {set; get;} - доступ к «сопернику»;
- public KnowledgeHolder HolderOfKnowledge {set; get;} - доступ к «лексемам» языка;
- public LanguageOfParticipants Language {set; get;} - язык текущего процесса;
- public PlayerRole Player {set; get;} - «игрок» «процесса решения»;
- public GameRules Rules {set; get;} - «правила» «процесса решения»;
- public UmpireRole Umpire {set; get;} - «судья» «процесса решения»;
- public void StartGame() - начать процесс;
- public bool MakeGameStep(string[] question) - сделать «шаг» в «процессе решения» «задачи-головоломки»;
public event EventHandler<QuestionProcessedEventArgs> QuestionProcessed - событие, на которое необходимо подписаться, чтобы получать «ответы» на «вопросы»;
Примечание: именно эти три составляющих представляют интерес для разработчика приложений из готовых компонентов, полученных путём детализации каркаса;
- Active - процесс активен (уже начался, но ещё не завершён);
- Inactive - процесс не активен (либо ещё не начался, либо уже завершён);
- AlmostCompleted - задача почти решена;
- Completed - задача решена полностью;
- NotCompleted - задача не решена (возможно, ещё и не решалась);
- English - английский язык;
- Russian - русский язык;
- Correct - вопрос-утверждение участника соответствует правилам задачи, действующим в рамках процесса;
- Incorrect - не соответствует правилам либо повторяется в то время, когда повторы запрещены;
- Repeat - соответствует правилам задачи, но уже имело место в рамках процесса;
Примечание: при инициализации класса GameManager можно указать -разрешены «повторения вопросов» со стороны главного участника или запрещены;
public class GamePuzzleStatesCatcher хранение всех «состояний решения задачи», полученных
за процесс (доступны через GameCompetent. Umpire. Statistics. States)
public class GameRules - правила «задачи-головоломки», которые действуют во время процесса
public class KnowledgeHolder - база знаний, содержащая словарные лексемы языка
public class PlayerQuestionsCatcher -хранитель вопросов, поступающих от игрока
public class PlayerRole - работа с «ролью» «игрока»
public class QuestionProcessedEventArgs : System.EventArgs - аргументы, передаваемые обработчику событий типа QuestionProcessed
public class StepsStatistics - статистика совершённых ходов
public class TimeCatcher - «временные отметки» совершения «ходов»
public class UmpireRole - работа с «ролью» «судьи»
- public void Add(GamePuzzleState state) - добавить состояние (выполняется автомтически логикой каркаса);
- public List<GamePuzzleState> Items {get;} - элементы всех «состояний решения задачи», учитываются автоматически логикой каркаса;
- public QuestionVerificationResult VerifyPlayerQuestion(string[] question, UmpireRole umpire) - проверить «вопрос» «игрока»;
- public bool AllowRepeatQuestions {set; get;} - разрешение или запрет на повторные «вопросы» со стороны «игрока»;
- public IVerifyQuestionStrategy VerifyQuestionStrategy {set; get;} -стратегия проверки утверждений со стороны игрока;
- public KnowledgeHolder(LanguageOfParticipants language) - конструктор, требует указания «языка» для работы;
- public void AddWord(string word) - добавить «лексему» в базу знаний на период «процесса решения»;
- public bool FindWord(string word) - проверить наличие конкретной «лексемы» в базе;
- public List<string> GetWordsByParams(int length) - найти все «лексемы» в базе заданной длины;
- public List<string> GetWordsByParams(int length, char firstLetter) -найти все «лексемы» в базе заданной длины, начинающиеся с определённой литеры;
- public List<string> Vocabulary {get;} - доступ к «словарю», содержащему «лексемы» текущего языка;
- public void Add(string[] question) - добавить «вопрос», учитываются автоматически логикой каркаса;
- public List<string> Items {get;} - получить список «вопросов»;
- public GamePuzzleState MakeStep(string[] question, out string answer, GameRules gameRules) - сделать «ход» (выполняется логикой каркаса во время вызова метода GameManager.MakeGameStep(..));
- public CompetitorRole Competitor {set; get;} - «соперник», ассоциированный с «игроком»;
- public UmpireRole Umpire {set; get;} - «судья», ассоциированный с «игроком»;
- public QuestionProcessedEventArgs(GamePuzzleState state, string answer)
- конструктор, требует указания состояния решения задачи и ответ на вопрос со стороны игрока (выполняется автоматически логикой каркаса во время вызова метода GameManager.MakeGameStep(..));
- public string Answer {get;} - «ответ» на «вопрос»;
- public GamePuzzleState State {get;} - «состояние решения задачи»;
- public PlayerQuestionsCatcher Questions {set; get;} - «вопросы», заданные «игроком» в «процессе решения» «задачи-головоломки»;
- public GamePuzzleStatesCatcher States {set; get;} - «состояния решения задачи»;
- public TimeCatcher TimeStamps {set; get;} - «временные отметки» совершённых «игроком» «ходов»;
- public void Add() - добавить временную отметку, учитываются логикой каркаса;
- public List<DateTime> Items {get;} - набор «временных отметок» совершения «ходов»;
- public void StartGame(PlayerRole player, CompetitorRole competitor) -начать «процесс решения» (выполняется автоматически при вызове метода GameManager. StartGame());
- public CompetitorRole Competitor {set; get;} - ассоциированы с «судьёй» «соперник»;
- public PlayerRole Player {set; get;} - ассоциированный с «судьёй» «игрок»;
- public GamePuzzleState PuzzleState {set; get;} - текущее состояние решения задачи;
- public StepsStatistics Statistics {set; get;} - «статистика шагов»;
public class WordPuzzle - работа с «задачей-головоломкой»
public class
WrongPlayerQuestionException :
System.Exception - исключения, вызванные некорректным составлением «вопросов»
- public string CompulsoryCondition {set; get;} - «обязательное условие» для решения задачи;
- public string InitialCondition {set; get;} - «начальное условие» для решения задачи;
- public string Secret {set; get;} - секрет «задачи»;
Конструкторы:
- public WrongPlayerQuestionException();
- public WrongPlayerQuestionException(string message);
- public WrongPlayerQuestionException(string message, System.Exception innerException);
protected WrongPlayerQuestionException(SerializationInfo info, StreamingContext context);
2.2. Шаблон детализации
Листинг 1. Код шаблона проекта
using System;
using GSEducation.AQLPGFramework;
namespace GSEducation.AQLPGFramework.DetalizationTemplate{ public partial class TemplateGameManager: GameManager)
public TemplateGameManager()
: base(LanguageOfParticipants.Russian, true){
Initial izeGame();}
public TemplateGameManager(LanguageOfParticipants language, bool allowRepeat)
: base(language, allowRepeat){
Initial izeGame();}
private void InitializeGame(){
Make Puzzle ();}
protected virtual void MakePuzzle(){
throw new NotImplementedException();}}
public partial class TemplateGetAnswerStrategy : IGetAnswerStrategy{
public TemplateGetAnswerStrategy(GameManager manager))
gameManager = manager;}
protected GameManager gameManager;
public GamePuzzleState GetAnswer(string[] question, out string answer){
GamePuzzleState puzzleState = GamePuzzleState.NotCompleted; answer =
puzzleState = GetAnswerLogic(question, out answer); return puzzleState;}
protected virtual GamePuzzleState GetAnswerLogic(string[] question, out string answer){
throw new NotImplementedException();}}
public partial class TemplateVerifyQuestionStrategy : IVerifyQuestionStrategy{
public TemplateVerifyQuestionStrategy(GameManager manager))
gameManager = manager;}
protected GameManager gameManager;
public QuestionVerificationResult VerifyQuestion(string[] question))
QuestionVerificationResult result =
QuestionVerificationResult. Correct;
VerifyQuestionLogic(question, out result); return result;}
protected virtual void VerifyQuestionLogic(string[] question, out result){
throw new NotImplementedException();}}}
Листинг 2. Предоставление точек расширения
using System;
using GS Education.AQLPGFramework;
namespace GSEducation.AQLPGFramework.DetalizationTemplateJ public class CustomizedGameManager : TemplateGameManagerj
public CustomizedGameManager(LanguageOfParticipants language, bool allowRepeat)
: base(language, allowRepeat){}
public CustomizedGameManager()
: base(){}
protected override void MakePuzzle(){
Rules.VerifyQuestionStrategy = new CustomizableVerifyQuestionStrategy(this);
Competitor.AnswerStrategy = new CustomizableGetAnswerStrategy(this);
//TODO:
//===============================
VARIABLE PART - EXTENSION POINT
//===============================
}
private class CustomizableVerifyQuestionStrategy : TemplateVerifyQuestionStrategyj
public CustomizableGetAnswerStrategy(GameManager manager)
: base(manager){}
protected override void VerifyQuestionLogic(string[] question, out QuestionVerificationResult verificationResult){
verificationResult = QuestionVerificationResult.Incorrect;
//TODO:
//===============================
VARIABLE PART - EXTENSION POINT
//===============================
}}
private class CustomizableGetAnswerStrategy : TemplateGetAnswerStrategyj
public CustomizableGetAnswerStrategy(UmpireRole umpire, CompetitorRole competitor)
: base(umpire, competitor)!}
protected override GamePuzzleState GetAnswerLogic(string[] question, out string answer){
GamePuzzleState puzzleState = GamePuzzleState.NotCompleted; answer =
//TODO:
//===============================
VARIABLE PART - EXTENSION POINT //===============================
return puzzleState;}}}}
Места в листингах, обозначенные как «VARIABLE PART», представляют собой точки расширения, в которые разработчик может вставлять изменяемый код (активно пользуясь элементами каркаса). Листинг 1 содержит код шаблона проекта, который абсолютно не требует изменений, он не содержит точек расширений и служит своеобразным проектным решением, способствующим более комфортной работе по созданию конечного компонента на основе каркаса. В листинге 2 следует изменить название класса «CustomizedGameManager» на более подходящее в конкретном контексте имя. Для предметно-ориентированного языка каркас, короткое описание которого
дано на рис. 1 и в описании членов пространства имён, а также шаблон его детализации (представленный листингами 1-2) представляют фиксированную часть.
Словарь предметной области
Каркас хорошо подходит для создания компонентов игровых лингвистических задач типа «вопрос-ответ». В нём содержится ряд элементов, реализующих концепции предметной области, перечисленных далее.
Словарь предметной области состоит из следующих элементов.
Язык (LanguageOfParticipants). Представленная реализация каркаса предполагает выбор между английским и русским языком. Алфавит (Alphabet). Набор литер выбранного языка. Лексемы. Элементы словаря (KnowledgeHolder.Vocabulary) могут быть отфильтрованы по длине либо по начальной литере. Роль. Определённое представление поведения в процессе решения задачи. Виды ролей: соперник (CompetitorRole), игрок (PlayerRole), судья (UmpireRole). Действия, производимые методами StartGame() и MakeGameStepO класса GameManager, происходят от лица игрока. Задача-головоломка (WordPuzzle). Состоит из обязательного условия, начального условия и секрета. Обязательное условие (CompulsoryCondition) - то, без чего невозможно решение задачи. Например, это может быть требование - составлять лексемы, начинающиеся только на определённую букву, определённой длины или содержащие заданные буквы. В реализации каркаса этот элемент представлен в виде строковой переменной, формат и логика обработки которой должна предусматриваться создателем задачи. Начальное условие и секрет также представлены в виде строковых переменных и соответственно предполагают создания логики их обработки и интерпретации. Начальное условие (InitialCondition) - то, с чего следует начинать процесс решения. Например, это может быть требование - начинать процесс с составления лексемы определённой длины. Ответ - действие соперника по отношению к игроку. Вопрос - действие игрока по отношению к сопернику. Ответы и вопросы — это элементы диалога, сообщения, которыми они обмениваются. В листинге 2, в методах VerifyQuestionLogic() и GetAnswerLogic() представлены точки расширения, которые требуют определения логик проверки вопросов и выдачи соответствующего ответа. В рамках логики проверки вопросов (VerifyQuestionLogic()) необходимо выдать результат обработки вопроса (QuestionVerificationResult). Результат может быть следующим: корректный вопрос, некорректный вопрос, повторный вопрос. В рамках логики ответа на вопрос (GetAnswerLogic()) необходимо указать состояние решения задачи (GamePuzzleState). Состояния решения задачи: почти решена, решена, не решена. Процесс решения. Состояние процесса решения: активный, неактивный. Если задача решена полностью, логика каркаса переводит процесс в неактивное состояние. Правила (GameRules). Следят за исполнением логики проверки вопроса (VerifyQuestionLogic). Шаг. В рамках процесса решения задачи шаг представляет собой последовательность действий — задать вопрос, получить ответ. Статистика шагов (StepsStatistics). Логика каркаса фик-
сирует каждый шаг в рамках статистики. Статистика учитывает состояния решения задачи, временные отметки, вопросы.
2.3. Примеры детализации каркаса
Лингвистическая задача «What Letter I Thought» (рис. 2)
Описание задачи. Условие - случайным образом загадывается буква, которую необходимо отгадать игроку. Игра состоит из двух этапов. На первом этапе игрока просят последовательно называть слова, в которых предположительно содержится загаданная буква. Если при очередном вопросе игрока, выраженном в виде требуемого слова, обнаружится, что это слово содержит загаданную букву, игрок переводится на следующий этап. На этом этапе он должен задавать вопросы в виде букв. Т.е. первый этап завершается тогда, когда игрок находит слово, в котором есть загаданная буква. Теперь на основе этого игрок должен найти букву. Когда она будет найдена, задача будет решена. Представление игрового процесса может быть оформлено интерфейсом, приведённым на рис. 2 (именно так оформлен игровой процесс одного из игровых продуктов автора статьи, проекта под названием «We Need Your Help», в котором используются компоненты, созданные путём детализации представленного каркаса). В верхней части окна графического интерфейса содержится информация в виде общих требований к игроку, того, что ему необходимо сделать, чтобы решить задачу. В левой части — требования и указания, касающиеся конкретного этапа процесса. Справа — отображение диалога игрока с системой в виде вопросов и ответов.
Логика создания задачи-головоломки (точка расширения MakePuzzle() в листинге 2) заключается в следующем. Необходимо выбрать случайным образом букву, которую игрок должен угадать. В данном случае можно воспользоваться GameCompetent.CharacterSet.Characters и CompetitorRole.Puzzle.Secret элементами предметной области (Листинг 3). Случайным образом выбирается буква из алфавита текущего языка. Её значение становится секретом задачи-головоломки.
Логика стратегии проверки вопроса игрока (точка расширения метода VerifyQuestionLogic(..)) представлена в листинге 3. После того как игрок сделал ход, задал вопрос, предложив слово, происходит его проверка в соответствии с текущим этапом игры. Если состояние решения задачи на данный момент - ещё не решена, значит, сейчас первый этап, если - почти решена, то второй. На первом этапе вопрос проверяется по словарю, на втором - по алфавиту. Выносится соответствующее решение о корректности или некорректности заданного вопроса. Как было сказано ранее в описании каркаса, вопрос может задаваться повторно. Повторения можно разрешить или запретить. Решить этот вопрос с запретом предлагается разработчику конечного предложения, который должен указать в конструкторе класса, представляющего данную игру в готовом к применению компоненте, запрет или разрешение повторов. Сами же повторы будут отслеживаться автоматически или вообще не отслеживаться логикой каркаса, в зависимости от сделанного выбора (разрешение или запрет).
Логика стратегии выдачи ответа (точка расширения Ое1Ап5\^егЬо£ю(..)) представлена в листинге 3. Суть такова - анализируется вопрос игрока. Если его вопрос, он же требуемое слово (либо буква, если игрок на втором этапе), содержит секрет задачи, т.е. букву, которую нужно угадать, то в зависимости от того, на каком этапе находится игрок, решается, перевести его на второй этап или же поздравить с победой. На первый взгляд кажется, что игрок на первом же этапе может назвать требуемую букву, не переходя на второй этап. Однако это невозможно, т.к. вышеописанная логика стратегии проверки вопроса игрока на первом этапе сравнивает его вопрос на принадлежность словарю. А словарь, по крайней мере входящий в реализацию описываемого каркаса, не содержит слов длиною в одну букву.
ThTsns^'WVliH^tc-HTcr xVo jws+ ТІюи^И+Т" ри&ьіе.
Tnpfgfjvijil wHVi words оч firs+
syaqe mA wi+tl le++ers оч second s+aqe ачЛ і|ои solve -ffits риььіе!
S-l-O0)c\:
Wr'l+5 words
le++er supposedly
i+ac)62.'.
Wri+e le++ers from 1)оиг \ae+ word +0 solve +Vie pMfcfcle,
■r keser i Г Mew PuzzleJ level I
QMes-Ноч: scores: 0
Poes +Vlis word: [LrON]
Contain 40ИГ Ie++er7
Yes, i+ is!
Рис. 2. Лингвистическая задача «What Letter I Thought»
Листинг 3. Лингвистическая задача «What Letter I Thought»
MakePuzzle() extension point:
Competitor.Puzzle = new WorclPuzzleQ;
Random randomizer = new RandomQ;
List<string> alphabet = CharacterSet.Characters;
int currentlndex = randomizer.Next(0, alphabet.Count - 1);
string randomizerAlphabet Effect = alphabet [currentlndex];
Competitor.Puzzle.Secret = randomizerAlphabet Effect;
VerifyQuestionLogic(..) extension point:
if (gameManager.Umpire.PuzzleState == GamePuzzleState.NotCompleted){
if (IgameManager.HolderOf Knowledge. Vocabulary. Contains) quest ion [0])){
verificationResult = QuestionVerificationResult.Incorrect; return;}}
if (gameManager.Umpire.PuzzleState == GamePuzzleState.AlmostCompleted){
if (question[0].Length == 1 && IgameManager.CharacterSet.Characters.Contains(question[0])){
verificationResult = QuestionVerificationResult.Incorrect;
return;}}
GetAnswerLogic(..) extension point:
if (question[0] .Contains(gameManager.Competitor.Puzzle.Secret)){
if (gameManager.Umpire.PuzzleState == GamePuzzleState.NotCompleted){ puzzleState = GamePuzzleState.AlmostCompleted;}
else if (gameManager.Umpire.PuzzleState == GamePuzzleState.AlmostCompleted){ puzzleState = GamePuzzleState.Completed;}} if (!question[0].Contains(gameManager.Competitor.Puzzle.Secret)){ if (gameManager.Umpire.PuzzleState ==
GamePuzzleState.AlmostCompleted && question[0].Length == 1){ return GamePuzzleState. Almost Completed;}}}
Лингвистическая задача «What Word I Thought» (рис. 3)
Описание задачи. Условие - случайным образом загадывается слово. От игрока требуется угадать это слово. Игрок последовательно должен задавать вопросы в виде требуемых слов. После каждого вопроса игрок получает ответ. Ответ - количество букв в загаданном слове, которые встречаются в вопросе игрока. То есть ответ представлен в виде подсказки, уточняющей правильность направлений поиска игрока в процессе решения задачи. Задача считается решённой только тогда, когда игрок отгадает загаданное слово. Детализация каркаса представлена в листинге 4.
THIS is "Wha-H Word I'Ve Jms+ ТИои^И+7" pwfcfcle. Tгч +b fW +He word toy asking wi+Vi variows o«jes. 4
\.TL^IN(0 wssfoj 4. cowfRcSSftO 5. 6^in(U (p. L^OTA'R’PftO YROVUCT (4J 6. ШотЫ ■_ Kesef 1 Г Mew Puzzle ' level I xs word: [WOT] scores: о 40ИГ5? No, Uw-I- mi) word 'nas [??] le-H-ers from your word.
Q W € Л 7 У U J О Г ASDfg»JKlWr Z х с V в N М ШШШ
Рис. 3. Лингвистическая задача «What Word I Thought»
Листинг 4. Лингвистическая задача «What Word I Thought»
MakePuzzle() extension point:
Competitor.Puzzle = new WordPuzzle();
Random randomizer = new Random();
List<string> vocabulary = HolderOfKnowledge.Vocabulary; int currentlndex = randomizer.Next(0, vocabulary.Count - 1); string randomizerVocabularyEffect = vocabulary [currentlndex];
Competitor.Puzzle.Secret = randomizerVocabularyEffect;
VerifyQuestionLogic(..) extension point:
if (!gameManager.HolderC)fKnowledge.Vocabulary.Contains(question[0])){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
GetAnswerLogic(..) extension point:
if (question[0] .Contains(gameManager. Umpire. Competitor. Puzzle. Secret)) { return GamePuzzleState.Completed;}
if (!question[0] .Contains(gameManager.Umpire.Competitor.Puzzle.Secret)){
int lettersNumber = 0;
for (int i = 0; i < question[0].Length; i++){
if (gameManager.Umpire.Competitor.Puzzle.Secret.Contains(question[0] [i].ToString()))
lettersNumber++;}
answer = lettersNumber.ToStringO;
return GamePuzzleState.NotCompleted;}
Лингвистическая задача «Funny Stairs»
Описание задачи. Реализация алгоритма (включает проверку на возможность решения задачи; если после 10 попыток не удаётся составить задачу, поддающуюся решению, работа алгоритма заканчивается нулевым результатом) представлена в листинге 5. Условия следующие. Обязательное условие: все вопросы игрока должны начинаться с определённой буквы. Начальное условие - количество необходимых для составления игроком слов, выбираемое случайным образом, в данном случае - от 4 до 8. Ещё один момент, который реализован стратегией проверки вопроса, - первый вопрос игрока должен начинаться со слова длиной не более 3. Каждый последующий корректный вопрос должен быть на единицу больше предыдущего. Задача будет решена тогда, когда игрок доберётся до самого последнего вопроса. Таким образом, в начале процесса игроку даются условия - построить лестницу слов, начиная со слов длиною не более 3, причём каждое должно начинаться с определённой обязательным условием буквы. В представленной реализации алгоритма каждый новый вопрос игрока - дополненный предыдущий. Отсюда следует, что игрок может заменять уже составленные в предыдущем ходе слова на новые, более ценные с его точки зрения или точки зрения игровой системы, где используется данный компонент. Например, каркас не предоставляет возможности оценивания результата решения задачи, т.к. было сделано предположение, что это обязанность «игрового движка» (в англоязычной литературе - game engine). Игровой движок может обращаться к статистике решения задачи посредством объекта класса StepsStatistics и произвести оценку в соответствии со своими потребностями.
Листинг 5. Лингвистическая задача «Funny Stairs»
MakePuzzle() extension point:
Competitor.Puzzle = new WordPuzzle();
Random randomizer = new Random();
List<string> alphabet = CharacterSet.Characters;
bool testResultlsGood = true;
int verificationlterationNumber = 0;
int maxVerificationlterationNumber = 10;
again:
int currentlndex = randomizer.Next(0, alphabet.Count - 1); string randomizerAlphabetEffect = alphabet [currentlndex];
Competitor.Puzzle.CompulsoryCondition = randomizerAlphabetEffect;
int puzzleSize = randomizer.Next(4, 8);
string randomizerPuzzleEffect = puzzleSize.ToString();
Competitor.Puzzle.InitialCondition = randomizerPuzzleEffect;
List<string> vocabularyltems; int vocabularyltemLength = 3;
int iterationNumber = Convert.ToInt32(Competitor.Puzzle.InitialCondition); for (int i = 0; i < iterationNumber; i++){
vocabularyltems =
HolderOfKnowledge.GetWordsByParams(i + vocabularyltemLength,
Competitor. Puzzle. CompulsoryCondition[0]); if (vocabularyltems == null || vocabularyltems.Count == 0) testResultlsGood = false;}
if (!testResultIsGood && verificationlterationNumber <= maxVerificationIterationNumber){
verificationIterationNumber++;
testResultlsGood = true;
goto again;}
else if (TestResultlsGood && verificationlterationNumber > maxVerificationlterationNumber)
Competitor.Puzzle = null;
VerifyQuestionLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length > lengthlnitialCondition){ verificationResult = QuestionVerificationResult.Incorrect; return;}
for (int i = 0; i < question.Length; i++){
if (!gameManager.HolderOfKnowledge.Vocabulary.Contains(question[i])){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
if (question[i] [0] .ToString() != gameManager.Umpire.Competitor.Puzzle.CompulsoryCondition){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
if ((i == 0) && question[0] .Length > 3){ verificationResult = QuestionVerificationResult.Incorrect; return;} if 0 >= 1){
if (question[i].Length - question[i - 1].Length != 1){ verificationResult = QuestionVerificationResult.Incorrect; return;}}}
GetAnswerLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length == lengthlnitialCondition) return GamePuzzleState.Completed;
Лингвистическая задача «Word Group»
Описание задачи. Алгоритм представлен (включая проверку на возможность решения составленной задачи) в листинге 6. Необходимое условие -случайно выбранное слово из словаря. Начальное условие - длина этого слова, в контексте задачи - количество слов, которые необходимо составить. Длина составляемых игроком слов - произвольная. Главное требование (в соответствии с необходимым условием) - чтобы игрок на каждую букву заданного слова составил по одному своему слову. Составление слов должно идти последовательно, от начальной буквы заданного слова до последней. Ещё один момент, на который необходимо обратить внимание, - логика каркаса не пропустит слов в вопросе игрока, которых нет в словаре каркаса. Чтобы каркас не отвергал слов, которые он не знает, необходимо добавить в его базу знаний новые слова, которые будут действовать только на время процесса решения задачи. Делается это с помощью метода AddWord(..) класса HolderOfKnowledge.
Листинг 6. Лингвистическая задача «Word Group» MakePuzzle() extension point:
Competitor.Puzzle = new WordPuzzle();
Random randomizer = new Random();
List<string> vocabulary = HolderOfKnowledge.Vocabulary; bool testResultlsGood = true;
int verificationlterationNumber = 0;
int maxVerificationlterationNumber = 10;
again:
int currentlndex = randomizer.Next(0, vocabulary.Count - 1); string randomizerVocabularyEffect = vocabulary [currentlndex];
Competitor.Puzzle.CompulsoryCondition = randomizerVocabularyEffect; string randomizerPuzzleEffect =
Competitor.Puzzle.CompulsoryCondition.Length.ToString();
Competitor.Puzzle.InitialCondition = randomizerPuzzleEffect;
List<string> vocabularyltems = new List<string>();
int vocabularyltemLength = Convert.ToInt32(Competitor.Puzzle.InitialCondition); int iterationNumber = Convert.ToInt32(Competitor.Puzzle.InitialCondition); for (int i = 0; i < iterationNumber; i++){ vocabularyltems = HolderOfKnowledge.Get WordsByParams( vocabularyltemLength,
Compet itor. Puzzle. CompulsoryCondition[i]); if (vocabularyltems == null || vocabularyltems.Count == 0) testResultlsGood = false;}
if (TestResultlsGood && verificationlterationNumber <= maxVerificationlterationNumber){
verificationIterationNumber++;
testResultlsGood = true;
goto again;}
else if (TestResultlsGood && verificationlterationNumber > maxVerificationlterationNumber)
Competitor.Puzzle = null;
VerifyQuestionLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length > lengthlnitialCondition)! verificationResult = QuestionVerificationResult.Incorrect; return;}
for (int i = 0; i < question.Length; i++){
if (!gameManager. HolderOfKnowledge. Vocabulary. Contains (question [i])){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
if (question[i] [0] != gameManager.Umpire.Competitor.Puzzle.CompulsoryCondition[i]){
verificationResult = QuestionVerificationResult.Incorrect;
return;}}
GetAnswerLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length == lengthlnitialCondition) return GamePuzzleState.Completed;
Лингвистическая задача «Word Square»
Описание задачи. Описание алгоритма представлено в листинге 7. Отличие от предыдущего случая - длины всех составляемых игроком слов должны быть одного размера.
Листинг 7. Лингвистическая задача «Word Square»
MakePuzzle() extension point:
Competitor.Puzzle = new WordPuzzle();
Random randomizer = new Random();
List<string> vocabulary = HolderOfKnowledge.Vocabulary;
bool testResultlsGood = true;
int verificationlterationNumber = 0;
int maxVerificationlterationNumber = 10;
again:
int currentlndex = randomizer.Next(0, vocabulary.Count - 1); string randomizerVocabularyEffect = vocabulary [currentlndex];
Competitor.Puzzle.CompulsoryCondition = randomizerVocabularyEffect; string randomizerPuzzleEffect =
Competitor.Puzzle.CompulsoryCondition.Length.ToStringO;
Competitor.Puzzle.InitialCondition = randomizerPuzzleEffect;
List<string> vocabularyltems = new List<string>();
int vocabularyltemLength = Convert.ToInt32(Competitor.Puzzle.InitialCondition); int iterationNumber = Convert.ToInt32(Competitor.Puzzle.InitialCondition); for (int i = 0; i < iterationNumber; i++){
vocabularyltems = HolderOfKnowledge.GetWordsByParams(vocabularyItemLength, Competitor. Puzzle. CompulsoryCondition[i]); if (vocabularyltems == null || vocabularyltems.Count == 0) testResultlsGood = false;}
if (TestResultlsGood && verificationlterationNumber <= maxVerificationlterationNumber)!
verificationIterationNumber++;
testResultlsGood = true;
goto again;}
else if (TestResultlsGood && verificationlterationNumber > maxVerificationlterationNumber) Competitor.Puzzle = null;
VerifyQuestionLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length > lengthlnitialCondition)! verificationResult = QuestionVerificationResult.Incorrect; return;}
for (int i = 0; i < question.Length; i++){
if (!gameManager.HolderOfKnowledge.Vocabulary.Contains(question[i])){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
if (question[i] [0] != gameManager.Umpire.Competitor.Puzzle.CompulsoryCondition[i]){
verificationResult = QuestionVerificationResult.Incorrect;
return;}
if ((i >= 1) && (question[i],Length != question[i - 1].Length) &&
(question[i],Length != lengthlnitialCondition))! verificationResult = QuestionVerificationResult.Incorrect; return;}}
GetAnswerLogic(..) extension point:
int lengthlnitialCondition = Convert.ToInt32( gameManager. U mpire. Competitor. Puzzle. InitialCondition); if (question.Length == lengthlnitialCondition) return GamePuzzleState.Completed;
Заключение
В работе представлено описание работы предметно-ориентированного языка. Проведён обзор литературы, лежащей в основании исследования автора, указана связь предшествующих работ с работой, представленной в предлагаемой статье. Проиллюстрирована реализация алгоритмов на предметно-ориентированном языке. Предложено проектное решение, позволяющее работать с абстракциями предметной области «вопрос-ответных» задач лингвистической направленности, не зависящее от области применения созданных компонентов. Однако их предполагаемое применение - область игрового электронного обучения. Следующая ступень - развитие темы каркаса и предметно-ориентированного языка - создание инструмента работы с языком. Речь идёт о так называемом визуальном предметно-ориентированном языке. Реализованные программно, инструменты такого языка позволяют создавать модели конкретных проблемных ситуаций и порождать из них готовый к использованию код. Применительно к тому, что было описано в статье, такой язык позволил бы создавать алгоритмы лингвистических задач (листинги 3 - 6) не вручную, а с помощью составления диаграмм заданной
нотации с последующей генерацией программного кода и помещением его в соответствующие места программы (точки расширения в листинге 2).
Литература
1. Гусс С.В. Обучающие программы на основе игр лингвистической направленности // Информатика и образование. М. : ОАО «Московская газетная типография». 2009. № 11. С. 123-124.
2. Гусс С.В. Элементы повторного использования для программных систем учебного назначения. Концептуальное проектирование и анализ // Математические структуры и моделирование. Омск : ООО «УниПак». 2009. Вып. 20. С. 78-92.
3. Гусс С.В. Использование компьютерных лингвистических игр в процессе обучения // Открытое образование. М. : «CAPITALPRESS». 2010. № 1. С. 18-29.
4. Гусс С.В. Высокоуровневая модель семейства программных компонентов для поддержки занятий в игровой форме // Математические структуры и моделирование. Омск : «Омское книжное издательство». 2010. № 21. С. 44-54.
5. Гусс С.В. Модель каркаса программных компонентов поддержки занятий лингвистической направленности в игровой форме // Прикладная информатика. М. : ООО «Маркет ДС Корпорейшн». 2010. Вып. 3 (27). С. 62-77.
6. Гусс С.В. Проблема повторного использования в разработке семейства игровых программных систем учебного назначения // Вестник Омского университета. Омск : Издательство ОмГУ им. Ф.М. Достоевского. 2010. № 4. С. 147-149.
7. Гусс С.В. Пакет вспомогательных средств для построения семейства программных систем в определённой предметной области // Программная инженерия. М. : «Новые технологии». 2011. № 1. С. 25-33.
8. Furtado A., Santos A. Using Domain-Specific Modeling towards Computer Games
Development Industrialization. URL: http://www.dsmforum.org/events/
DSMO6/Papers/l-Furtado.pdf (дата обращения: 6.04.2011).
9. Furtado A., Santos A., Ramalho G. A Computer Games Software Factory and Edutainment Platform for Microsoft .NET. URL: http://www.cin.ufpe.br/ ~awbf/files/IET_SharpLudus .pdf (дата обращения: 6.04.2011).
10. Furtado A., Santos A. Extending Visual Studio .NET as a Software Factory for Computer Games Development in the .NET Platform. URL: http://www. cin .ufpe .br/~awbf /files/IVNET2006_SharpLudus .pdf (дата обращения: 6.04.2011).
11. Furtado A., Santos A. Defining and Using Ontologies as Input for Game
Software Factories. URL: www.cin.ufpe.br/~awbf/files/SBGames2 006_
GameOntology.pdf (дата обращения: 6.04.2011).
12. Куракин А.С. Опыт использования технологий дистанционного обучения в корпоративном образовательном проекте // Открытое образование. М. : «CAPITALPRESS». 2010. № 6. С. 57-68.
13. Шабалина О.А. Применение компьютерных игр для обучения разработке программного обеспечения // Открытое образование. М. : «CAPITALPRESS». 2010. № 6. С. 19-25.
14. Перевозчикова М.С. Создание компьютерной игры - эффективный инструмент самообразования // Информатика и образование. М. : ОАО «Московская газетная типография». 2009. № 11. С. 115-117.
15. Амблер С. Гибкие технологии: экстремальное программирование и унифицированный процесс разработки. СПб.: Питер, 2005. 412 с.
16. Арлоу Д., Нейштадт A. UML 2 и Унифицированный процесс. Практический объектно-ориентированный анализ и проектирование. 2-е издание. СПб. : Символ-Плюс, 2007. 624 с.
17. Липаев В.В. Экономика производства программных продуктов. Издание второе. М. : СИНТЕГ, 2011. 352 с.
18. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приёмы объектно-ориентированного проектирования. Паттерны проектирования. СПБ. : Питер, 2008. 366 с.
19. Гринфилд Д., Шорт К., Кук С., Кент С., Крупи Д. Фабрики разработки программ: потоковая сборка типовых приложений, моделирование, структуры и инструменты. М. : ООО «И.Д. Вильямс», 2007. 592 с.
20. Коплиен Д. Мультипарадигменное проектирование для C++. СПб. : Питер, 2005. 235 с.
21. Чарнецки К., Айзенекер У. Порождающее программирование: методы, инструменты, применение. СПб. : Питер, 2005. 731 с.
22. Эванс Э. Предметно-ориентированное проектирование (DDD): структуризация сложных программных систем. М. : ООО «И.Д. Вильямс», 2011. 448 с.
23. Cook S., Jones G., Kent S. Domain-Specific Development with Visual Studio DSL Tools / United States of America : Addison Wesley Longman, Inc., 2007. 563 p.
24. Sutcliffe A. The Domain Theory: Patterns for Knowledge and Software Reuse. United States of America : CRC Press, 2002. 424 p.