# Javascript example: CubeTimer. Reviews?



## Stefan (Nov 19, 2009)

I'm learning Javascript and wrote a minimalistic cube timer as exercise:
http://stefan-pochmann.info/ptimer/STimer.html

I'm pretty happy with the result and the code, but I'd appreciate if more experienced Javascript coders could have a look and tell me whether I'm doing something badly. Especially I'd like to know whether the time formatting can be done better, I really hate that part but couldn't find a better way.

I thought about asking in a Javascript forum and I still might, but I guess I'd have to explain some cube stuff to them. Also, maybe other cubers new to programming are interested in having a look at a timer with a manageable amount of code like this.


----------



## joey (Nov 19, 2009)

Put it in the <head></head>?


----------



## Escher (Nov 19, 2009)

I just got in a scramble:
R' D2 F' D R2 D2 U B2 D' *L R' L' R *B2 F2 U R D R F2 D' B2 U2 F2 L2

I'm not programmer, but that isn't good right?


----------



## Stefan (Nov 19, 2009)

Oops. Should prevent canceling. Looking into that.
Also looking into whether it should go into the head.


----------



## Edward (Nov 19, 2009)

Im no coder, but I like the simplistic design. Now all you have to do is figure out averages, different puzzles, and cardboard stackmat functionality. I hope you figure out what ever problem you have right now, I cant really help.

And you kind of have to make it so that you have to press 2 buttons, or the spacebar to stop it. I found I can start and stop it by pressing only 1 button the keyboard.


----------



## Stefan (Nov 19, 2009)

The move canceling should be fixed. Forgot that "/" doesn't round in Javascript. Using "%" now.


----------



## Stefan (Nov 19, 2009)

joey said:


> Put it in the <head></head>?


Ok, as far as I understand, this is only necessary if something in the early HTML calls Javascript that comes later. Because then the Javascript might not be ready yet. Since I don't do that, I think I'm safe. Or not?


----------



## joey (Nov 19, 2009)

It wasn't really a "lol this doesn't work" thing, it was more it's "standard" to put most/as much as possible of the javascript into the head.


----------



## Stefan (Nov 19, 2009)

Edward said:


> And you kind of have to make it so that you have to press 2 buttons, or the spacebar to stop it. I found I can start and stop it by pressing only 1 button the keyboard.


You should be able to use the space bar. Does it not work?

Requiring two keys would make things more complicated and I wanted to keep this program minimalistic, hence the single-key usage.


----------



## Edward (Nov 19, 2009)

StefanPochmann said:


> Edward said:
> 
> 
> > And you kind of have to make it so that you have to press 2 buttons, or the spacebar to stop it. I found I can start and stop it by pressing only 1 button the keyboard.
> ...



Yes the space bar works.


----------



## JBCM627 (Nov 19, 2009)

This bit of code:
document.onkeydown = null;
window.setTimeout( 'document.onkeyup = startTimer', 1000 )​is an interesting way to fix the timer from starting on keyup... I wouldn't have thought of that. Maybe try changing it so it disables the next onkeyup completely.


----------



## Stefan (Nov 19, 2009)

joey said:


> It wasn't really a "lol this doesn't work" thing, it was more it's "standard" to put most/as much as possible of the javascript into the head.


Ok, I see. Good practice. I changed it, is it good now?
http://stefan-pochmann.info/ptimer/STimer.html
(old: http://stefan-pochmann.info/ptimer/STimerOld.html)



JBCM627 said:


> This bit of code:
> document.onkeydown = null;
> window.setTimeout( 'document.onkeyup = startTimer', 1000 )​is an interesting way to fix the timer from starting on keyup... I wouldn't have thought of that. Maybe try changing it so it disables the next onkeyup completely.


I think you might have misread. I disable onkey*down* there, onkey*up* already gets disabled when timing starts.

The idea is that always only one of them is active and they switch at start/stop of solve. Except the switch at stopping is delayed to prevent accidental restarting by hitting the key twice or hitting several keys. So for one second, neither keyup nor keydown are active.


----------



## qqwref (Nov 19, 2009)

It looks kinda like a very very early version of my timer  I don't see any problems with the code although your scrambling code is quite opaque to me. (If the regular expressions are for replacing the 1 in your scrambles, I'd suggest ["","'","2"][Math.floor(3*Math.random())] instead of "12'".charAt(3*Math.random()). It's slightly longer but doesn't need to be corrected later.)


