John Bintz's Blog

The Kids Lying To Their Parents Game: Welcome!

I've been working on some incarnation of some sort of board/card game for about six months now, and it's finally to the point where I want to start talking about it. I've done a few playtests of it with friends, plenty with myself, and thought I would start blarghing about it and have a place where people can download the in-development print'n'play PDFs.

IMG_8270

The theme of the game is that the players are a group of siblings who have to convince their parents that the thing they're being accused of (which, if the first player wants to come up with it, can most certainly do!) was not their fault, since they were actually deaing with a series of escalating lies...er...events, each one getting more fantastical than the last! You can embellish those lies a little to make them sound better, but talk fast, because if your siblings finish their stories before you do, you get trash duty for a month!

The game has the following mechanics:

  • The primary one is a number-based press your luck card stacking scoring mechanic like Lost Cities.
  • There are multiple possible chainable actions that cards allow you to perform, much like Dominion if you could chain Buys and Actions out of order.
  • There are card modifier cards, like Gloom, but playing them isn't the whole focus of game, like it is in Gloom.
  • First player selection is not arbitrary ("oldest player", "last one to ride on a train", etc.). The first player is the one who starts the game by revealing the highest value card out of anyone else. This makes it more difficult for them to complete that stack of cards, but lets them go first, potentially gaining a lead over others. This is similar to how the start player in Innovation is selected.
  • In the first expansion, there is a card "tucking" mechanism, like tucking under splayed cards in Innovation.
  • There's a little bit of "gotcha" player attacking through the removal of cards from other player's stacks, or taking a card from other players' hands, but it's not the focus of the game (so no Munchkin level 9 grinds, but it can get pretty brutal, as we've found in playtesting).
  • Theoretically, if the players wanted to, they can roleplay a story a bit, like in Gloom. :)

I have one expansion already designed and somewhat playtested, but not thoroughly. It's more of an idea at this point. It adds more cards and a new action one can take. It's all in the rules. :) You can check out the rules in this Google Doc and download the latest version of the game from this Dropbox link. I'll be posting stuff in /r/tabletopgamedesign as well as here. Feedback should go to Reddit or Twitter.

AngularJS Day 1: Brain against a cheese grater edition

So I needed a JavaScript-y component for a Rails application I was working on, and I didn't want to build it in Backbone because I'm sick of making a ton of JavaScript templates, and I wasn't going to rewrite this entire Active Admin-based application as a JavaScript app for this one component, so I decided to give AngularJS a spin. All I wanted was an easy-to-build component that would read in and dump JSON data to/from the app for this particular field, to be processed with a form object on the backend. Here's what I learned:

It's seemingly easier than I thought

The tutorials and documentation make this seem really nutty and complex. If all you're doing is reading/writing some POJO (Plain Old JavaScript Object, the JS equivalent of my good friend PORO) in your controller, this is all you basically need on your page (assume it's already wrapped in a <form> tag, since it lives in an Active Admin Formtastic call):

%div{'ng-app' => 'myapp'}
  %div{'ng-controller' => 'ThingsController'}
    %ol
      %li{'ng-repeat' => 'thing in things'}
        %h4= "It's a {{ thing.name }}"
        %input{:name => :name, 'ng-model' => 'thing.name'}
    %fieldset
      %input{:name => :name, 'ng-model' => 'thing.name'}
      %input{:type => :button, 'ng-click' => 'addThing()', :value => 'add'}

Then in your JavaScript...well, CoffeeScript (outside of a jQuery.ready block):

app = angular.module('myapp')
app.controller 'ThingsController', ($scope) ->
  $scope.things = [ { name: 'hi', subthings: [ { name: 'bye' } } } ]

  $scope.$watch(
    'things',
    ->
      # look! an u-u-u-u-u-u-pdate
      console.log($scope.things)
    # that true below means "deep dirty check", and $watch will not execute
    # your callback if you don't set it. normally $watch only checks the
    # object properties to see if they have changed, and won't look at
    # nested properties. slower, yes, but whatever.
    , true
  )

  $scope.addThing = ->
    $scope.things.push($scope.thing)
    $scope.thing = {}

That's basically it for something simple.

Simple controller/model nesting is easy and barely documented

Yeah, this works as expected, but good luck finding an example of it anywhere:

