📜 ⬆️ ⬇️

In retro style: J2ME on TCL


After I could not answer the call in the daughter's phone, I decided that something had to be done. Experts say that all is not lost and with the help of special technologies you can keep up with the younger generation. One such tool is N-Back . Since I can’t do it with a cell phone with a token (a vicious circle is obtained), I tried to find such an application under J2ME. I did not find it and decided to write it myself. But the problem is that Scala and Clojure do not support J2ME, and it will be hard for me to learn Java without having trained on a program that has not yet been written. After some googling, a solution was found - Hecl , slightly reworked Tcl .

I must say that I programmed on Tcl for a very long time - then I worked on an SGI O2 computer and envied those who could play “lines” (they are also “balls”). I am not very pretentious about the appearance of applications, and with the help of Tcl with the Tk library I solved this problem.
Tcl is a simple imperative scripting language, syntax-like Unix Shell (and sometimes used as its quality). By extensibility it can be compared with Fort and Lisp. The ease of embedding it in C applications has made it popular among CAD developers.
Hecl inherited many of the features of Tcl, it is only integrated with Java applications, and not on C. The development of a REPL simplifies the development, in contrast to the classic tclsh that supports command history and line editing.
The Hecl site has a ready-made MIDlet with examples and even a minimal development environment. In the jar-archive there is a file script.hcl - it is enough to change it (do not forget to correct .jad), so that you can run your script on the J2ME-platform.

So, let's begin. We need to get a random character.
set alph {ACGT} set alphsize [llen $alph] proc rand {} { global alph alphsize lindex $alph [* [random] $alphsize] } 

Variable assignment is done with the set command. The variable variable name is written simply as in Python, and when used, it is necessary to add '$', as in Perl. If you wish, you can write
 set aaa bbb set $aaa ccc 
and the variable bbb is assigned the value "ccc".
Strings, as in the Unix Shell, usually do not need to be enclosed in quotes. If you still have to, in addition to the usual double quotes, you can use balanced curly braces ({}) - strings can be "nested".
The string is broken down by spaces (you get a list) and the first word is interpreted as the name of the procedure - here Tcl is a bit like Lisp. Enclosed calls to other commands are enclosed in square brackets ([]).
Commands + and * are new to Hecl. The original Tcl had to call a special DSL.
 expr 1 + 2 * 3 
almost like in Shell (only * no escaping needed).

A bit of psychology and terver
In this N-Back implementation, characters from a small alphabet are used with equal probability. If you increase the alphabet, then matches will become very rare and it will become too boring to play. It is possible to make the generation of symbols by a more complex Markov process (the probability depends on the changing state), which will make the matches quite frequent. There is another interesting point here - how much the brain can analyze hidden Markov models and take into account the Baesian probability when recognizing coincidences. Instead of symbols, you can use pictures (Chinese characters or chemical formulas - we combine training with memorization) or sounds.

')
 set nback {aa aa} set last "" proc getnext {} { global nback last set nbach [lappend [lset $nback 0] $last] set last [rand] return $last } proc first {} { global nback last eq $last [lindex $nback 0] } 

N in the name N-Back is given by the initial length of the list. N == 2 is enough for me :-).
The initial values ​​of the history are chosen not coinciding with the symbols of the alphabet for simplification. Since I did not pursue the beauties, the first N-1 characters generated to fill the buffer will go to the guess counter.

 set stats {0 0 0 0} proc update k { global stats lset $stats $k [1+ [lindex $stats $k]] set stats } 

The procedure for calculating statistics. 1+ - the name of the function of adding one. The stats array stores the number of successfully noticed mismatches, erroneously noticed mismatches, erroneously noticed matches, and successfully noticed matches. Such a sequence was chosen from the convenience of implementation, but it turned out to be convenient for perception.

The following code I skargokultil from the original script.hcl
 proc PrintLn {g txt} { global MIDL $g clear $g string [list 4 $MIDL] $txt nw } proc EventHandler {ce} { global last MIDL set reason [$e cget -reason] if {!= 5 $reason} {return} set MIDL [/ [$c cget -height] 2] set keycode [$e cget -keycode] set res [first] set sym [getnext] set g [$c graphics] set k [eq 49 $keycode] if {eq $k $res} { PrintLn $g "[update [+ $res $res $k]] Ok $last" } else { PrintLn $g "[update [+ $res $res $k]] Fail $last" } } set c [lcdui.canvas -title "N-Back" -fullscreen 1 -eventhandler EventHandler] $c setcurrent 

Here you can observe the object-oriented properties of Tcl - the object is masked by the procedure stored in the variable, and the messages are marked with string constants in the arguments. The “constructor” lcdui.canvas creates a “canvas object” and hangs an event handler on it. My handler recognizes events with cause 5 (keystroke). The key "1" is treated as a noticed coincidence, the rest - as a noticed mismatch. I'm not sure that the choice is good, but laziness is experimenting - the procedure of downloading it to the phone is the most difficult in all development :-).

In general, Hecl can be recommended for rapid development / prototyping and as a language embedded in Java applications, including for legacy platforms.

Source: https://habr.com/ru/post/206834/


All Articles