Jamie Starke bio photo

Jamie Starke

I develop for my career, but I also develop for fun, and whenever I think it can solve a problem I'm having. This has lead me to create side projects, such as Rental Map and BusTimes, among others.

Consulting Newsletter Email LinkedIn Github Stackoverflow More

Overview

Motivation

I always enjoy to try new technologies. Even if I don’t end up using the technology itself, I figure that I might pick up some interesting strategies and techniques that are useful in other projects.

While getting frustrated with a mini-game inside a game I was playing lately, I decided to build a solver that would assist me in beating the game. Triple Triad is based on a fictional set of cards and looking at it, it seemed that a Minimax algorithm should be helpful with.

I’d previously tried out a minimax algorithm during undergrad, where we had to have it play a game of tic-tac-toe. Pretty simple, but I figured that the algorithm could be a starting point.

The real callenge I figured would be data entry. I could do the game in Python, but constantly representing the cards in a text file to feed in to the algorithm seemed like it would be a real slog. Sure I could potentially win the game, but I definitely wouldn’t have fun doing it.

HTML and JavaScript jumped out as a pretty obvious choice for creating a more interesting and enjoyable interface for this. I could build little card elements that could take all the input needed to represent a card in the game, and then even drag the card to the right position to indicate to my algorithm the current state in the game. I enter what the computer does in the game and I play in the game what my algorithm does.

Web Components

I’ve been keeping my eye on Web Components for a while, or at least the Polymer implementation of them, as it’s been around for a while. What I like about Web Components is the modularity. The code (JavaScript) related to a component is with the view (HTML), and the style (CSS). This method of architecting a system I find to be quite enjoyable.

In terms of code organization, elements of code are composed of other elements, but each element can be build, maintained, and tested relatively independently.

For example, in my application, I saw there being two hands that represent the players available cards, and a common board on which to play their cards. In Web Components, you build your own custom HTML elements, so at the top level of my application, this is how it’s defined:

Custom Dom Elements

<dom-module id="triad-solver">
    <style>
    .horizontal {
      @apply(--layout-horizontal)
    }
    </style>

  <template>
    <div class="horizontal">
      <triad-hand color="red"></triad-hand>
      <triad-board></triad-board>
      <triad-hand color="blue"></triad-hand>
    </div>
  </template>
  <script>
    Polymer({
        is: "triad-solver"
    });
  </script>
</dom-module>

And Below is the card element. In this case, we define the top row to fill the full width of the parent.

<dom-module id="triad-card">
  <style>
    .grid {
        border: 1px solid gray;
        padding: 5px;
        width:70px;
        height:70px;
        @apply(--layout-vertical);
        @apply(--layout-around-justified);
    }
    .row {
        @apply(--layout-horizontal);
        @apply(--layout-around-justified);
    }
    .value-input {
        width: 16px;
        text-align: center;
    }
    .no-show {
        visibility: hidden;
    }
    .red {
        background-color: pink;
    }
    .blue {
        background-color: lightblue;
    }

  </style>
  <template>
    <div id="grid" class="grid">
        <div class="row">
            <input class="value-input no-show"></input>
            <input is="iron-input" bind-value="" type="text" title="" class="value-input"></input>
            <input is="iron-input" bind-value="" type="text" class="value-input"></input>
        </div>
        <div class="row">
            <input is="iron-input" bind-value="" type="text" class="value-input"></input>
            <span bind-value="" class="card-modifier-value"></span>
            <input is="iron-input" bind-value="" type="text" class="value-input"></input>
        </div>
        <div class="row">
            <input id="bottom-value" is="iron-input" bind-value="" type="text" class="value-input"></input>
        </div>
    </div>
  </template>
</dom-module>
<script>
    Polymer({
        is: 'triad-card',
        properties: {
            color: {
                type: String,
                observer: 'colorChanged'
            },
            top: Number,
            left: Number,
            right: Number,
            bottom: Number,
            element: String,
            modifier: Number
        },
        colorChanged: function(newColor, oldColor) {
            this.$.grid.classList.remove(oldColor);
            this.$.grid.classList.add(newColor);
        },
        flip: function () {
            colorFlipMap = {
                red: "blue",
                blue: "red"
            }

            if (this.color in colorFlipMap) {
                this.color = colorFlipMap[this.color];
            }
        },
        rep: function () {
            var cardRep = new CardRep(parseInt(this.top), parseInt(this.left), parseInt(this.right), parseInt(this.bottom), this.element, parseInt(this.modifier), this.color);
            return cardRep;
        }
    })
</script>

In the above, whenever the color property is changed, it actually sets the css class on the element. From a given <triad-card> element, the color, top, left, etc. can all be accessed from the element.

Testing Web Components

This can all be unit tested using web-component-tester. Here’s one of my unit tests for the <triad-card>.

<body>
    ...
    <script>
      ...
      suite('<triad-card>', function() {
        ...
        test('color flip: the color should change, and back', function () {
          var card = createCardElement();
          card.color = "red";

          var expectedColor = "blue";

          card.flip();

          assert.equal(card.color, expectedColor, "The color should change to blue");

          expectedColor = "red";

          card.flip();

          assert.equal(card.color, expectedColor, "The color should change to red");
        });
      });
    </script>
  </body>
</html>

This makes developing feel awesome, because when I build a set of tests for a component, and run the tests, when they pass, I feel confident it works.

It’s currently a work in progress, but you can check out the code at Triple Triad Solver.

In my next post, I’ll explain how I set up continuous integration with web-component-tester and Travis-CI.