More Tinkering with Concentration

I’ve been tinkering again with my Concentration game.

It started the day after Thanksgiving. I was stuck at the car dealership, waiting while they fixed my car, and decided to scratch a couple of long standing itches, and then, as I’ve been playing with it, I’ve been noticing things and fixing them.

There are now styles for larger screens. On my laptop, the default puzzle size was starting to feel small. When I created the Angular version, I added responsive styles directed at mobile devices; I’ve now added another size class for bigger devices — the puzzle is larger, while the prizes stay the same size.

I had a dickens of a time adding this, partly because there are a lot of off-by-one (or two) issues due to the gaps between trilons, and partly because I’d forgotten how the trick of laying out trilons worked. I got it working, and then a couple of days later, reworked it again, setting up a couple of Sass mixins to handle it.

Next, I improved the game end transitions. One sore point — it’s even been pointed out to my by an end user (Hi Glenn!) — was that when the board was resetting itself from the puzzle state to the number state, it passed through the prize state. This was a consequence of the way the trick worked.

The number face has a rotation of 0°, the prizes a rotation of -120°, and the prizes are -240°. The turning of the trilons is accomplished via a Cascading Style Sheet (CSS) transition — you specify the property that will be changing, and tell the browser how long you want the transition to last. The browser then animates the change, gradually changing the value of the property over the specified time from the starting value to the ending value.

This works fine when moving in normal game order; when a number is clicked, it animates changing the rotation from zero to -120°, making it look like the trilon is rotating clockwise. And in the case of a non-match, there is no intermediate state as it rotates counterclockwise back.

Unfortunately, at the end of the game, we would prefer to continue going clockwise from the prize state to the puzzle state, but the transition from -240° to 0° is a counterclockwise one, taking us through the prize state.

I tried fixing this before, by temporarily making the number state -360°, which is visually the same as 0°. Unfortunately, the transitions made the trilons spin like whirling dervishes.

This time, it occurred to me that what I needed to do, in addition, was turn off the transitions first, pause for part of a second, and then make the number state be -360°. I then pause for another fraction of a second, re-enable the transitions, and then set the trilon state to number. The transition from -240° to -360° is the desired clockwise motion. I then wait for the transition to complete, turn off transitions again, restore the number state to 0°, wait a fraction of a second and re-enable transitions. This gives a smooth reset to start the new game.

I’ve been tinkering with puzzles and prizes. I’ve added a couple more puzzles — there are now 12 — and added more prizes, both good prizes and bad prizes. I’ve been playing the game a lot myself lately, and the same prizes do repeat. There’s not much to be done about that except to add more.

I’ve been tinkering with the innards of the style system — repetitive code has been replaced by Sass mixins. I’ve also been playing with the speed of the rotation. Previously, the animation was linear, running at a constant speed. I’ve added “easing”, so that the rotation starts slow(ish), speeds up, then slows down again; this better reproduces how the physical trilons worked. This necessitated changes to the overall trilon speed — for a while, it was too fast, then it was too slow. Now it feels about right… just about the speed of the Jack Narz board.

Speaking of the Jack Narz board, I’ve more closely matched the colors. It’s hard to match the colors exactly, since I’ve been picking up the colors from YouTube videos that are full of compression artifacts, but it is closer, It will never be an exact match since the font is different, but it’s closer.

Finally, I noticed that there had been a regression between the jQuery and Angular versions of the board. I was idly playing with the old version, and noticed a pronounced perspective effect on the turning trilons that wasn’t present in the Angular version. It was supposed to be there; I’d copied the perspective and transform-style properties over. But it wasn’t.

It turned out that the problem was an artifact of how Angular renders components. Unlike React, which only renders the HTML elements within the React Component, an Angular component will render a custom HTML element representing itself. So, the rendered Angular source for a trilon looks something like this:

<ca-trilon _ngcontent-ndj-c21="" _nghost-ndj-c19="" class="ng-tns-c21-0 ng-star-inserted" style="">
   <div _ngcontent-ndj-c19="" class="trilon state-number row1 col2">
      <div _ngcontent-ndj-c19="" class="face num">
         <div _ngcontent-ndj-c19="" class="inner">
            8
         </div>
      </div>
      <div _ngcontent-ndj-c19="" class="face prize"><!---->
       <!----><div _ngcontent-ndj-c19="" class="inner ng-star-inserted">
        Green House
             </div><!----><!---->
       </div>
       <div _ngcontent-ndj-c19="" class="face pzl" style="background-image: url(&quot;/assets/puzzles/pzzl-005-2x.gif&quot;); background-position: -302px -98.5px;">
      </div>
   </div>
</ca-trilon>

What this means in terms of the style system was that there was an intervening element — the <ca-trilon> element — between the element that had the perspective on it, and the <div class="trilon> that had the preserve-3d style on it.

This required massive changes to fix. I had to apply styles to the <ca-trilon> element — height, width, and the preserve-3d property, as well as make it display: block. This threw the layout of the board totally out of whack. Previously, each trilon had been placed absolutely with a fixed top and left position; I removed this, and changed it to a simpler flex-box arrangement. I then had to fudge all the measurements until there was the proper amount of space around each trilon, and the puzzle as a whole… and then repeat that for the other two sizes. Happily, in the end, I think I’ve wound up with simpler code in the end.

Although I did successfully get perspective working, I found that the effect as implemented in the jQuery version was too strong. It was especially noticeable at number 30 — the corners of the rotating trilon appeared to be moving through its neighbors. You control the perspective effect by specifying a number — think of it as specifying how far away the vanishing point of a perspective drawing is. The smaller the number, the stronger the effect. The jQuery original used 700px; I’m using 2800px for this. Number 30 doesn’t seem to clip, but there is still a bit of a perspective effect as the trilon rotates, making it look more like the back edge is receding.

Finally, a couple of housekeeping items. I used ng new to create the original shell of the Angular application, giving me an Angular favicon. I’d also set the document title to “Concentration/Angular” as my original intention was to also create a React version. I’m not so sure anymore that I want to do that. So it’s now just “Concentration”, with the classic “Mystery Logo” as the favicon.