Buckshot Videos

Loading...

Tuesday, November 11, 2014

A Short Book Review - "Game Programming Patterns" by Robert Nystrom (or "I Saw The Sign, And The Sign Said Buy This Book")

I am seriously the worst person to review a book like this.  But I read it, and being a fan of Bob and his works (check out his work with Magpie or Finch and prepare for dazzle), so I thought I'd have a crack at a short review.  Incidentally, Bob has done some incredible work on Google's Dart project.  I have greatly understated the previous sentence.

First a little context about me, the reader.  I'm not a software engineer.  If software engineers were like structural engineers who design buildings and bridges, I would be the guy who builds really (really) nice models of those same buildings and bridges in his basement.  You'd like my model bridge, but you wouldn't want me building the actual bridge across the river in your town.  That said,  I've been writing code for a long time.  I'm talking the 8086/8 8-bit assembly days (if you have any idea what an 8086 is, high-five!).  I love writing code.  It's my singular non family related passion.

The recent publishing of Game Programming Patterns is timely for me, because I happen to be coding a game right now.  Even more coincidentally, Bob mentions a game in his book called "RoboWar", which is somewhat similar in concept to what I'm working on.  Clearly fate has brought us together at this nexus of time and space.  Let's move on to the review.

The overall tone of the book is exactly where I like it to be.  Bob stuffs every pages with useful technical nuggets, while at the same time weaving in his own, often humorous voice, with little asides.  In one particularly funny section, Bob is critiquing historical overuse of class inheritance during the emergence of OOP, and manages to illustrate the point with this aside, which cracked me up:
"That same year, Ace of Base had not one but three hit singles, so that may tell you something about our taste and discernment back then."
Hey Bob, we thought we were cool in the 80's okaaaaaay.  We invented Spuds Mckenzie, fat laces, and tails!

You're damn right we made animals hock our beer in the 80s!
The content of the book is laid out in groups of design patterns, with each group containing chapters for several specific patterns.  For each pattern, Bob provides a "motivation", along with pros, cons, and examples that arch over a common use case.  I liked the balanced approach he took, which to me sums up as "Hey you might find this pattern helpful for this set of problems, but be aware of this other set of problems using the pattern might create."

Another aspect of the book I enjoyed was that periodically Bob would open the doors to the "big game development" sausage factory, and share with the reader a bit of what it's like to work in those companies.

If someone came to me and said "John, describe the flyweight pattern to me.", I would start with "uhhhh" and then proceed to describe it in an "all over the map" style that would leave your head spinning.  Bob does an amazing job balancing the depth at which he covers each pattern against a trajectory that moves the reader along a common use case for it.  There are many rabbit holes to go down when talking about design patterns, and Bob does a good job of only dipping down far enough to get his point across.

Nearly all of the code examples in the book are in C++.   This is certainly the best choice for the target audience I think.  I wondered if this choice may exclude the more "webified" community of game developers who  may find it more difficult to map the concepts to concrete examples, in say javascript or other popular GC languages.  It's a nit issue really.  To Bob's credit, he does visit this point of "GC vs non-GC" languages a few times in the book and how this may affect the decision to use a pattern or not.  I would have liked to have seen more side-by-side examples though.

The book is nicely illustrated, in just the right places.  If I'm not mistaken, it looks like Bob did all of his own illustrations.  Impressive.

What I liked best about the book, and the reason why I'd recommend it as a buy, is that it sparked real ideas in my 8-bit brain as to how I might improve my own code.  Several times while reading, I was tempted to put it down and go re-factor some old project of mine.  I call that a serious mark of success.

So now, go buy Bob's book Game Programming Patterns, and enjoy it as much as I did!  I leave you with this inspirational video...





Wednesday, October 29, 2014

Creating a lightweight DSL using Dart operator overrides.

I'm working on a game called "hakk.it".  hakk.it is 100% written in Dart and when launched, will be widely available as a modern web application for most devices that support the Chrome browser (I'm looking at you with a raised eyebrow IOS...).

The premise of the game is pretty simple, you write special software code called "hakks".  These hakks take physical form and combat each other in arenas.  In addition to code, the hakks are made up of different types of blocks, each of which the code can make use of in various ways. It's a lot of fun, if I do say so myself.

Early screenshot of a hakk.it arena match in action.

What!? Nobody wants to write code in assembly?

This post isn't really about hakk.it.  That that will come at a later time.  This post is about one challenging aspect of the project that I needed to address.  The hakk.it virtual machine (VM) runs a machine language very similar to assembly for any CPU, and and most efficient hakks can be written directly in this machine language I call "hakkML".  I want hakk.it to be accessible to beginners and experts alike, and I realized lot of people will find the prospect of coding in assembly quite daunting.  I decided that I needed to create an easier way for people to express their code, but at this stage I didn't want to develop a full-fledged DSL, with tooling and everything else that comes along with it (that will come, later).

Dart To The Rescue!

Among the many features I love about Dart, one of my favorite is the ability of override operators.  I decided to attempt a DSL that is imbedded in Dart itself.  Technically this isn't a DSL.  It's more accurately described as a macro language, but as you'll see, it does offer enough expressiveness that it feels like a DSL.

I wanted the API to feel flexible and accessible like BASIC, and yet still allow access to the underlying power of the hakk.it hakkML instruction set.  This meant that I needed to support inline expressions that, to the programmer, felt like real expressions.  I also needed looping and conditional mechanisms that work intuitively.  Thanks to the power of Dart, I was able to accomplish all of these goals, and more.

Using Dart I'm able to provide an "DSL" to players, and yet still allow them to take advantage of all the great Dart tooling that's already in place, such as the Dart Editor.

How It Looks

Building a hakk with the basic API starts by declaring a name and something called a "system block" which is basically a block containing some memory for the compiler to use.  So the basic form of all hakks looks like this:

 hakk('hello_world');  
 Block.system(0, -1);  

This is valid Dart code, by the way.  All you have to do is import the API library (linked later) and start writing a hakk.

Next we want the hakk to do something.  Well in a normal hakk, we would write code for moving it around, firing weapons, activating defensive capabilities and so on.  For the purposes of this article, we'll keep things a bit more simple.  Here is an example of "hello world":

 hakk('hello_world');  
   Block.system(0, -1);  
   output('Hello World!');  
 print(build());  

That's it.  What the build() function does behind the scenes is activate the compiler, which compiles the following hakkML into a string:

 name: "hello_world"  
 blocks:  
  - core:  
  - mem: {name: "__sys0__", loc: [0, 1]}  
 code:  
  core:  
   - out: "Hello World!"  

