Пример 1. Простые вычисления с помощью класса MathParser
Мы начнем с примера, разъясняющего работу с классом MathParser. В приложении, показанном на рисунке 1, пользователь вводит выражение, зависящее от значения переменной x, и численное значение этой переменной, при этом допустим такой синтаксис, как sqrt(2*pi) или e^2. Затем, для вычисления значения выражения, пользователь нажимает клавишу ввода.
Заметьте, что для вычисляемых выражений класс MathParser использует математические функции и константы языка ActionScript. Подобно Java, JavaScript, C++, и многим другим языкам программирования, математические функции ActionScript и константы поддерживают двойную степень точности (не уверен правильно ли я перевел термин double precision accuracy). Важно учитывать данный факт, т.к. это может привести к странным (неожиданным) результатам. Например, если вы попробуете вычислить значение выражения tan(pi/2), то (т.к. значение константы pi/2 не может быть выражено в численном виде абсолютно точно) вы получите значение тангенса при значении переменной x очень и очень близком к pi/2 (но не равном ему), а это очень большое число (хотя как мы знаем, что функция тангенса не определена при pi/2). Мораль здесь в том, что, чтобы создать точный научный калькулятор, нужно проделать намного больше работы, чем просто суметь вычислить значения встроенных функций и констант языка программирования.
Настройка сцены
Чтобы создать приложение, изображенное на рис. 1, сначала нам понадобится несколько элементов на сцене. Это должны быть 2 текстовых поля для ввода текста с именами inVal и inExp и динамическое текстовое поле txtResult. Остальную работу сделает скрипт.
![]() |
| Рис. 1. Простенький научный калькулятор (для просмотра щелкните по изображению) |
Пишем код
Сначала мы импортируем класс MathParser, а также другие необходимые классы. Отметим, что папка flashandmath должна находиться в той же папке, что и исходный файл приложения.
package
{
import flashandmath.as3.parsers.*;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.ui.Keyboard;
import teormech.utils.TextUtils;
public class Main extends Sprite
{
... var mpExp:MathParser = new MathParser(["x"]); var mpVal:MathParser = new MathParser([ ]);
var compobjExp:CompiledObject = new CompiledObject(); var compobjVal:CompiledObject = new CompiledObject();
// Данная строка строка взята из тела функции init()
stage.addEventListener( KeyboardEvent.KEY_DOWN, compute);
...
private function compute(kevt:KeyboardEvent):void {
if (kevt.keyCode != Keyboard.ENTER) {
return;
}
// «Захват» содержимого текстовых полей
var stVal:String = inVal.text;
var stExpression:String = inExp.text;
// «Компиляция» выражений, введенных пользователем
compobjVal = mpVal.doCompile(stVal);
compobjExp = mpExp.doCompile(stExpression);
// Проверка на наличие синтаксических ошибок
// во введенных выражениях.
// При возникновении ошибки в соответствующем
// текстовом поле выводится сообщение
if (compobjVal.errorStatus == 1) {
txtResult.text = compobjVal.errorMes;
stage.focus = inVal;
return;
}
if (compobjExp.errorStatus == 1) {
txtResult.text = compobjExp.errorMes;
stage.focus = inExp;
return;
}
// Вычисление значения выражения переменной
var xVal:Number = mpVal.doEval( compobjVal.PolishArray, [ ]);
// Вычисление значение выражения,
// зависящего от значения переменной
var resVal:Number =
mpExp.doEval( compobjExp.PolishArray, [xVal]);
// Вывод ответа с точностью то десятых долей.
txtResult.text = resVal.toFixed(10);
}
Так как выражение для анализатора mpVal не содержит переменных, то ему мы передали пустой массив, а для анализатора mpExp мы передали массив с одним элементом (содержащим значение этой переменной), т.к. это выражение содержит одну переменную.
Исходники к этому примеру можно взять здесь.
Пример 2. Использование класса MathParser для создания простой математической викторины
У класса MathParser может быть множество вариантов применения. Здесь мы рассмотрим простой пример, в котором осуществляется проверка ответа студента на вопросы с произвольно генерируемыми исходными данными (см. рис.2).
![]() |
| Рис. 2. Проверьте свои знания по школьной математике (для проверки щелкните по картинке) |
Идея, лежащая в основе проверки вводимого ответа, такова: программа берет numpoints значений переменной (в данном случае переменной x), лежащих в промежутке между значениями min и max, и сравнивает результаты вычисления «правильного» выражения (которое выводит сама программа) с результатами вычисления выражения, введенного пользователем при выбранных значениях переменной. Если все результаты вычислений отличаются не более чем на величину tolerance, то ответ считается правильным. Хотя это и ненадежный механизм для проверки алгебраических ответов, он достаточно хорошо работает в данных условиях, когда мы знаем, что ответы являются простыми многочленами. Устанавливая значения переменных numpoints, min, max, и tolerance в начале программы, мы можем более точно ее настраивать для каждого конкретного случая.
Настройки сцены
Чтобы создать описываемое приложение, Вам понадобится расположить на сцене несколько объектов: это ярлыки (labels), динамические текстовые поля (txtInitial, txtRecursivePart, txtResponseBox) и текстовое поле для ввода текста пользовательского ответа txtUserAnswer, а также кнопки btnCheck и btnNext.
Пишем код
Сперва мы импортируем необходимые классы (MathParser в их числе) и далее задаем значения переменных-параметров нашей программы, предназначенных для проверки ответа:
package
{
import com.bit101.components.Label;
import com.bit101.components.PushButton;
import com.bit101.components.Style;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.ui.Keyboard;
import teormech.utils.TextUtils;
import flashandmath.as3.parsers.*;
public class Main extends Sprite
{
private var txtPts:TextField;
private var txtUserAnswer:TextField;
private var txtResponseBox:TextField;
private var btnCheck:PushButton;
private var btnNext:PushButton;
private var numpoints:Number = 12;
private var tolerance:Number = 0.0000001;
private var min:Number = 2;
private var max:Number = 5;
private var stPt1:String;
private var stPt2:String;
private var stUserAnswer:String;
private var stCorrectAnswer:String;
...
private function nextProblem():void
{
var a:int;
var b:int;
var x1:int;
var y1:int;
var x2:int;
var y2:int;
/*
Выбираем случайные значения параметров для задачи,
лежащие в диапазоне {-2; 5}
*/
a = 5 - Math.floor(8*Math.random());
b = 5 - Math.floor(8*Math.random());
x1 = 5 - Math.floor(8*Math.random());
x2 = 5 - Math.floor(8*Math.random());
if (x1 == x2) {
x2 = x1 + 1;
}
y1 = a*x1 + b;
y2 = a*x2 + b;
stCorrectAnswer = String(a) + "*x + " + String(b);
txtPts.text = "(" + String(x1) + ", " + String(y1) +
") and (" + String(x2) + ", " + String(y2) + ").";
txtResponseBox.text = "";
txtUserAnswer.text = "";
}
private function checkAnswer():void
{
// Проверка – был ли введен ответ. Если нет,
// то ничего не делаем
var stUserAnswer:String = txtUserAnswer.text;
if (stUserAnswer.length == 0) {
return;
}
// Осуществляем анализ введенного пользователем
// и правильного выражений
var procFun:MathParser = new MathParser(["x"]);
var corrCO:CompiledObject= procFun.doCompile(stCorrectAnswer);
var userCO:CompiledObject = procFun.doCompile(stUserAnswer);
// Сообщаем об ошибке, если какое-либо из выражений
// содержит синтаксическую ошибку
if (userCO.errorStatus == 1) {
txtResponseBox.text =
"Ошибка синтаксиса в пользовательском ответе. " +
userCO.errorMes;
return;
}
if (corrCO.errorStatus == 1) {
txtResponseBox.text =
"Ошибка синтаксиса в программном ответе. " +
corrCO.errorMes;
return;
}
/* Выбираем значения переменной x и интервала [min; max]
и находим значения y для выражений введенных пользователем
и правильного ответа. Если ответы различаются более, чем
на величину переменной tolerance, то мы знаем, что ответ
неправильный.
*/
var thisX:Number;
var userY:Number;
var corrY:Number;
var i:Number;
for (i = 0; i < numpoints; i++)
{
thisX = min + i*(max - min)/numpoints;
userY = procFun.doEval(userCO.PolishArray,[thisX]);
corrY = procFun.doEval(corrCO.PolishArray,[thisX]);
if (Math.abs(userY - corrY) > tolerance)
{
var incorrectTextFormat:TextFormat =
new TextFormat("Arial", "18", 0xff0000);
txtResponseBox.text = "Неправильно";
txtResponseBox.setTextFormat(incorrectTextFormat);
return;
}
}
// Если же мы не нашли ошибки, то ответ правильный
txtResponseBox.text = "Правильно!";
txtResponseBox.setTextFormat(txtResponseBox.defaultTextFormat);
}
btnCheck.addEventListener( MouseEvent.CLICK, btnCheckPressed);
stage.addEventListener( KeyboardEvent.KEY_DOWN, keyPressed);
...
private function btnCheckPressed(e:MouseEvent):void {
checkAnswer();
}
function keyPressed(evt:KeyboardEvent):void {
// Проверка ответа срабатывает только при нажатии
// на ENTER
if (evt.keyCode == Keyboard.ENTER) {
checkAnswer();
}
}
nextProblem();
UPD: В исходных классах пакета flashandmath у многих переменных отсутствует типизация, если работать во Flash IDE, то никаких проблем не возникает, но если вы разрабатываете приложения с помощью Flex SDK, то компилятор ругается на отсутствие типизации переменных и идентификаторов, поэтому мне пришлось потратить немного времени для устранения этой проблемки. Классы пакета flashandmath, включенные в исходники к примерам отличаются от официальных лишь добавлением типизации.


Комментариев нет:
Отправить комментарий