/////////////////////////////////////////////////////////////////////
//
// Aritm by M.O.B. as Java ME MIDlet app for mobile phones.
// Copyright (C) 1992-2007 by Mikael O. Bonnier, Lund, Sweden.
// License: GNU GPL v3 or later, http://www.gnu.org/licenses/gpl-3.0.txt
// Donations are welcome to PayPal mikael.bonnier@gmail.com.
// The source code is at .
//
// It was developed in J2ME (Java) using WTK-2.2 [patch 200511] and JDK 1.5.0_09 on
// Windows 2000. The jar-file was generated using the default obfuscator ProGuard 3.7
// using default settings. This file does also compile using WTK-2.5.2 and JDK 1.6.0_06 on
// Kubuntu Hardy Heron.
//
// Revision history:
// 1992: MS-DOS version in C.
// 1997-Feb: 1.0bX Beta versions as Java SE applet and application.
// 2007: 0.5 for mobile phones with Java ME.
//
// Suggestions, improvements, and bug-reports
// are always welcome to:
// Mikael Bonnier
// Osten Undens gata 88
// SE-227 62 LUND
// SWEDEN
//
// Or use my electronic addresses:
// Web: http://www.df.lth.se.orbin.se/~mikaelb/
// E-mail/MSN: mikael.bonnier@gmail.com
// ICQ # 114635318
// Skype: mikael4u
// _____
// / / \
// ***********/ / \***********
// / / \
// *********/ / \*********
// / / / \ \
// *******/ / / \ \*******
// / / / \ \ \
// *****/ / /***\ \ \*****
// / /__ /_____\ \ \
// ***/ \ \ \***
// /_________________\ \ \
// **\ \ /**
// \______________________\/
//
// Mikael O. Bonnier
/////////////////////////////////////////////////////////////////////
import java.io.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.*;
import java.util.Random;
public class Aritm extends MIDlet implements ItemStateListener, CommandListener {
private final String _sHelpText =
"Aritm trains you in simple mental calculation. This program teaches"
+ " its users the addition, subtraction, multiplication, and division"
+ " tables. It employs a very effective method, which makes the process"
+ " short with these useful tables. If you know these tables it is much"
+ " easier to follow the mathematics education. Further more, you can use"
+ " them in everyday situations, especially if you also know rough"
+ " estimate calculation. These tables, neither more nor less, is"
+ " everything you need to know by heart, because there are manual"
+ " methods for calculating with more complicated numbers. It is always"
+ " good to do an Aritm workout before you are going to a math test."
// + " Also, you can use Aritm to train calculation in foreign languages."
+ " You can mix the problems anyway you like, e.g. you can choose"
+ " addition and multiplication at the same time.\n\n"
+ "A d d i t i o n\n"
+ "(1) The sum of two single digit terms.\n"
+ "(2) The sum of one double digit and one single digit term.\n\n"
+ "S u b t r a c t i o n\n"
+ "(1) The difference of two small terms.\n"
+ "(2) The difference of one larger term and one smaller.\n"
+ "(From) The problem is written M from N, instead of N-M.\n\n"
+ "M u l t i p l i c a t i o n\n"
+ "The product of two single digit factors.\n\n"
+ "D i v i s i o n\n"
+ "The quotient between two numbers. The dividend (numerator)"
+ " is usually larger than the divisor (denominator).\n\n"
+ "S t a r t / S t o p\n"
+ "When you have checked which problems you want, you select START,"
+ " and write the answer using digits and select ENTER. If your answer"
+ " is incorrect, you will get that problem again, later. If you want"
+ " to end prematurely, select STOP. You should make about 10 problems"
+ " per minute or more. "
+ " You may pause and the clock is stopped during the pause.\n\n"
+ "Aritm is also available as a Java applet with more features at"
+ " . Welcome!" ;
private List _lstMenu;
private Form _frmProblem;
private TextField _tfProblem;
private StringItem _siResult;
private Form _frmProblemsChoice;
private ChoiceGroup _chgAdd, _chgSub, _chgChoice, _chgDiv;
private boolean _bAddSave, _bSubSave, _bMulSave, _bDivSave;
private ChoiceGroup _chgAddLev, _chgSubLev;
private boolean _bAddLevSave[] = new boolean[2], _bSubLevSave[] = new boolean[3];
private StringItem _siNoOfProblems;
private Command _cmdExit, _cmdSelect, _cmdMenu, _cmdEnter, _cmdStop, _cmdStart,
_cmdCancel, _cmdOk;
private String _sLanguage = "enu";
private String _sGood;
private String _sProbPerMin;
private String _sNotFin;
private String _sProblems;
private String _sAdd;
private String _sSub;
private String _sFrom;
private String _sMul;
private String _sDiv;
private String _sArabic;
private String _sWords;
private String _sRoman;
private String _sStart;
private String _sStop;
private String _sTryAgain;
private String _sRight;
private String _sProbsLeft;
private String _sWrong;
private String _sIs;
private String _sIntPart;
private String _sDividedBy;
private String _sSFrom;
private String _sPlus;
private String _sMinus;
private String _sTimes;
private String _sFromSuffix;
private char MULSIGN;
private char DIVSIGN;
private final int MAXPROB = 590;
private Problem _prob[] = new Problem[MAXPROB];
private int _index[] = new int[MAXPROB];
private int _nUsedIndices;
private int _iCurrent;
private int _iIndex;
private boolean _bRunning = false;
private String _sProblem;
private Random _rand = new Random();
private int _total; // Total number of Problems asked so far.
private long _lStart;
private long _lPause;
private final int REQD = 1; // Number of times a Problem must be answered correctly
// before it is removed from active part of _prob[].
public Aritm() {
_sGood = "Good!!! You made ";
_sProbPerMin = " problems/minute.";
_sNotFin = "Not finished. You made ";
_sProblems = " problems.";
_sAdd = "Addition";
_sSub = "Subtraction";
_sFrom = "From";
_sMul = "Multiplication";
_sDiv = "Division";
_sTryAgain = "Try again.";
_sRight = "Right! ";
_sProbsLeft = " problems left.";
_sWrong = "Wrong. ";
_sIs = " is ";
_sIntPart = "The integer part of ";
_sSFrom = " from ";
_sFromSuffix = "";
MULSIGN = '×';
DIVSIGN = '÷';
String[] stringElements = {"START", "SETUP", "HELP", "ABOUT"};
String sFilename = "/Aritm.png";
Image[] imageElements = {loadImage(sFilename), loadImage(sFilename),
loadImage(sFilename), loadImage(sFilename)};
_lstMenu = new List("Aritm", List.IMPLICIT,
stringElements, imageElements);
_cmdSelect = new Command("SELECT", Command.OK, 0);
_cmdExit = new Command("EXIT", Command.EXIT, 0);
_lstMenu.addCommand(_cmdSelect);
_lstMenu.addCommand(_cmdExit);
_lstMenu.setCommandListener(this);
_frmProblem = new Form("Aritm/Problem");
_cmdMenu = new Command("MENU", Command.BACK, 2);
_cmdEnter = new Command("ENTER", Command.OK, 0);
_cmdStop = new Command("STOP", Command.SCREEN, 1);
_cmdStart = new Command("START", Command.SCREEN, 1);
_frmProblem.addCommand(_cmdMenu);
_frmProblem.setCommandListener(this);
_tfProblem = new TextField("", "", 3, TextField.NUMERIC);
_frmProblem.append(_tfProblem);
_siResult = new StringItem(null, "");
_frmProblem.append(_siResult);
_frmProblemsChoice = new Form("Aritm/Setup");
_cmdCancel = new Command("CANCEL", Command.CANCEL, 0);
_cmdOk = new Command("OK", Command.OK, 0);
_frmProblemsChoice.addCommand(_cmdCancel);
_frmProblemsChoice.addCommand(_cmdOk);
_frmProblemsChoice.setCommandListener(this);
_chgAdd = new ChoiceGroup(null, Choice.MULTIPLE);
_chgAdd.append(_sAdd, null);
_chgAdd.setSelectedIndex(0, true);
_frmProblemsChoice.append(_chgAdd);
_chgAddLev = new ChoiceGroup(null, Choice.MULTIPLE);
String sSpacer = " ";
_chgAddLev.append(sSpacer + "1", null);
_chgAddLev.append(sSpacer + "2", null);
// _chgAddLev.setLayout(Item.LAYOUT_2 | Item.LAYOUT_LEFT | Item.LAYOUT_SHRINK);
_chgAddLev.setSelectedIndex(0, true);
_frmProblemsChoice.append(_chgAddLev);
_chgSub = new ChoiceGroup(null, Choice.MULTIPLE);
_chgSub.append(_sSub, null);
_frmProblemsChoice.append(_chgSub);
_chgSubLev = new ChoiceGroup(null, Choice.MULTIPLE);
_chgSubLev.append(sSpacer + "1", null);
_chgSubLev.append(sSpacer + "2", null);
_chgSubLev.append(sSpacer + _sFrom, null);
// _chgSubLev.setLayout(Item.LAYOUT_2 | Item.LAYOUT_LEFT | Item.LAYOUT_SHRINK);
_chgSubLev.setSelectedIndex(0, true);
_frmProblemsChoice.append(_chgSubLev);
_chgChoice = new ChoiceGroup(null, Choice.MULTIPLE);
_chgChoice.append(_sMul, null);
_frmProblemsChoice.append(_chgChoice);
_chgDiv = new ChoiceGroup(null, Choice.MULTIPLE);
_chgDiv.append(_sDiv, null);
_frmProblemsChoice.append(_chgDiv);
_siNoOfProblems = new StringItem(null, "");
_frmProblemsChoice.append(_siNoOfProblems);
_frmProblemsChoice.setItemStateListener(this);
itemStateChanged(_chgAdd);
}
public void startApp() {
if(_bRunning) {
_lStart += System.currentTimeMillis() - _lPause;
Display.getDisplay(this).setCurrent(_frmProblem);
}
else
Display.getDisplay(this).setCurrent(_lstMenu);
}
public void pauseApp()
{
if(_bRunning)
_lPause = System.currentTimeMillis();
else {
startCmds();
}
}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s)
{
if(c == _cmdSelect || c == List.SELECT_COMMAND) {
int i = _lstMenu.getSelectedIndex();
switch(i)
{
case 0: // START
Display.getDisplay(this).setCurrent(_frmProblem);
start();
break;
case 1: // SETUP
_bAddSave = _chgAdd.isSelected(0);
_bSubSave = _chgSub.isSelected(0);
_bMulSave = _chgChoice.isSelected(0);
_bDivSave = _chgDiv.isSelected(0);
_chgAddLev.getSelectedFlags(_bAddLevSave);
_chgSubLev.getSelectedFlags(_bSubLevSave);
Display.getDisplay(this).setCurrent(_frmProblemsChoice);
break;
case 2: // HELP
Alert alrHelp = new Alert("Aritm/Help", _sHelpText, null, AlertType.INFO);
alrHelp.setTimeout(Alert.FOREVER);
Display.getDisplay(this).setCurrent(alrHelp, _lstMenu);
break;
case 3: // ABOUT
Runtime rt = Runtime.getRuntime();
Alert alrAbout = new Alert("About Aritm v." + getAppProperty("MIDlet-Version"),
"This program \"Aritm\" is Copyright © 1997-2007 by Mikael O. Bonnier, Lund, Sweden"
+" ."
+ " All rights reserved.\n"
+ "DISCLAIMER: THIS PROGRAM IS USED AT YOUR OWN RISK.\n"
+ "Free mem: " + rt.freeMemory() + " B\n"
+ "Total mem: " + rt.totalMemory() + " B\n"
+ "Profiles: " + System.getProperty("microedition.profiles") + '\n'
+ "Config: " + System.getProperty("microedition.configuration") + '\n'
+ "Encoding: " + System.getProperty("microedition.encoding") + '\n'
+ "Locale: " + System.getProperty("microedition.locale") + '\n',
null, AlertType.INFO);
alrAbout.setTimeout(Alert.FOREVER);
Display.getDisplay(this).setCurrent(alrAbout, _lstMenu);
break;
default:
Alert alert = new Alert("Your selection",
"You chose " + _lstMenu.getString(i) + ".",
null, AlertType.INFO);
Display.getDisplay(this).setCurrent(alert, _lstMenu);
}
}
else if(c == _cmdOk)
Display.getDisplay(this).setCurrent(_lstMenu);
else if(c == _cmdCancel) {
_chgAdd.setSelectedIndex(0, _bAddSave);
_chgSub.setSelectedIndex(0, _bSubSave);
_chgChoice.setSelectedIndex(0, _bMulSave);
_chgDiv.setSelectedIndex(0, _bDivSave);
_chgAddLev.setSelectedFlags(_bAddLevSave);
_chgSubLev.setSelectedFlags(_bSubLevSave);
Display.getDisplay(this).setCurrent(_lstMenu);
}
else if(c == _cmdMenu) {
startCmds();
Display.getDisplay(this).setCurrent(_lstMenu);
}
else if(c == _cmdExit)
notifyDestroyed();
else if(c == _cmdEnter && _bRunning)
if(!check())
stop();
else
ask();
else if(c == _cmdStop)
stop();
else if(c == _cmdStart)
start();
else
debug(c);
}
void start()
{
generate();
_total = 0;
_siResult.setText(_nUsedIndices + _sProblems);
ask();
_lStart = System.currentTimeMillis();
_bRunning = true;
startCmds();
}
void startCmds() {
_frmProblem.removeCommand(_cmdStart);
_frmProblem.addCommand(_cmdStop);
_frmProblem.addCommand(_cmdEnter);
}
void stop()
{
displayScore();
_bRunning = false;
_frmProblem.removeCommand(_cmdEnter);
_frmProblem.removeCommand(_cmdStop);
_frmProblem.addCommand(_cmdStart);
}
public void itemStateChanged(Item item)
{
_siNoOfProblems.setText(String.valueOf(countProblems()) + _sProblems);
debug("itemStateChanged" + item);
}
boolean debug(Object o) {
// System.out.println("Debug!" + o);
return true;
}
void displayScore()
{
long lStop = System.currentTimeMillis();
if(_nUsedIndices == 0)
{
// bell(880); bell(1108.73); bell(1318.51); bell(1760);
_siResult.setText(_sGood + (_total*60000)/(lStop-_lStart) + _sProbPerMin);
}
else
_siResult.setText(_sNotFin + (_total*60000)/(lStop-_lStart) + _sProbPerMin);
}
private Image loadImage(String name)
{
Image image = null;
try {
image = Image.createImage(name);
}
catch (IOException ioe) {
// System.out.println(ioe);
}
return image;
}
int countProblems()
{
int nProblems = 0;
if(_chgAdd.isSelected(0))
{
if(_chgAddLev.isSelected(0))
nProblems += 100;
if(_chgAddLev.isSelected(1))
nProblems += 100;
}
if(_chgSub.isSelected(0))
{
if(_chgSubLev.isSelected(0))
nProblems += 100;
if(_chgSubLev.isSelected(1))
nProblems += 100;
}
if(_chgChoice.isSelected(0))
nProblems += 100;
if(_chgDiv.isSelected(0))
nProblems += 90;
return nProblems;
}
void generate()
{
_nUsedIndices = _iIndex = 0;
if(_chgAdd.isSelected(0))
{
if(_chgAddLev.isSelected(0))
genAdd(0);
if(_chgAddLev.isSelected(1))
genAdd(1);
}
if(_chgSub.isSelected(0))
{
if(_chgSubLev.isSelected(0))
if(!_chgSubLev.isSelected(2))
genSub(0);
else
genSub(1);
if(_chgSubLev.isSelected(1))
if(!_chgSubLev.isSelected(2))
genSub(2);
else
genSub(3);
}
if(_chgChoice.isSelected(0))
genMul();
if(_chgDiv.isSelected(0))
genDiv();
for(int i = 0; i < _nUsedIndices; ++i)
_index[i] = i;
shuffle();
}
void genAdd(int mod)
{
int i, j;
for(i=0; i<=9; ++i)
for(j=0; j<=9; ++j) {
_prob[_nUsedIndices] = new Problem();
_prob[_nUsedIndices].op1 = (mod==1 ? 10*((_rand.nextInt() & Integer.MAX_VALUE)%8+1) : 0)
+ i;
_prob[_nUsedIndices].sign = '+';
_prob[_nUsedIndices].op2 = j;
_prob[_nUsedIndices].ans = _prob[_nUsedIndices].op1+j;
_nUsedIndices++;
}
}
void genSub(int mod)
{
int i, j;
for(i=0; i<=9; ++i)
for(j=i; j<=9+i; ++j)
{
_prob[_nUsedIndices] = new Problem();
_prob[_nUsedIndices].op1 = (mod==2 || mod==3 ? 10*((_rand.nextInt()
& Integer.MAX_VALUE)%9+1) : 0)+j;
_prob[_nUsedIndices].sign = mod==1 || mod==3 ? 'f' : '-';
_prob[_nUsedIndices].op2 = i;
_prob[_nUsedIndices].ans = _prob[_nUsedIndices].op1-i;
_nUsedIndices++;
}
}
void genMul()
{
int i, j;
for(i=0; i<=9; ++i)
for(j=0; j<=9; ++j)
{
_prob[_nUsedIndices] = new Problem();
_prob[_nUsedIndices].op1 = i;
_prob[_nUsedIndices].sign = MULSIGN;
_prob[_nUsedIndices].op2 = j;
_prob[_nUsedIndices].ans = i*j;
_prob[_nUsedIndices].correct = 0;
_nUsedIndices++;
}
}
void genDiv()
{
int q, d;
for(q=0; q<=9; ++q)
for(d=1; d<=9; ++d)
{
_prob[_nUsedIndices] = new Problem();
_prob[_nUsedIndices].op1 = q*d+(_rand.nextInt() & Integer.MAX_VALUE)%d;
_prob[_nUsedIndices].sign = DIVSIGN;
_prob[_nUsedIndices].op2 = d;
_prob[_nUsedIndices].ans = q;
_nUsedIndices++;
}
}
void ask()
{
_iCurrent = _index[_iIndex];
_sProblem = expandProblem(_iCurrent);
_tfProblem.setLabel(_sProblem);
_tfProblem.setString("");
Display.getDisplay(this).setCurrentItem((Item)_tfProblem);
}
boolean check()
{
int nAns;
String sAns = _tfProblem.getString();
if(sAns.length() == 0)
{
// bell(ATTNFQ);
_siResult.setText(_sTryAgain);
return true;
}
++_total;
nAns = Integer.parseInt(sAns);
if(nAns == _prob[_iCurrent].ans)
{
++_prob[_iCurrent].correct;
int nLeft = 0;
for(int i = 0; i < _nUsedIndices; ++i) {
nLeft = nLeft + REQD - _prob[_index[i]].correct;
}
_siResult.setText(_sRight + nLeft + _sProbsLeft);
++_iIndex;
}
else
{
--_prob[_iCurrent].correct;
// bell(ATTNFQ);
_siResult.setText(_sWrong + _sProblem.substring(0, _sProblem.length() - 1) + _sIs +
_prob[_iCurrent].ans + ".");
packArray();
shuffle();
_iIndex = 0;
}
if(_iIndex >= _nUsedIndices)
{
_iIndex = 0;
return packArray();
}
return true;
}
boolean packArray()
{
int i, j, n = 0;
for(i = 0; i < _nUsedIndices; ++i)
{
j = _index[i];
if(_prob[j].correct < REQD)
_index[n++] = j;
}
_nUsedIndices = n;
return _nUsedIndices != 0;
}
void shuffle()
{
int i, j, temp;
for(i = 0; i < _nUsedIndices; ++i)
{
j = (_rand.nextInt() & Integer.MAX_VALUE) % _nUsedIndices;
temp = _index[i];
_index[i] = _index[j];
_index[j] = temp;
}
}
String expandProblem(int indx)
{
StringBuffer sRet;
switch(_prob[indx].sign)
{
case '/':
case '÷':
sRet = new StringBuffer(_sIntPart + _prob[indx].op1 + _prob[indx].sign +
_prob[indx].op2 + "=");
break;
case 'f':
sRet = new StringBuffer(String.valueOf(_prob[indx].op2) + _sSFrom + _prob[indx].op1 +
_sFromSuffix + "=");
break;
default:
sRet = new StringBuffer(String.valueOf(_prob[indx].op1) + _prob[indx].sign +
_prob[indx].op2 + "=");
} // switch
return sRet.toString();
}
}
class Problem
{
protected int op1;
protected char sign;
protected int op2;
protected int ans;
protected int correct;
}