----------



## JBCM627 (Nov 19, 2009)

StefanPochmann said:


> Except the switch at stopping is delayed to prevent accidental restarting by hitting the key twice or hitting several keys. So for one second, neither keyup nor keydown are active.


Ok, I think I did misunderstand. But a consequence of this is that once you have held down a key to stop the timer for over a second, it will start again once you pick that key up.


----------



## Stefan (Nov 19, 2009)

qqwref said:


> It looks kinda like a very very early version of my timer


I guess that's a good sign 



qqwref said:


> your scrambling code is quite opaque to me.


Yeah well, sometimes I'm a bit of a short-code-geek. I don't think it's that bad, though, is it? I mean, I'm not even using ">>0" instead of Math.flloor().



qqwref said:


> I'd suggest ["","'","2"][Math.floor(3*Math.random())] instead of "12'".charAt(3*Math.random()).


Ah, thanks. Didn't know how to use arrays yet. It's actually shorter now. The other reason was to get rid of the space prefix. I'd like to just say ".trim()" but since that apparently doesn't exist (what the ****?!?), I just keep the space and threw out the replacing altogether.



JBCM627 said:


> But a consequence of this is that once you have held down a key to stop the timer for over a second, it will start again once you pick that key up.


True. But who does that?


----------



## Cride5 (Nov 19, 2009)

Stefan, from your experience with computer solvers, would you consider it possible to implement a Javascript solver, capable on finding <25 move solutions in around 10 sec? And, would you consider using random-state scrambles in your timer?

Another feature which is missing from most (all?) web-based timers is a time breakdown feature. Blah's timer has a basic 2-stage one for BLD mode, but one with a user-defined number of stages would be much more useful to me, and probably many others.


----------



## Johannes91 (Nov 19, 2009)

I strongly prefer putting all JavaScript code in separate .js-files, separate from the HTML. They can be included with <script type="..." src="foo.js"></script>.


```
function startTimer ( event ) {
  ...
  key = event.which ? event.which : event.keyCode;
  ...
}
```

Here, key is a global variable. It stays alive after startTimer returns. To make it local (function scope), you have to use the var-keyword. You also use globals at a few other places similarly.


```
window.setTimeout( 'document.onkeyup = startTimer', 1000 );
```

This uses eval to execute the string. It can be avoided using a function instead of a string as the first argument. In this case it's not a big deal, but in general using functions instead of eval is better style. That way the code is checked at compile time.

If you plan to write something bigger, I *really* recommend learning and using JQuery or some other library. It hides all browser dependent things, like events, for you behind a nice interface. Debugging code that works fine in some browsers but not on others is incredibly annoying.

Edit:

```
timerId = window.setInterval( 'showTime()', 30 );
```

Much better this way:


```
timerId = window.setInterval( showTime, 30 );
```


----------



## Stefan (Nov 19, 2009)

Cride5 said:


> would you consider it possible to implement a Javascript solver, capable on finding <25 move solutions in around 10 sec?


Maybe. Normal Thistlethwaite supposedly averages 31.3 moves:
http://www.jaapsch.net/puzzles/compcube.htm
But I think this just picks the first optimal solution for each of the four steps. Checking out more solutions like Cube Explorer does should lead to shorter results. How short, I don't know. But yeah, actually I intend to implement this, though maybe not in Javascript at first as I'm not yet comfortable enough with it.



Cride5 said:


> And, would you consider using random-state scrambles in your timer?


Not in this one. This one's really just a little exercise for me and a demonstration for other Javascript/programmer beginners. I'm not going to extend this much. The idea is to support the functionality you see right now with the minimum amount of code.

I did try Herbert's Java Cube Explorer thing in my Java PTimer. It worked, but the first solve is a bit slow even on my relatively fast computer, so instead I wrote my own standard 25-moves generator. Maybe I'll put Herbert's stuff in there again, but another issue is that I'd have to find out how I'm allowed to do it.


----------



## deepSubDiver (Nov 19, 2009)