%div{'ng-app' => 'myapp'}
  %div{'ng-controller' => 'ThingsController'}
    %ol
      %li{'ng-repeat' => 'thing in things'}
        %h4= "It's a {{ thing.name }}"
        %input{:name => :name, 'ng-model' => 'thing.name'}
        %div{'ng-controller' => 'SubthingsController'}
          %ol
            %li{'ng-repeat' => 'subthing in thing.subthings'}
              %h5= "A subthing! {{ subthing.name }}"
              %input{:name => :name, 'ng-model' => 'subthing.name'}
          %fieldset
            %input{:name => :name, 'ng-model' => 'subthing.name'}
            %input{:type => :button, 'ng-click' => 'addSubthing()', :value => 'add'}
    %fieldset
      %input{:name => :name, 'ng-model' => 'thing.name'}
      %input{:type => :button, 'ng-click' => 'addThing()', :value => 'add'}

The JS you need for this should be obvious.

That's all for day one. Day two will be getting data in and out of this contraption, but I think that will be easier than I think, too.

Apache Include module: Why does it work and yet not work?

I had upgraded Apache on a server a while back, and one of the sites on there still uses Server Side Includes. Whatever. Anyway, the upgraded site's SSI directives stopped working. I neglected to check the included module list first, thinking that if I had missed the module, then the Includes Option and the server-parsed handlers would have just exploded. Nope, they just failed silently with the module not loaded. Added the module back in and it all worked swimmingly. Color me confused.

Net::IMAP parse errors and how to get around them cleanly

I have a spam trainer script in Ruby that goes through the messages on my Citadel server, picks the ones in the spam folder, trans SpamAssassin with them, then deletes them. It hasn't been working for a while, so I decided to dig in and find out why.

Net::IMAP was throwing a ton of parse errors at me. One of the spam messages was being a jerk, and it was tough to find out which one. So for now, I decided to make my Net::IMAP use more robust.

Net::IMAP does a few things when it can't parse a message:

  • It closes your connection to the IMAP server
  • It raises a Net::IMAP::ResponseParseError

After a little experimentation, and liberal use of Net::IMAP.debug, I found that it's possible to recover from these errors and proceed to the next message. All you need is a Net::IMAP factory. My code is roughly something like this:


def make_imap
  imap = Net::IMAP.new(*args)
  imap.authenticate(*sugarpuck)
  imap
end

imap = make_imap
imap.select("Spam")
imap.each do |message_id|
  begin
    message = imap.fetch(message_id, "BODY[TEXT] ENVELOPE").first
    do_stuff_to message
  rescue Net::IMAP::ResponseParseError
    # imap won't work anymore at this point, so reconnect and reset the source folder.
    # the original enumerator above seems to continue to work
    imap = make_imap
    imap.select("Spam")
  end
end

In my final code, I wrapped Net::IMAP in a SimpleDelegator, had it remember what was last selected, then added a reconnect! method to reconnect to IMAP and (potentially) reselect the same folder.

ActiveRecord::Relation.merge is very nice

I just discovered ActiveRecord::Relation#merge. Being able to reuse and factor out all those well-tested finders for database data is really going to make my life easier:

class ThingWithRelation < ActiveRecord::Base
  def self.a_finder
    where(cats: 'Dogs')
  end

  def self.another_finder
    where(rats: 'hiss').group(:cats)
  end
end

OtherThing.joins(:thing_with_relations)
          .merge(ThingWithRelation.a_finder)
          .merge(ThingWithRelation.another_finder)

Making a PORO behave like an ActiveRecord object

There's a bunch of guides for this already, this is for my own purposes. Make a Plain Old Ruby Object look and act like an ActiveRecord one enough to let Rails use it for things like forms and collection rendering and the like:

class MyPoro
  include Virtus

  extend ActiveModel::Naming
  include ActiveModel::Conversion

  def persisted?
    false
  end
end

 

30 Days of Clean(er) Livin': Postscript

Yeah, I wasn't updating this, so I'm just going to cancel it. It was basically a good rigorous test of publishing features of this new system anyway, so it served its purpose. On to other things!

30 Days of Clean(er) Livin': Day 17

  • Water intake: OK.
  • Caffeine: Medium.
  • Alcohol: 1 beer.
  • Candy: 1 fancy coffee.
  • Upper body: 70 pushups/140 crunches/wrists/day.

Much better. Stepping up the upper body workout seems to help.

Unless otherwise indicated, all content is © 2009-2013 John Bintz. All rights reserved.