Lets do something a little more advanced.  Lets say we want to perform some complex O(n^2) operation (you really, really wouldn't want to do this in a hakk meant for the arena, by the way).  In hakk.it every hakk comes standard with a "core" block, which contains 16 memory spaces to store and retrieve information during runtime.  The basic API provides an easy way to access these spaces, so lets use them to create something more complex with the API.  What follows is a nested FOR/NEXT loop construct, written with the API:

  hakk('for_example');  
  Block.system(0, 1);  
  FOR(core0 << 0, core0 < 10, () => inc(core0));  
   output('in core 0');  
   FOR(core1 << 0, core1 < 5, () => inc(core1));  
    output('  in core 1');  
   NEXT();   
  NEXT();  
  print(build());  

It's very similar to any FOR loop you might be familiar with.  The "<<" operator takes the place of "=" because Dart doesn't allow us to override "=".  But I think it's better anyway, because in the API what you are actually expressing with that operator is "store the result of the expression on the right side, into the memory location on the left side".  In that context, it is more precise than the general purpose "=" is.

In the first parameter of the FOR construct, we initialize core0 with 0.  In the second parameter we describe our iterator condition (core0 < 10).  And in the third parameter, we pass a function that will be called at the end of the loop, in this case simply incrementing the value in core0.  Pretty straightforward on the surface.  What's happening under the hood though is quite interesting.  Each of those operators like "<" is actually an override which looks in code like this:

  _ExpressionNode operator <(next){  
   next = _wrapLiteral(next);  
   final node = new _ExpressionNode(this, next, 'jl');  
   _expressionQueue.add(node);  
   return node;  
  }  

The API override "<" in this case, and instead constructs a node that becomes part of an expression tree, which will in turn generate all the hakkML necessary to achieve that expression in the hakk.it VM.  I do the same thing with all the other common operators (+, -, *, /, <, >, &, |) and voila! thanks to Dart we have an fully realized expression syntax.

In case your wondering, here is the hakkML that our example from above generates on behalf of the programmer:

 name: "for_example"
 blocks:  
  - core:  
  - mem: {name: "__sys0__", loc: [0, 1]}  
 code:  
  core:  
   - set: [core.0, 0]  
   - lbl: __while_test_1__  
   - jl: [core.0, 10, __istrue_5__]  
   - set: [__sys0__.0, false]  
   - goto: __logic_finish_5__  
   - lbl: __istrue_5__  
   - set: [__sys0__.0, true]  
   - lbl: __logic_finish_5__  
   - je: [__sys0__.0, true, __iftrue_3__]  
   - goto: __endif_3__  
   - lbl: __iftrue_3__  
   - out: "in core 0"  
   - set: [core.1, 0]  
   - lbl: __while_test_8__  
   - jl: [core.1, 5, __istrue_12__]  
   - set: [__sys0__.2, false]  
   - goto: __logic_finish_12__  
   - lbl: __istrue_12__  
   - set: [__sys0__.2, true]  
   - lbl: __logic_finish_12__  
   - je: [__sys0__.2, true, __iftrue_10__]  
   - goto: __endif_10__  
   - lbl: __iftrue_10__  
   - out: "  in core 1"  
   - add: [__sys0__.4, core.1, 1]  
   - set: [core.1, __sys0__.4]  
   - goto: __while_test_8__  
   - lbl: __endif_10__  
   - add: [__sys0__.3, core.0, 1]  
   - set: [core.0, __sys0__.3]  
   - goto: __while_test_1__  
   - lbl: __endif_3__  

After viewing the machine language generated, the benefits of having a higher level language become readily apparent.  Here is the runtime output of the code itself:

 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
 in core 0  
   in core 1  
   in core 1  
   in core 1  
   in core 1  
   in core 1  

The Real Power of Using Dart, Combinators

I won't go into other aspects of the API itself.  I'll do that in some video tutorials later.  But the API supports other standard constructs like WHILE/ENDWHILE, IF/THEN, and GOSUB/RETURN.  GOSUB incidentally, provides support for passing parameters and returning a result.  It's not as robust as closures, but good enough for the limited purpose of what hakks are intended for.

With all this in place, it's now possible to use the API itself to construct higher-level functionality.  Convenience functions, that would help beginners and people getting to know hakk.it get up and running faster.  Take for example this function provided by the API:

 faceEnemy();  

faceEnemy() orients the hakk toward the nearest opponent in the arena.  It uses the API itself to build up the logic necessary to perform the action it is intended for.  Here's the actual function:

 _HakkObject faceEnemy(){  
  _HakkObject result = _MMU.malloc('face_enemy');  
  _HakkObject x = _MMU.malloc('face_enemy');  
  _HakkObject y = _MMU.malloc('face_enemy');  
  locateEnemy();  
  x << pop();  
  y << pop();  
  output('enemy location');  
  vectorTo(x, y);  
  x << pop();  
  y << pop();  
  output('vector to enemy:');  
  result << faceDirection(vectorToDirection(x, y));  
  _MMU.dalloc('face_enemy');  
  return result;  
 }  

It allocates some temporary memory space in `result`, `x`, and `y`, and then uses other functions and expressions provided by the API to generate all the code necessary to locate and turn the hakk toward the opponent.  The trade-off of using something like this is speed, because the hakkML generated is quite a bit larger than a programmer could write directly in ML.  But it is convenient, and far easier to express.  Using faceEnemy() we could write a simpl logic routine that tries to move toward the enemy in the arena:

 core0 << true;  
 WHILE(core0);  
  core0 << faceEnemy();  
  IF(core0);  
   moveForward();  
   moveForward();  
  ENDIF();  
 ENDWHILE();  

These few lines generate a ton of hakkML code on behalf of the programmer.  I'm including it below so you can get a sense of the power of how using simple Dart combinators can yield very complex results!  Prepare yourselves for a lot of scrolling...

 name: "finder"  
 blocks:  
  - core:  
  - mem: {name: "__sys0__", loc: [0, 1]}  
 code:  
  core:  
   - set: [core.0, true]  
   - lbl: __while_test_0__  
   - set: [__sys0__.0, core.0]  
   - je: [__sys0__.0, true, __iftrue_2__]  
   - goto: __endif_2__  
   - lbl: __iftrue_2__  
   - find:  
   - pop: __sys0__.4  
   - set: [__sys0__.2, __sys0__.4]  
   - pop: __sys0__.5  
   - set: [__sys0__.3, __sys0__.5]  
   - out: "enemy location"  
   - tvec: [__sys0__.2, __sys0__.3]  
   - pop: __sys0__.6  
   - set: [__sys0__.2, __sys0__.6]  
   - pop: __sys0__.7  
   - set: [__sys0__.3, __sys0__.7]  
   - out: "vector to enemy:"  
   - set: [__sys0__.8, -1]  
   - je: [__sys0__.2, 0, __istrue_7__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_7__  
   - lbl: __istrue_7__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_7__  
   - je: [__sys0__.3, -1, __istrue_8__]  
   - set: [__sys0__.10, false]  
   - goto: __logic_finish_8__  
   - lbl: __istrue_8__  
   - set: [__sys0__.10, true]  
   - lbl: __logic_finish_8__  
   - je: [__sys0__.9, true, __istrue_10__]  
   - set: [__sys0__.11, false]  
   - goto: __and_finish_9__  
   - lbl: __istrue_10__  
   - je: [__sys0__.10, true, __istrue_11__]  
   - set: [__sys0__.11, false]  
   - goto: __and_finish_9__  
   - lbl: __istrue_11__  
   - set: [__sys0__.11, true]  
   - lbl: __and_finish_9__  
   - je: [__sys0__.11, true, __iftrue_5__]  
   - goto: __endif_5__  
   - lbl: __iftrue_5__  
   - set: [__sys0__.8, 0]  
   - lbl: __endif_5__  
   - je: [__sys0__.2, 0, __istrue_15__]  
   - set: [__sys0__.12, false]  
   - goto: __logic_finish_15__  
   - lbl: __istrue_15__  
   - set: [__sys0__.12, true]  
   - lbl: __logic_finish_15__  
   - je: [__sys0__.3, 1, __istrue_16__]  
   - set: [__sys0__.13, false]  
   - goto: __logic_finish_16__  
   - lbl: __istrue_16__  
   - set: [__sys0__.13, true]  
   - lbl: __logic_finish_16__  
   - je: [__sys0__.12, true, __istrue_18__]  
   - set: [__sys0__.14, false]  
   - goto: __and_finish_17__  
   - lbl: __istrue_18__  
   - je: [__sys0__.13, true, __istrue_19__]  
   - set: [__sys0__.14, false]  
   - goto: __and_finish_17__  
   - lbl: __istrue_19__  
   - set: [__sys0__.14, true]  
   - lbl: __and_finish_17__  
   - je: [__sys0__.14, true, __iftrue_13__]  
   - goto: __endif_13__  
   - lbl: __iftrue_13__  
   - set: [__sys0__.8, 2]  
   - lbl: __endif_13__  
   - je: [__sys0__.2, 1, __istrue_23__]  
   - set: [__sys0__.15, false]  
   - goto: __logic_finish_23__  
   - lbl: __istrue_23__  
   - set: [__sys0__.15, true]  
   - lbl: __logic_finish_23__  
   - je: [__sys0__.3, 0, __istrue_24__]  
   - set: [__sys0__.16, false]  
   - goto: __logic_finish_24__  
   - lbl: __istrue_24__  
   - set: [__sys0__.16, true]  
   - lbl: __logic_finish_24__  
   - je: [__sys0__.15, true, __istrue_26__]  
   - set: [__sys0__.17, false]  
   - goto: __and_finish_25__  
   - lbl: __istrue_26__  
   - je: [__sys0__.16, true, __istrue_27__]  
   - set: [__sys0__.17, false]  
   - goto: __and_finish_25__  
   - lbl: __istrue_27__  
   - set: [__sys0__.17, true]  
   - lbl: __and_finish_25__  
   - je: [__sys0__.17, true, __iftrue_21__]  
   - goto: __endif_21__  
   - lbl: __iftrue_21__  
   - set: [__sys0__.8, 1]  
   - lbl: __endif_21__  
   - je: [__sys0__.2, -1, __istrue_31__]  
   - set: [__sys0__.18, false]  
   - goto: __logic_finish_31__  
   - lbl: __istrue_31__  
   - set: [__sys0__.18, true]  
   - lbl: __logic_finish_31__  
   - je: [__sys0__.3, 0, __istrue_32__]  
   - set: [__sys0__.19, false]  
   - goto: __logic_finish_32__  
   - lbl: __istrue_32__  
   - set: [__sys0__.19, true]  
   - lbl: __logic_finish_32__  
   - je: [__sys0__.18, true, __istrue_34__]  
   - set: [__sys0__.20, false]  
   - goto: __and_finish_33__  
   - lbl: __istrue_34__  
   - je: [__sys0__.19, true, __istrue_35__]  
   - set: [__sys0__.20, false]  
   - goto: __and_finish_33__  
   - lbl: __istrue_35__  
   - set: [__sys0__.20, true]  
   - lbl: __and_finish_33__  
   - je: [__sys0__.20, true, __iftrue_29__]  
   - goto: __endif_29__  
   - lbl: __iftrue_29__  
   - set: [__sys0__.8, 3]  
   - lbl: __endif_29__  
   - set: [__sys0__.21, false]  
   - hvec:  
   - pop: __sys0__.25  
   - set: [__sys0__.22, __sys0__.25]  
   - pop: __sys0__.26  
   - set: [__sys0__.23, __sys0__.26]  
   - je: [__sys0__.22, 0, __istrue_39__]  
   - set: [__sys0__.27, false]  
   - goto: __logic_finish_39__  
   - lbl: __istrue_39__  
   - set: [__sys0__.27, true]  
   - lbl: __logic_finish_39__  
   - je: [__sys0__.23, -1, __istrue_40__]  
   - set: [__sys0__.28, false]  
   - goto: __logic_finish_40__  
   - lbl: __istrue_40__  
   - set: [__sys0__.28, true]  
   - lbl: __logic_finish_40__  
   - je: [__sys0__.27, true, __istrue_42__]  
   - set: [__sys0__.29, false]  
   - goto: __and_finish_41__  
   - lbl: __istrue_42__  
   - je: [__sys0__.28, true, __istrue_43__]  
   - set: [__sys0__.29, false]  
   - goto: __and_finish_41__  
   - lbl: __istrue_43__  
   - set: [__sys0__.29, true]  
   - lbl: __and_finish_41__  
   - je: [__sys0__.29, true, __iftrue_37__]  
   - goto: __endif_37__  
   - lbl: __iftrue_37__  
   - set: [__sys0__.24, 0]  
   - lbl: __endif_37__  
   - je: [__sys0__.22, 0, __istrue_47__]  
   - set: [__sys0__.30, false]  
   - goto: __logic_finish_47__  
   - lbl: __istrue_47__  
   - set: [__sys0__.30, true]  
   - lbl: __logic_finish_47__  
   - je: [__sys0__.23, 1, __istrue_48__]  
   - set: [__sys0__.31, false]  
   - goto: __logic_finish_48__  
   - lbl: __istrue_48__  
   - set: [__sys0__.31, true]  
   - lbl: __logic_finish_48__  
   - je: [__sys0__.30, true, __istrue_50__]  
   - set: [__sys0__.32, false]  
   - goto: __and_finish_49__  
   - lbl: __istrue_50__  
   - je: [__sys0__.31, true, __istrue_51__]  
   - set: [__sys0__.32, false]  
   - goto: __and_finish_49__  
   - lbl: __istrue_51__  
   - set: [__sys0__.32, true]  
   - lbl: __and_finish_49__  
   - je: [__sys0__.32, true, __iftrue_45__]  
   - goto: __endif_45__  
   - lbl: __iftrue_45__  
   - set: [__sys0__.24, 2]  
   - lbl: __endif_45__  
   - je: [__sys0__.22, 1, __istrue_55__]  
   - set: [__sys0__.33, false]  
   - goto: __logic_finish_55__  
   - lbl: __istrue_55__  
   - set: [__sys0__.33, true]  
   - lbl: __logic_finish_55__  
   - je: [__sys0__.23, 0, __istrue_56__]  
   - set: [__sys0__.34, false]  
   - goto: __logic_finish_56__  
   - lbl: __istrue_56__  
   - set: [__sys0__.34, true]  
   - lbl: __logic_finish_56__  
   - je: [__sys0__.33, true, __istrue_58__]  
   - set: [__sys0__.35, false]  
   - goto: __and_finish_57__  
   - lbl: __istrue_58__  
   - je: [__sys0__.34, true, __istrue_59__]  
   - set: [__sys0__.35, false]  
   - goto: __and_finish_57__  
   - lbl: __istrue_59__  
   - set: [__sys0__.35, true]  
   - lbl: __and_finish_57__  
   - je: [__sys0__.35, true, __iftrue_53__]  
   - goto: __endif_53__  
   - lbl: __iftrue_53__  
   - set: [__sys0__.24, 1]  
   - lbl: __endif_53__  
   - je: [__sys0__.22, -1, __istrue_63__]  
   - set: [__sys0__.36, false]  
   - goto: __logic_finish_63__  
   - lbl: __istrue_63__  
   - set: [__sys0__.36, true]  
   - lbl: __logic_finish_63__  
   - je: [__sys0__.23, 0, __istrue_64__]  
   - set: [__sys0__.37, false]  
   - goto: __logic_finish_64__  
   - lbl: __istrue_64__  
   - set: [__sys0__.37, true]  
   - lbl: __logic_finish_64__  
   - je: [__sys0__.36, true, __istrue_66__]  
   - set: [__sys0__.38, false]  
   - goto: __and_finish_65__  
   - lbl: __istrue_66__  
   - je: [__sys0__.37, true, __istrue_67__]  
   - set: [__sys0__.38, false]  
   - goto: __and_finish_65__  
   - lbl: __istrue_67__  
   - set: [__sys0__.38, true]  
   - lbl: __and_finish_65__  
   - je: [__sys0__.38, true, __iftrue_61__]  
   - goto: __endif_61__  
   - lbl: __iftrue_61__  
   - set: [__sys0__.24, 3]  
   - lbl: __endif_61__  
   - set: [__sys0__.8, __sys0__.24]  
   - je: [__sys0__.8, 0, __istrue_72__]  
   - set: [__sys0__.22, false]  
   - goto: __logic_finish_72__  
   - lbl: __istrue_72__  
   - set: [__sys0__.22, true]  
   - lbl: __logic_finish_72__  
   - je: [__sys0__.22, true, __iftrue_70__]  
   - goto: __endif_70__  
   - lbl: __iftrue_70__  
   - je: [__sys0__.8, 2, __istrue_76__]  
   - set: [__sys0__.24, false]  
   - goto: __logic_finish_76__  
   - lbl: __istrue_76__  
   - set: [__sys0__.24, true]  
   - lbl: __logic_finish_76__  
   - je: [__sys0__.24, true, __iftrue_74__]  
   - goto: __endif_74__  
   - lbl: __iftrue_74__  
   - turn: [__sys0__.40, 1]  
   - set: [__sys0__.21, __sys0__.40]  
   - turn: [__sys0__.41, 1]  
   - set: [__sys0__.21, __sys0__.41]  
   - lbl: __endif_74__  
   - je: [__sys0__.8, 1, __istrue_80__]  
   - set: [__sys0__.39, false]  
   - goto: __logic_finish_80__  
   - lbl: __istrue_80__  
   - set: [__sys0__.39, true]  
   - lbl: __logic_finish_80__  
   - je: [__sys0__.39, true, __iftrue_78__]  
   - goto: __endif_78__  
   - lbl: __iftrue_78__  
   - turn: [__sys0__.41, 0]  
   - set: [__sys0__.21, __sys0__.41]  
   - lbl: __endif_78__  
   - je: [__sys0__.8, 3, __istrue_84__]  
   - set: [__sys0__.40, false]  
   - goto: __logic_finish_84__  
   - lbl: __istrue_84__  
   - set: [__sys0__.40, true]  
   - lbl: __logic_finish_84__  
   - je: [__sys0__.40, true, __iftrue_82__]  
   - goto: __endif_82__  
   - lbl: __iftrue_82__  
   - turn: [__sys0__.42, 1]  
   - set: [__sys0__.21, __sys0__.42]  
   - lbl: __endif_82__  
   - goto: __end_turn_to_69__  
   - lbl: __endif_70__  
   - je: [__sys0__.8, 1, __istrue_88__]  
   - set: [__sys0__.23, false]  
   - goto: __logic_finish_88__  
   - lbl: __istrue_88__  
   - set: [__sys0__.23, true]  
   - lbl: __logic_finish_88__  
   - je: [__sys0__.23, true, __iftrue_86__]  
   - goto: __endif_86__  
   - lbl: __iftrue_86__  
   - je: [__sys0__.8, 0, __istrue_92__]  
   - set: [__sys0__.39, false]  
   - goto: __logic_finish_92__  
   - lbl: __istrue_92__  
   - set: [__sys0__.39, true]  
   - lbl: __logic_finish_92__  
   - je: [__sys0__.39, true, __iftrue_90__]  
   - goto: __endif_90__  
   - lbl: __iftrue_90__  
   - turn: [__sys0__.41, 1]  
   - set: [__sys0__.21, __sys0__.41]  
   - lbl: __endif_90__  
   - je: [__sys0__.8, 2, __istrue_96__]  
   - set: [__sys0__.40, false]  
   - goto: __logic_finish_96__  
   - lbl: __istrue_96__  
   - set: [__sys0__.40, true]  
   - lbl: __logic_finish_96__  
   - je: [__sys0__.40, true, __iftrue_94__]  
   - goto: __endif_94__  
   - lbl: __iftrue_94__  
   - turn: [__sys0__.42, 0]  
   - set: [__sys0__.21, __sys0__.42]  
   - lbl: __endif_94__  
   - je: [__sys0__.8, 3, __istrue_100__]  
   - set: [__sys0__.41, false]  
   - goto: __logic_finish_100__  
   - lbl: __istrue_100__  
   - set: [__sys0__.41, true]  
   - lbl: __logic_finish_100__  
   - je: [__sys0__.41, true, __iftrue_98__]  
   - goto: __endif_98__  
   - lbl: __iftrue_98__  
   - turn: [__sys0__.43, 1]  
   - set: [__sys0__.21, __sys0__.43]  
   - turn: [__sys0__.44, 1]  
   - set: [__sys0__.21, __sys0__.44]  
   - lbl: __endif_98__  
   - goto: __end_turn_to_69__  
   - lbl: __endif_86__  
   - je: [__sys0__.8, 2, __istrue_104__]  
   - set: [__sys0__.24, false]  
   - goto: __logic_finish_104__  
   - lbl: __istrue_104__  
   - set: [__sys0__.24, true]  
   - lbl: __logic_finish_104__  
   - je: [__sys0__.24, true, __iftrue_102__]  
   - goto: __endif_102__  
   - lbl: __iftrue_102__  
   - je: [__sys0__.8, 0, __istrue_108__]  
   - set: [__sys0__.40, false]  
   - goto: __logic_finish_108__  
   - lbl: __istrue_108__  
   - set: [__sys0__.40, true]  
   - lbl: __logic_finish_108__  
   - je: [__sys0__.40, true, __iftrue_106__]  
   - goto: __endif_106__  
   - lbl: __iftrue_106__  
   - turn: [__sys0__.42, 1]  
   - set: [__sys0__.21, __sys0__.42]  
   - turn: [__sys0__.43, 1]  
   - set: [__sys0__.21, __sys0__.43]  
   - lbl: __endif_106__  
   - je: [__sys0__.8, 1, __istrue_112__]  
   - set: [__sys0__.41, false]  
   - goto: __logic_finish_112__  
   - lbl: __istrue_112__  
   - set: [__sys0__.41, true]  
   - lbl: __logic_finish_112__  
   - je: [__sys0__.41, true, __iftrue_110__]  
   - goto: __endif_110__  
   - lbl: __iftrue_110__  
   - turn: [__sys0__.43, 1]  
   - set: [__sys0__.21, __sys0__.43]  
   - lbl: __endif_110__  
   - je: [__sys0__.8, 3, __istrue_116__]  
   - set: [__sys0__.42, false]  
   - goto: __logic_finish_116__  
   - lbl: __istrue_116__  
   - set: [__sys0__.42, true]  
   - lbl: __logic_finish_116__  
   - je: [__sys0__.42, true, __iftrue_114__]  
   - goto: __endif_114__  
   - lbl: __iftrue_114__  
   - turn: [__sys0__.44, 0]  
   - set: [__sys0__.21, __sys0__.44]  
   - lbl: __endif_114__  
   - goto: __end_turn_to_69__  
   - lbl: __endif_102__  
   - je: [__sys0__.8, 3, __istrue_120__]  
   - set: [__sys0__.39, false]  
   - goto: __logic_finish_120__  
   - lbl: __istrue_120__  
   - set: [__sys0__.39, true]  
   - lbl: __logic_finish_120__  
   - je: [__sys0__.39, true, __iftrue_118__]  
   - goto: __endif_118__  
   - lbl: __iftrue_118__  
   - je: [__sys0__.8, 0, __istrue_124__]  
   - set: [__sys0__.41, false]  
   - goto: __logic_finish_124__  
   - lbl: __istrue_124__  
   - set: [__sys0__.41, true]  
   - lbl: __logic_finish_124__  
   - je: [__sys0__.41, true, __iftrue_122__]  
   - goto: __endif_122__  
   - lbl: __iftrue_122__  
   - turn: [__sys0__.43, 0]  
   - set: [__sys0__.21, __sys0__.43]  
   - lbl: __endif_122__  
   - je: [__sys0__.8, 1, __istrue_128__]  
   - set: [__sys0__.42, false]  
   - goto: __logic_finish_128__  
   - lbl: __istrue_128__  
   - set: [__sys0__.42, true]  
   - lbl: __logic_finish_128__  
   - je: [__sys0__.42, true, __iftrue_126__]  
   - goto: __endif_126__  
   - lbl: __iftrue_126__  
   - turn: [__sys0__.44, 0]  
   - set: [__sys0__.21, __sys0__.44]  
   - turn: [__sys0__.45, 0]  
   - set: [__sys0__.21, __sys0__.45]  
   - lbl: __endif_126__  
   - je: [__sys0__.8, 2, __istrue_132__]  
   - set: [__sys0__.43, false]  
   - goto: __logic_finish_132__  
   - lbl: __istrue_132__  
   - set: [__sys0__.43, true]  
   - lbl: __logic_finish_132__  
   - je: [__sys0__.43, true, __iftrue_130__]  
   - goto: __endif_130__  
   - lbl: __iftrue_130__  
   - turn: [__sys0__.45, 1]  
   - set: [__sys0__.21, __sys0__.45]  
   - lbl: __endif_130__  
   - lbl: __endif_118__  
   - lbl: __end_turn_to_69__  
   - set: [__sys0__.1, __sys0__.21]  
   - set: [core.0, __sys0__.1]  
   - set: [__sys0__.1, core.0]  
   - je: [__sys0__.1, true, __iftrue_134__]  
   - goto: __endif_134__  
   - lbl: __iftrue_134__  
   - lbl: __endif_134__  
   - goto: __while_test_0__  
   - lbl: __endif_2__  
   - find:  
   - movef: __sys0__.2  
   - movef: __sys0__.3  
   - pop: __sys0__.3  
   - set: [__sys0__.1, __sys0__.3]  
   - pop: __sys0__.3  
   - set: [__sys0__.2, __sys0__.3]  
   - out: "enemy location"  
   - tvec: [__sys0__.1, __sys0__.2]  
   - pop: __sys0__.3  
   - set: [__sys0__.1, __sys0__.3]  
   - pop: __sys0__.3  
   - set: [__sys0__.2, __sys0__.3]  
   - out: "vector to enemy:"  
   - set: [__sys0__.3, -1]  
   - je: [__sys0__.1, 0, __istrue_139__]  
   - set: [__sys0__.4, false]  
   - goto: __logic_finish_139__  
   - lbl: __istrue_139__  
   - set: [__sys0__.4, true]  
   - lbl: __logic_finish_139__  
   - je: [__sys0__.2, -1, __istrue_140__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_140__  
   - lbl: __istrue_140__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_140__  
   - je: [__sys0__.4, true, __istrue_142__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_141__  
   - lbl: __istrue_142__  
   - je: [__sys0__.5, true, __istrue_143__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_141__  
   - lbl: __istrue_143__  
   - set: [__sys0__.6, true]  
   - lbl: __and_finish_141__  
   - je: [__sys0__.6, true, __iftrue_137__]  
   - goto: __endif_137__  
   - lbl: __iftrue_137__  
   - set: [__sys0__.3, 0]  
   - lbl: __endif_137__  
   - je: [__sys0__.1, 0, __istrue_147__]  
   - set: [__sys0__.4, false]  
   - goto: __logic_finish_147__  
   - lbl: __istrue_147__  
   - set: [__sys0__.4, true]  
   - lbl: __logic_finish_147__  
   - je: [__sys0__.2, 1, __istrue_148__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_148__  
   - lbl: __istrue_148__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_148__  
   - je: [__sys0__.4, true, __istrue_150__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_149__  
   - lbl: __istrue_150__  
   - je: [__sys0__.5, true, __istrue_151__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_149__  
   - lbl: __istrue_151__  
   - set: [__sys0__.6, true]  
   - lbl: __and_finish_149__  
   - je: [__sys0__.6, true, __iftrue_145__]  
   - goto: __endif_145__  
   - lbl: __iftrue_145__  
   - set: [__sys0__.3, 2]  
   - lbl: __endif_145__  
   - je: [__sys0__.1, 1, __istrue_155__]  
   - set: [__sys0__.4, false]  
   - goto: __logic_finish_155__  
   - lbl: __istrue_155__  
   - set: [__sys0__.4, true]  
   - lbl: __logic_finish_155__  
   - je: [__sys0__.2, 0, __istrue_156__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_156__  
   - lbl: __istrue_156__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_156__  
   - je: [__sys0__.4, true, __istrue_158__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_157__  
   - lbl: __istrue_158__  
   - je: [__sys0__.5, true, __istrue_159__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_157__  
   - lbl: __istrue_159__  
   - set: [__sys0__.6, true]  
   - lbl: __and_finish_157__  
   - je: [__sys0__.6, true, __iftrue_153__]  
   - goto: __endif_153__  
   - lbl: __iftrue_153__  
   - set: [__sys0__.3, 1]  
   - lbl: __endif_153__  
   - je: [__sys0__.1, -1, __istrue_163__]  
   - set: [__sys0__.4, false]  
   - goto: __logic_finish_163__  
   - lbl: __istrue_163__  
   - set: [__sys0__.4, true]  
   - lbl: __logic_finish_163__  
   - je: [__sys0__.2, 0, __istrue_164__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_164__  
   - lbl: __istrue_164__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_164__  
   - je: [__sys0__.4, true, __istrue_166__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_165__  
   - lbl: __istrue_166__  
   - je: [__sys0__.5, true, __istrue_167__]  
   - set: [__sys0__.6, false]  
   - goto: __and_finish_165__  
   - lbl: __istrue_167__  
   - set: [__sys0__.6, true]  
   - lbl: __and_finish_165__  
   - je: [__sys0__.6, true, __iftrue_161__]  
   - goto: __endif_161__  
   - lbl: __iftrue_161__  
   - set: [__sys0__.3, 3]  
   - lbl: __endif_161__  
   - set: [__sys0__.4, false]  
   - hvec:  
   - pop: __sys0__.8  
   - set: [__sys0__.5, __sys0__.8]  
   - pop: __sys0__.8  
   - set: [__sys0__.6, __sys0__.8]  
   - je: [__sys0__.5, 0, __istrue_171__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_171__  
   - lbl: __istrue_171__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_171__  
   - je: [__sys0__.6, -1, __istrue_172__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_172__  
   - lbl: __istrue_172__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_172__  
   - je: [__sys0__.8, true, __istrue_174__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_173__  
   - lbl: __istrue_174__  
   - je: [__sys0__.9, true, __istrue_175__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_173__  
   - lbl: __istrue_175__  
   - set: [__sys0__.10, true]  
   - lbl: __and_finish_173__  
   - je: [__sys0__.10, true, __iftrue_169__]  
   - goto: __endif_169__  
   - lbl: __iftrue_169__  
   - set: [__sys0__.7, 0]  
   - lbl: __endif_169__  
   - je: [__sys0__.5, 0, __istrue_179__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_179__  
   - lbl: __istrue_179__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_179__  
   - je: [__sys0__.6, 1, __istrue_180__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_180__  
   - lbl: __istrue_180__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_180__  
   - je: [__sys0__.8, true, __istrue_182__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_181__  
   - lbl: __istrue_182__  
   - je: [__sys0__.9, true, __istrue_183__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_181__  
   - lbl: __istrue_183__  
   - set: [__sys0__.10, true]  
   - lbl: __and_finish_181__  
   - je: [__sys0__.10, true, __iftrue_177__]  
   - goto: __endif_177__  
   - lbl: __iftrue_177__  
   - set: [__sys0__.7, 2]  
   - lbl: __endif_177__  
   - je: [__sys0__.5, 1, __istrue_187__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_187__  
   - lbl: __istrue_187__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_187__  
   - je: [__sys0__.6, 0, __istrue_188__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_188__  
   - lbl: __istrue_188__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_188__  
   - je: [__sys0__.8, true, __istrue_190__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_189__  
   - lbl: __istrue_190__  
   - je: [__sys0__.9, true, __istrue_191__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_189__  
   - lbl: __istrue_191__  
   - set: [__sys0__.10, true]  
   - lbl: __and_finish_189__  
   - je: [__sys0__.10, true, __iftrue_185__]  
   - goto: __endif_185__  
   - lbl: __iftrue_185__  
   - set: [__sys0__.7, 1]  
   - lbl: __endif_185__  
   - je: [__sys0__.5, -1, __istrue_195__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_195__  
   - lbl: __istrue_195__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_195__  
   - je: [__sys0__.6, 0, __istrue_196__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_196__  
   - lbl: __istrue_196__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_196__  
   - je: [__sys0__.8, true, __istrue_198__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_197__  
   - lbl: __istrue_198__  
   - je: [__sys0__.9, true, __istrue_199__]  
   - set: [__sys0__.10, false]  
   - goto: __and_finish_197__  
   - lbl: __istrue_199__  
   - set: [__sys0__.10, true]  
   - lbl: __and_finish_197__  
   - je: [__sys0__.10, true, __iftrue_193__]  
   - goto: __endif_193__  
   - lbl: __iftrue_193__  
   - set: [__sys0__.7, 3]  
   - lbl: __endif_193__  
   - set: [__sys0__.3, __sys0__.7]  
   - je: [__sys0__.3, 0, __istrue_204__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_204__  
   - lbl: __istrue_204__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_204__  
   - je: [__sys0__.5, true, __iftrue_202__]  
   - goto: __endif_202__  
   - lbl: __iftrue_202__  
   - je: [__sys0__.3, 2, __istrue_208__]  
   - set: [__sys0__.7, false]  
   - goto: __logic_finish_208__  
   - lbl: __istrue_208__  
   - set: [__sys0__.7, true]  
   - lbl: __logic_finish_208__  
   - je: [__sys0__.7, true, __iftrue_206__]  
   - goto: __endif_206__  
   - lbl: __iftrue_206__  
   - turn: [__sys0__.9, 1]  
   - set: [__sys0__.4, __sys0__.9]  
   - turn: [__sys0__.10, 1]  
   - set: [__sys0__.4, __sys0__.10]  
   - lbl: __endif_206__  
   - je: [__sys0__.3, 1, __istrue_212__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_212__  
   - lbl: __istrue_212__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_212__  
   - je: [__sys0__.8, true, __iftrue_210__]  
   - goto: __endif_210__  
   - lbl: __iftrue_210__  
   - turn: [__sys0__.10, 0]  
   - set: [__sys0__.4, __sys0__.10]  
   - lbl: __endif_210__  
   - je: [__sys0__.3, 3, __istrue_216__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_216__  
   - lbl: __istrue_216__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_216__  
   - je: [__sys0__.9, true, __iftrue_214__]  
   - goto: __endif_214__  
   - lbl: __iftrue_214__  
   - turn: [__sys0__.11, 1]  
   - set: [__sys0__.4, __sys0__.11]  
   - lbl: __endif_214__  
   - goto: __end_turn_to_201__  
   - lbl: __endif_202__  
   - je: [__sys0__.3, 1, __istrue_220__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_220__  
   - lbl: __istrue_220__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_220__  
   - je: [__sys0__.5, true, __iftrue_218__]  
   - goto: __endif_218__  
   - lbl: __iftrue_218__  
   - je: [__sys0__.3, 0, __istrue_224__]  
   - set: [__sys0__.7, false]  
   - goto: __logic_finish_224__  
   - lbl: __istrue_224__  
   - set: [__sys0__.7, true]  
   - lbl: __logic_finish_224__  
   - je: [__sys0__.7, true, __iftrue_222__]  
   - goto: __endif_222__  
   - lbl: __iftrue_222__  
   - turn: [__sys0__.9, 1]  
   - set: [__sys0__.4, __sys0__.9]  
   - lbl: __endif_222__  
   - je: [__sys0__.3, 2, __istrue_228__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_228__  
   - lbl: __istrue_228__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_228__  
   - je: [__sys0__.8, true, __iftrue_226__]  
   - goto: __endif_226__  
   - lbl: __iftrue_226__  
   - turn: [__sys0__.10, 0]  
   - set: [__sys0__.4, __sys0__.10]  
   - lbl: __endif_226__  
   - je: [__sys0__.3, 3, __istrue_232__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_232__  
   - lbl: __istrue_232__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_232__  
   - je: [__sys0__.9, true, __iftrue_230__]  
   - goto: __endif_230__  
   - lbl: __iftrue_230__  
   - turn: [__sys0__.11, 1]  
   - set: [__sys0__.4, __sys0__.11]  
   - turn: [__sys0__.12, 1]  
   - set: [__sys0__.4, __sys0__.12]  
   - lbl: __endif_230__  
   - goto: __end_turn_to_201__  
   - lbl: __endif_218__  
   - je: [__sys0__.3, 2, __istrue_236__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_236__  
   - lbl: __istrue_236__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_236__  
   - je: [__sys0__.5, true, __iftrue_234__]  
   - goto: __endif_234__  
   - lbl: __iftrue_234__  
   - je: [__sys0__.3, 0, __istrue_240__]  
   - set: [__sys0__.7, false]  
   - goto: __logic_finish_240__  
   - lbl: __istrue_240__  
   - set: [__sys0__.7, true]  
   - lbl: __logic_finish_240__  
   - je: [__sys0__.7, true, __iftrue_238__]  
   - goto: __endif_238__  
   - lbl: __iftrue_238__  
   - turn: [__sys0__.9, 1]  
   - set: [__sys0__.4, __sys0__.9]  
   - turn: [__sys0__.10, 1]  
   - set: [__sys0__.4, __sys0__.10]  
   - lbl: __endif_238__  
   - je: [__sys0__.3, 1, __istrue_244__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_244__  
   - lbl: __istrue_244__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_244__  
   - je: [__sys0__.8, true, __iftrue_242__]  
   - goto: __endif_242__  
   - lbl: __iftrue_242__  
   - turn: [__sys0__.10, 1]  
   - set: [__sys0__.4, __sys0__.10]  
   - lbl: __endif_242__  
   - je: [__sys0__.3, 3, __istrue_248__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_248__  
   - lbl: __istrue_248__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_248__  
   - je: [__sys0__.9, true, __iftrue_246__]  
   - goto: __endif_246__  
   - lbl: __iftrue_246__  
   - turn: [__sys0__.11, 0]  
   - set: [__sys0__.4, __sys0__.11]  
   - lbl: __endif_246__  
   - goto: __end_turn_to_201__  
   - lbl: __endif_234__  
   - je: [__sys0__.3, 3, __istrue_252__]  
   - set: [__sys0__.5, false]  
   - goto: __logic_finish_252__  
   - lbl: __istrue_252__  
   - set: [__sys0__.5, true]  
   - lbl: __logic_finish_252__  
   - je: [__sys0__.5, true, __iftrue_250__]  
   - goto: __endif_250__  
   - lbl: __iftrue_250__  
   - je: [__sys0__.3, 0, __istrue_256__]  
   - set: [__sys0__.7, false]  
   - goto: __logic_finish_256__  
   - lbl: __istrue_256__  
   - set: [__sys0__.7, true]  
   - lbl: __logic_finish_256__  
   - je: [__sys0__.7, true, __iftrue_254__]  
   - goto: __endif_254__  
   - lbl: __iftrue_254__  
   - turn: [__sys0__.9, 0]  
   - set: [__sys0__.4, __sys0__.9]  
   - lbl: __endif_254__  
   - je: [__sys0__.3, 1, __istrue_260__]  
   - set: [__sys0__.8, false]  
   - goto: __logic_finish_260__  
   - lbl: __istrue_260__  
   - set: [__sys0__.8, true]  
   - lbl: __logic_finish_260__  
   - je: [__sys0__.8, true, __iftrue_258__]  
   - goto: __endif_258__  
   - lbl: __iftrue_258__  
   - turn: [__sys0__.10, 0]  
   - set: [__sys0__.4, __sys0__.10]  
   - turn: [__sys0__.11, 0]  
   - set: [__sys0__.4, __sys0__.11]  
   - lbl: __endif_258__  
   - je: [__sys0__.3, 2, __istrue_264__]  
   - set: [__sys0__.9, false]  
   - goto: __logic_finish_264__  
   - lbl: __istrue_264__  
   - set: [__sys0__.9, true]  
   - lbl: __logic_finish_264__  
   - je: [__sys0__.9, true, __iftrue_262__]  
   - goto: __endif_262__  
   - lbl: __iftrue_262__  
   - turn: [__sys0__.11, 1]  
   - set: [__sys0__.4, __sys0__.11]  
   - lbl: __endif_262__  
   - lbl: __endif_250__  
   - lbl: __end_turn_to_201__  
   - set: [__sys0__.0, __sys0__.4]  
   - set: [core.0, __sys0__.0]  

Whew! You made it!

Conclusion

Using Dart to create an expressive embedded "DSL" API is entirely possible.  Operator overrides provide a gateway to building powerful expression combinators.  Keeping the API embedded in Dart allows developers to take advantage of Dart's existing tooling ecosystem.  For my project, using Dart allowed me to build an API that provides an easier entry point for potential gamers.

If you want to check out the library for yourself, you can import the hakk builder library into your own Dart project here.  It's pretty well documented, though not fully yet.  There are 3 libraries to choose from on import.  Chose the basic library with:

 import 'package:hakk_builder/basic.dart';  

The builder is not yet on github, but you can also download the source code from pub if you wish.


Thursday, November 1, 2012

Dart Metadata Is Your Friend

Metadata is a recent feature addition to the Dart language.  The Dart SDK already includes a few metadata tags that (integrated with the Dart Editor) can help you catch common errors, and alert users to deprecated code.  In this post, we'll see how to use the two metadata types included in the SDK: '@deprecated' and '@override'


What Is Metadata?


Metadata is essentially a piece of information that can provide additional context to your code.  This information can be used by tools such as Dart Editor, and eventually by your own code via mirror-based reflection.

According to the Dart Specification "Metadata can appear before a library, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import or export directive."

Using The Dart 'meta' Library


Since this is a package library, you'll need to add a reference to it in your application pubspec, and then run pub install (see pub.dartlang.org for more information about this process).  Once available, you can import the library like so:

 import 'package:meta/meta.dart';  

Now that the metadata types are in scope for your app, it's time to put them to good use!


Using the @deprecated Metadata Type

Let's say you have a class for a function that you no longer want users of your library to use.  By marking your object with the @deprecated tag, the Dart editor will strike-through any references to it, giving a great visual clue to the developer that they should use a new approach.

First lets look at our function before @deprecated is applied:

Suddenly foo() isn't so cool anymore and we want to let users of the library know about it.  Let's add the @deprecated metadata and see what Dart Editor does:

Notice how Dart editor strikes through not only the implementation function, but also any references to that function.  Neat huh?  The editor also gives other visual clues, such as an informational message and a squiggly underneath the reference.


Using the @override Metadata Type

Now this one I really like, because it's actually helped me catch a few inheritance-related bugs in my code.  Let's look at this example where we have a class Bar which inherits from a class Foo, and Bar wants to override some methods in Foo:


By using the @override metadata type, we can see that the editor is helping us identify a problem in our Bar class, where we have a typo in the override class name.  Notice how we get no help on the 'donothing()' method in Bar, when we probably wanted to override 'doNothing()' in Foo.

In larger, non-trivial applications these kinds of bugs can be nasty to track down, if you consider that this code...

 new Bar().doThat();  

...will happily execute and give you a result of "doThat" from Foo instead of the expected "Do that other thing." from Bar - leaving you with clenched fists and pulled hair as you try to trace down the problem..  In short, using @override every time you expect to be overriding a superclass method will help you avoid a whole class of bugs in your code.

Summary

Dart's metadata functionality is still in early days, but already proves quite helpful when combined with tools such as the Dart Editor.  Liberal use of @deprecated and @override will go along way toward making your code easier to work with and troubleshoot.  Give it a try in your code today and give your feedback to the Dart team.

References:
http://news.dartlang.org/2012/07/draft-spec-changes-for-metadata-in-dart.html
http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.d0rowtffuudf

Friday, October 5, 2012

Common Dart Scenarios for the 'Future' API

A Future<T> object represents a unit of work that will complete at some point in the - you guessed it - future.  I use Futures a lot in my code and I thought that rather than do an exhaustive walk-through of the class itself, I'd share some of the more common patterns and concepts that I often find useful.

In Future Does Not Mean In Parallel

If you come from the .net world, you'll probably have some experience with Task<T> and the whole parallel processing API.  Futures aren't that.  They are more like structured callbacks, which will almost always run in the same memory space and thread as your application.  They won't run in their own threads or multi-core on their own.  If you're interested in parallelism, consider exploring Dart's Isolates API.

Futures Are Not Automatically Asynchronous

At the time of this writing, there is a ticket open in the Dart queue to make all futures asynchronous, but for now what you are about to read remains accurate.

It is important to understand that Futures are not necessarily asynchronous by default. Let's look at this example:
 // This future is not asynchronous and will complete as soon as it is called.  
 Future<bool> greaterThan42(int number){  
   final c = new Completer();  
   c.complete(number > 42);    
   return c.future;  
 }  

This above code is synchronous, in fact you can write it in a much more succinct way using the .immediate() constructor of the Future class:
 Future<bool> greaterThan42(int number) =>  new Future.immediate(number > 42);  

Futures are really most powerful when dealing with asynchronous work, lets use the Timer class to simulate that here:
 Future<bool> greaterThan42(num number){  
   final c = new Completer();  
   
   void doWork(_){  
    c.complete(number > 42);  
   }  
   
   // take 3 long seconds to return our result  
   new Timer(3000, doWork);  
   
   return c.future;  
 }  

The example above uses the Timer asynchronously callback a function after a 3 seconds has elapsed.

A Couple Of Common Future Scenarios

Waiting For One Or More Futures To Complete

The futures API provides a very convenient way to deal with this scenario, in Futures.wait().  Lets see how it works by modifying our greaterThan42 future a bit.
 Future<bool> greaterThan42(num number, int howLongMs){  
   final c = new Completer();  
   
   void doWork(_){  
    c.complete(number > 42);  
   }  
   
   // take 3 long seconds to return our result  
   new Timer(howLongMs, doWork);  
   
   return c.future;  
 }  
   
 main(){  
   Futures  
    .wait([greaterThan42(5, 1000), greaterThan42(100, 3000)])  
    .then((List<bool> results){  
      print(results);  
    }  
 }  

So what is happening above when we send a list of 2 futures into Futures.wait()?  Well, it waits!  It does all the mundane work necessary to be sure that all the futures in the list have completed.  It then itself returns a Future, containing a list of the results returned by the Futures we were waiting on.

The results of running the above code will yield:
 [false, true]  

Similar to this, we often need to iterate over a list of objects, where a method in each object returns a future. Dealing with this in a standard iteration construct won't work cleanly,  because the iteration will continue happily along whether or not our future has completed.  We can use Futures.wait() and a .map() to deal with this nicely:
 main(){  
   Futures   
   .wait(listOfFoos.map((foo) => foo.callFutureMethod()))   
   .then(results){  
     // now we can safely iterate the results of the future calls  
     results.forEach((bar) { // ... });  
   }   
 }   


Working with Futures in Sequence

Often times we want to receive the result of some Future, and then pass that result into another Future.  Do this 4 or 5 times and you get a really nasty scaffolding effect:
 callFutureA()  
   .then((resultA){  
    callFutureB(resultA)  
      .then((resultB){  
       callFutureC(resultB)  
         .then((resultC){  
           print('Kill me now!');  
         });  
      });  
   });  

Fortunately, the Future API gives us a nice way to deal with this as well, with Future.chain().  Future.chain() takes some result and then returns another future, such that you can keep your control flow flat:
 callFutureA()  
  .chain((resultA) => callFutureB(resultA))  
  .chain((resultB) => callFutureC(resultB))  
  .chain((resultC) => callFutureD(resultC))  
  .then((resultD){  
    print('Wait, don't kill me after all!');  
   });  

Furthermore, if you are just doing a simple transforms on a future, you don't have to wrap all of your transformational functions in Futures.  You can use the Future.transform() function to achieve the same result:
 futureA(String foo) => new Future.immediate('$foo A');  
 functionB(String foo) => '$foo B';  
 functionC(String foo) => '$foo C';  
 functionD(String foo) => '$foo D';  
   
   
 main(){  
  futureA('Transform me!')  
   .transform(functionB)  
   .transform(functionC)  
   .transform(functionD)  
   .then((result) => print('$result'));  
 }  

Yields:
 Transform me! A B C D

Now, I could go off on a tangent here about the need for an await keyword in Dart, and how that would make dealing with asynchronous control flows even more simple to work with, but I'll save that for another post (maybe).

Summary

The Future API provides a great way to manage asynchronous coding in Dart.  Smart use of the API will keep your asynchronous code well managed and readable.

Sunday, August 26, 2012

Working With Mirrors In Dart - A Brief Introduction

Mirrors provide a way to perform reflection on your application.  The great thing about mirrors vs traditional reflection in other languages is that they are not intrinsically tied to the object system.  This stratification provides many benefits.  If you want to learn more about mirrors in general, check out this great list of links provided by Gilad Bracha.

Dragons!  The mirror API is still very new and subject to change at any time.  At the time of this writing, it is only supported in the Dart VM (not dart2js).

A mirror is a meta object, that provides information about, and in some cases operations on, objects in a Dart application.  Each type of canonical "thing" in Dart has, generally speaking, a corresponding mirror type.

A listing of mirror types supported by the API.
As you can see from the list above, there is a mirror for just about everything.  Different mirrors provide different kinds of visibility (introspection) and operations.

Mirrors Beget Mirrors

Mirror functions always return another mirror as a result. Even the instantiation and invocation functions will return an InstanceMirror. It is from the InstanceMirror that you can get access to the concrete object from your application.

Perusing Dart With Mirrors

The mirror API allows you to inspect pretty much anything in your application.  At the top level, the starting point for doing so done this way:

 final MirrorSystem ms = currentMirrorSystem();  

I should note there that there is another sibling of currentMirrorSystem() called mirrorSystemOf(SendPort port), which is used to reflect on other isolates, but I won't be covering that in this post.

With this mirror in hand, you can iterate through all the libraries that are currently in scope of your application, iterating through the libraries map will naturally yield LibraryMirror's.

 final MirrorSystem ms = currentMirrorSystem();  
 // Iterating through libraries  
 ms  
   .libraries  
   .forEach((String name, LibraryMirror libMirror){  
      print('$name $libMirror');  
   });  

LibraryMirror, in turn, exposes collections of members, classes, functions, getters, setters, and variables for that particular library.  It becomes trivial then, to drill down to exactly information you need.

Instantiating and Invoking

There are two mirror types in particular that provide a way to instantiate objects and invoke methods:  ClassMirror and ObjectMirror.  In ClassMirror, there is a function called newInstance() which will return a Future<InstanceMirror> object. Lets see how this works:

 #import('dart:mirrors');   
   
 main(){   
  final foo = new Foo();   
   
  //lets get a reflection of foo   
  InstanceMirror fooIM = reflect(foo);   
   
  //now we get to the ClassMirror of fooIM   
  ClassMirror fooCM = fooIM.type;   
   
  //with our class mirror we can create a new instance of foo   
  //(an new InstanceMirror is returned)   
  fooCM   
   .newInstance('',[])   
   .then((InstanceMirror newIM){   
   
      //our concrete instance is now located in newIM.reflectee   
      newIM.reflectee.doSomething();   
   });   
  }   
   
 Class Foo   
 {   
   void doSomething(){   
     print('you did it!');   
   }   
 }   

Running this program will yield:

 you did it!  

Invoking methods is not much more difficult, but there is one area where you will want to pay special attention:  Invocation of instance methods will need to be done on an InstanceMirror, whereas invocation of static methods will be done on the ClassMirror.  Lets try both:

  #import('dart:mirrors');   
  main(){   
  final foo = new Foo();   
   
  //lets get a reflection of foo   
  InstanceMirror fooIM = reflect(foo);   
   
  //now we get to the ClassMirror of fooIM   
  ClassMirror fooCM = fooIM.type;   
   
  //invoke the instance method  
  fooIM.invoke('doSomething', [reflect('hello world')]);  
   
  //invoke the static method  
  fooCM.invoke('doSomethingStatic', []);  
  }   
   
  Class Foo   
  {   
   static void doSomethingStatic(){  
     print('you invoked me and I'm static method!');  
   }  
   
   void doSomething(String message){   
     print('instance method received message $message');   
   }   
  }   

.invoke() also returns a Future<InstanceMirror> on the result of the invocation, if we are interested in the return.  In the example above we aren't.

Also in the example above, we pass a value to doSomething() during the invocation, and we need to wrap it in a mirror using reflect() (the Dart team may do this automatically for us in the future).

Non-final fields, along with explicit getters and setters, also have a similar invocation mechanism, but the calls are made to .getField() and .setField() instead.  More information about these can be found in the ObjectMirror class.

Summary

The Dart mirrors API provides a powerful set of tools for reflecting on your code.  Hopefully this brief introduction to the will help you get started.

Thursday, August 23, 2012

Fun House Of Mirrors

Working feverishly on a version of Buckshot that uses the new #dartlang mirrors API.

Where before you had to pre-register controls to the framework, this version finds and instantiates controls automatically.  All you have to do is import the library with the control in your app, and Buckshot does the rest.  This has the added benefit of preventing registration sequence problems where a control might want to reference another control that hasn't been registered yet.

This branch of the project only works in Dartium at the moment because mirrors isn't yet supported in dart2js, but if you'd like to check out some aspects of how mirrors work, then give it a spin at the link provided below.  All of the included demos work with the mirror-based version.

I have a helper class that provides some utility functions via mirrors here: miriam.dart

Buckshot 'Latest' Branch On Github

Tuesday, June 19, 2012

Two Of My Projects Make the Google I/O Intro To Dart

This is a very comprehensive and well done introduction to Dart by Seth Ladd.  I was pleasantly surprised and honored to see two of my projects listed on the community slide: Buckshot UI and the "Zart" Z-Machine.  

Congrats to all the great community projects that made the video (around minute 34:00)!