StefanPochmann said:


> True. But who does that?


I do, sometimes staring at the time or taking a deep breath before looking up.


----------



## Stefan (Nov 19, 2009)

Thanks for your suggestions, Johannes!

Separate .js file: Ok, I'll do that with larger projects. In this small one I still prefer it to be all in one file.

Global variables: Ah, so that's what "var" is for. Added a few now. Made my only local variable "scramble" global though so I can copy it to oldScramble simply from the variable rather than accessing the DOM.

setTimeout( 'document.onkeyup = startTimer', 1000 ): In this particular case I wouldn't want to have that simple statement somewhere else, separated from the preceding "document.onkeydown = null". But in general, especially for more code, I'll make an extra function. Didn't think of the compile-time checking advantage, but here the code is easy enough.

JQuery and other libraries: I'll definitely learn how to use them and do it. You're right, I was disappointed when I saw that even for checking the pressed key I have to look two ways. But this once, in this small program, I'm ok with it. I'd rather not include a library just for that.

setInterval( 'showTime()', 30 ) vs setInterval( showTime, 30 ): Ouch. I should've seen that.

Question: I hope the way I'm determining minutes and seconds works well. The idea is to separate them using only integers and only then divide and round the seconds. I was afraid that if I try to compute the minutes from the milliseconds by just dividing and rounding, I might get rounding errors and for example show "2" instead of "3" when it's like 2.999999999. What do you think about the way I did it, should that work like intended?


----------



## Stefan (Nov 19, 2009)

deepSubDiver said:


> I do, sometimes staring at the time or taking a deep breath before looking up.


Hmm. I'd really like to have it optimal and please everyone, but sadly I don't see how to do this without bloating the code too much...


----------



## Johannes91 (Nov 19, 2009)

eval vs function: JavaScript has anonymous functions and they are often used for this: setTimeout( function () { document.keyup = startTime; }, 1000 );. The keyword is a bit long, but at least better than defining and naming a function somewhere else in the code.

I'm not comfortable with floating point arithmetic and not sure what works and what doesn't. When I need integers, I often use Math.floor or Math.round almost everywhere and just hope for the best... Need to read this some day.

What about replacing
window.setTimeout( 'document.onkeyup = startTimer', 1000 );
with
document.onkeyup = function () { document.onkeyup = startTimer; };
? Seems to work here.


----------



## Cride5 (Nov 19, 2009)

StefanPochmann said:


> But yeah, actually I intend to implement this, though maybe not in Javascript at first as I'm not yet comfortable enough with it.



Nice to hear  

Javascript is clearly not the natural choice for implementing a computer solver, but I think building a good one in js would be of great benefit to the cubing community. A key challenge is Javascript's data storage efficiency, especially if the algorithm needs to store large lookup/pruning tables. Implementing the Kociemba lookup tables using a naive cube-state representation turned out to be infeasible, but if/when I find the time I'm going to modify the implementation to store cube-state in the lookup tables as strings. A single cube can be stored in a minimum of 7 characters in javascript. Even if this works, the implementation will still be very sluggish to initialise. I think a more memory efficient implementation needs to be found for Javascript.

Another project I've been working on is finding a heuristic which provides an accurate measure of a cube state's distance from the solved state. A perfect heuristic should lead to an optimal solver which runs in linear time. I've had some ideas and limited success, but I've as yet found nothing good enough for a direct route to the solution.



Cride5 said:


> Maybe I'll put Herbert's stuff in there again, but another issue is that I'd have to find out how I'm allowed to do it.



As far as I'm aware, using Herbert's Java implementation of the Two Phase algorithm is fine provide credit is given. This is what I did for my random-state scrambler, but the code is used as a library and not modified directly.


----------



## Stefan (Nov 19, 2009)

Johannes91 said:


> eval vs function: JavaScript has anonymous functions and they are often used for this: setTimeout( function () { document.keyup = startTime; }, 1000 );.


Ah, very nice! I'm familiar with that in general, but didn't think of it here.



Johannes91 said:


> Need to read this some day.


Ugh. I've seen that before. Probably when you mentioned it before. I really don't want to go through that. My understanding is that working with integers in floats is exact as long as they're relatively small (fit in the significand part) and there's no rounding.



Johannes91 said:


> What about replacing
> window.setTimeout( 'document.onkeyup = startTimer', 1000 );
> with
> document.onkeyup = function () { document.onkeyup = startTimer; };
> ? Seems to work here.


Whoa, wait... <thinks.../>... ok, that is cool, but it leads to accidental timer restarts by hitting and releasing two keys (or the same key twice). I really want the one second delay. I'm considering this:
document.onkeyup = function () { window.setTimeout( function () { document.onkeyup = startTimer; }, 1000 ); };
But ugh... this is not for the beginnerz.


----------



## Stefan (Nov 19, 2009)

Cride5 said:


> Javascript is clearly not the natural choice for implementing a computer solver, but I think building a good one in js would be of great benefit to the cubing community.


I agree, it would be very nice. I'm thinking of using Thistlethwaite with tables for bi-directional search for each step, so eight tables of rather small size (a few thousand entries). Then just combine those tables.


----------



## Stefan (Nov 19, 2009)

Booyah!

document.onkeyup = function () { document.onkeyup = null; window.setTimeout( function () { document.onkeyup = startTimer; }, 1000 ); };

That first waits for a keyup, then waits another second to allow starting again. But... it's not that much better than the original and it's a hell of a lot more complicated. Though... seems oddly straight-forward in hindsight.


----------



## Lucas Garron (Nov 20, 2009)

Cride5 and Stefan would probably be interested in this, and I hope Jeremy doesn't mind me linking to it.

Jeremy wrote a 3x3x3 RSS hack at the beginning of October. Problem is, he never got it to be fully cross-browser (essentially Chrome, FF, Safari, IE - both on Windows and Mac).
(This was supposed to work better, but fails for me.)


----------



## Stefan (Nov 20, 2009)

He connects Javascript to Herbert's solver through a small applet? Not bad, but also, well... still somewhat unsatisfying. Both versions produce good scrambles for me, btw, but the first shows the cubes unscrambled.


----------



## Johannes91 (Nov 20, 2009)

Cride5 said:


> ... I'm going to modify the implementation to store cube-state in the lookup tables as strings. A single cube can be stored in a minimum of 7 characters in javascript.


Humm, you're doing it wrong. The cube states are supposed to take _zero_ space. This is the whole point of indexing; you only store the values in an array, and find the one that corresponds to a given cube state using table[cubeToIndex(cubeState)].

I did some tests using spidermonkey, and an array of 10^7 values uses about 70 bytes (!) per number. It's probably using a hash table internally. I know some implementations are smarter and use a real array when initializing with new Array(size), but not all do that.

A string with 10^7 characters (all '.'), on the other hand, uses only one byte per character. This is what I meant earlier, to store the _table_, not cube states, in a string. I haven't tried other JavaScript engines and huge strings might cause problems in some of them, but it might work.



Cride5 said:


> Another project I've been working on is finding a heuristic which provides an accurate measure of a cube state's distance from the solved state. A perfect heuristic should lead to an optimal solver which runs in linear time. I've had some ideas and limited success, but I've as yet found nothing good enough for a direct route to the solution.


I'll be really impressed if you find anything good that doesn't rely on precomputed tables. I haven't given it much thought, but it just seems really hard/impossible.


----------



## Stefan (Nov 20, 2009)

StefanPochmann said:


> I'm thinking of using Thistlethwaite with tables for bi-directional search for each step, so eight tables of rather small size (a few thousand entries). Then just combine those tables.


That was stupid. My old Thisthethwaite implementation did do four bi-directional BFS searches, but of course I can only precompute tables for the backwards searches, as the goal is always the same but the start isn't.


----------



## Cride5 (Nov 22, 2009)

Johannes91 said:


> Cride5 said:
> 
> 
> > ... I'm going to modify the implementation to store cube-state in the lookup tables as strings. A single cube can be stored in a minimum of 7 characters in javascript.
> ...


... good point, move tables store cube state in coordinate form 
Still, the values stored in the move tables are natural numbers with ranges significantly lower than is justified by using 64-bit numbers. From my understanding, the largest move tables are URFtoDLF and URtoDF. Each need to store values up to 8!/(8-6)!-1 = 20159 (15-bits). Pruning tables only need to store values up to 18-1 (so 5-bits per entry). 



Johannes91 said:


> A string with 10^7 characters (all '.'), on the other hand, uses only one byte per character.



In js I'm quite sure 16-bits are used for each character, to allow for unicode. I'm not sure if this is standard across all implementations, but I'd be surprised if it wasn't. This would mean that move tables would conveniently be able to store 1 entry per character, and pruning tables would be able to store 3 entries per character.

The result would be that the largest move tables would require strings of length 20160 (~40Kb) and the largest pruning table (541284 entries) would be storable in 180428 characters (~361Kb). Further compression could be achieved by allowing entries to be stored between two characters, but the extra overhead involved with lookups probably wouldn't be worth the small saving in space.



Johannes91 said:


> Cride5 said:
> 
> 
> > Another project I've been working on is finding a heuristic which provides an accurate measure of a cube state's distance from the solved state. A perfect heuristic should lead to an optimal solver which runs in linear time. I've had some ideas and limited success, but I've as yet found nothing good enough for a direct route to the solution.
> ...



A heuristic I found was able to solve some scrambles up to about 10 moves linearly. Larger scrambles often hit local maxima, so I wasn't able to get it to work perfectly. Just to give you an example of where I got with it, here is an optimal random-state scramble from cube explorer along with the measured heuristic distance of each state:

12: B 
43: B L 
190: B L F' 
310: B L F' D 
356: B L F' D U' 
968: B L F' D U' B' 
1480: B L F' D U' B' F' 
1937: B L F' D U' B' F' L 
2392: B L F' D U' B' F' L B 
2576: B L F' D U' B' F' L B R 
2192: B L F' D U' B' F' L B R U' 
2321: B L F' D U' B' F' L B R U' R 
2952: B L F' D U' B' F' L B R U' R D' 
2600: B L F' D U' B' F' L B R U' R D' L2 
3393: B L F' D U' B' F' L B R U' R D' L2 B2 
2616: B L F' D U' B' F' L B R U' R D' L2 B2 F' 
3384: B L F' D U' B' F' L B R U' R D' L2 B2 F' L'

This heuristic certainly provides a 'rough' estimate of a cube's state from the solved state, but isn't perfect. I think a perfect one does exist and I'm going to see if I can find it..




Lucas Garron said:


> Cride5 and Stefan would probably be interested in this, and I hope Jeremy doesn't mind me linking to it.
> 
> Jeremy wrote a 3x3x3 RSS hack at the beginning of October. Problem is, he never got it to be fully cross-browser (essentially Chrome, FF, Safari, IE - both on Windows and Mac).
> (This was supposed to work better, but fails for me.)



Hmm, I wonder if cross-platform/browser compatibility is always going to be a problem for js calling java applets. It certainly didn't work in my browser :/


----------



## Johannes91 (Nov 22, 2009)

Cride5 said:


> Still, the values stored in the move tables are natural numbers with ranges significantly lower than is justified by using 64-bit numbers.


And, once again, the actual memory usage can be more than 10 times that. Try it yourself.



Cride5 said:


> In js I'm quite sure 16-bits are used for each character, to allow for unicode.


You're right, from the ECMAScript standard: _"A string value is a member of the type String and is a finite ordered sequence of zero or more 16-bit unsigned integer values."_. The implementation I tested is apparently from 2007, but it definitely used 8 bits.


----------



## Fishycuber (Nov 22, 2009)

I cant get the timer to do anything. It is a black screen that says begin.


----------



## Stefan (Nov 22, 2009)

Fishycuber said:


> I cant get the timer to do anything. *It is a black screen that says begin.*


And nothing else? Is Javascript on?


----------



## Cride5 (Nov 23, 2009)

Johannes91 said:


> Cride5 said:
> 
> 
> > Still, the values stored in the move tables are natural numbers with ranges significantly lower than is justified by using 64-bit numbers.
> ...



Don't worry I do believe you. It wouldn't surprise me if all engines implement arrays using hashtables. Theres some discussion on it here..
http://stackoverflow.com/questions/1460427/does-the-array-size-matter-in-javascript-in-this-case


----------

