Aug 22 2010

Closing soon

Yeah, it’s pretty clear that I haven’t had as much to say on this topic as I thought I would. I’ll be shutting down this blog in a while, and moving the posts to my LiveJournal, which is also where I’ll post anything further I might have to say on my code projects, unless I happen to find myself with an abundance of content again.


Mar 17 2010

Project Progress

I’ve been kind of quiet here since I’ve been kind of sporadic at working on my game.

Mainly I’ve been trying to flesh out the rather flimsy framework I’m starting from into plot and/or puzzles. The hardest part is that the focus of the game and the source of the puzzles are the NPCs, and NPCs are hard to do well. (Ah, ambition.) At any rate I’ve found my first puzzle to code, and have thus been trying to implement a card game in the least extravagant way I can—where “least extravagant” means “which does not require individually implementing all forty cards”.

Yes, it’s a forty-card deck. It’s going to be briscola, not Double Fanucci.


Feb 18 2010

Time in ship’s bells.

I wonder if there might be a better way to do this?

To say (relevant time – a time) as ship’s bell time:

let M be the minutes part of relevant time;

let B be (the remainder after dividing the hours part of relevant time by 4) multiplied by 2;

if B is 0 then change B to 8;

say "[if M is greater than 29][the remainder after dividing B plus 1 by 8][otherwise][B][end if] bell[s] [the remainder after dividing M by 30] min[s]"

When play begins:

change the right hand status line to "[time of day as ship's bell time]".


Feb 10 2010

New project.

It’s the custom to apologize for a long absence, isn’t it?

I haven’t posted here in a while chiefly because with my lexicon app in a usable enough state that I’m not constantly itching to fix bugs, I’ve started a new project: a game in Inform 7. Only I’m not quite so sure how to blog about it here! I’m quite on a beginner’s level with the language; the last project I tried was in Inform 6, which is significantly different—and that was a decade ago in any case.

(For those who haven’t encountered it, Inform 7 is rather striking to look at; the usual programming constructs are present but they are for the most part recast in phrasing inspired by ordinary English. This may make it easier for non-programmers but does obscure things for those of us who are used to neatly–laid-out code. There are some examples at Wikipedia’s article.)

Anyway. As to what I might post here on it — a lot of what I’ve been working on it isn’t really in scope for this blog (room descriptions ho!), but I might post snippets of it anyway. Or, you could leave a comment and let me know what you’d like to hear about.


Jan 10 2010

Userscript: A checkbox that sets a cookie.

Making this work for me was a lot harder than it should have been. (My JavaScript’s still pretty weak.)

myControls = document.createElement("div")
myControls.setAttribute("id", "mycontrols");
myControls.innerHTML = "My controls:";

var myCheck = document.createElement("input");
myCheck.setAttribute("type", "checkbox");
myCheck.setAttribute("id", "myCheck");
if (getCookie("myOption") == "true") { // assumes getCookie is defined
	myCheck.setAttribute("checked", "checked");
};
myCheck.onclick = function () {
	document.cookie="myOption="+document.getElementById("myCheck").checked+"; path=/"
};

var myCheckLabel = document.createElement("label");
myCheckLabel.setAttribute("for", "myCheck");
myCheckLabel.innerHTML = "Option Active";

myControls.appendChild(myCheck);
myControls.appendChild(myCheckLabel);

And then just add myControls wherever you want it.

What this does is build a checkbox (and put a check in it, if your option is already set) and respond to clicks by setting the value of the ‘myOption’ cookie to true or false, depending on whether the box is checked or not. It sets the cookie’s path to /, so that you can use the option on pages on the same site other than the page you’re setting the cookie on.

When you want code execution to depend on your option, just do:

if (getCookie("myOption") == "true") { // assumes getCookie is defined
	// run code here
};

If your option is set, it’ll run the code.

Find a getCookie method if you don’t already have one.


Dec 16 2009

Hiatus.

This blog will be on hiatus for the holiday season till after new year’s.

Those who want to keep up with me in the meantime can do so on Twitter.


Nov 29 2009

Rounding to the next even (or odd) number.

This was another fun one off RMC. Finding out whether an integer is odd or even is pretty basic (i % 2 == 0 ? "even" : "odd"), but if our number doesn’t have the parity we want, what do we do if we want to round to the next even or odd number?

I put together methods to perform the evens and odds equivalent of ceil, floor, and round. It’s likely possible to do this using modulo operations, but the original request used them and wanted to know if there was a different way, so I consciously avoided them.

class Numeric
  # Returns the smallest even number greater than or equal to self.
  def evenize_ceil
    self.quo(2).ceil * 2
  end

  # Returns the largest even number less than or equal to self.
  def evenize_floor
    self.quo(2).floor * 2
  end

  # Rounds to the nearest even number.
  def evenize_round
    (self + 1).evenize_floor
  end 

  # Returns the smallest odd number greater than or equal to self.
  def oddize_ceil
    (self - 1).evenize_ceil + 1
  end

  # Returns the largest odd number less than or equal to self.
  def oddize_floor
    (self - 1).evenize_floor + 1
  end

  # Rounds to the nearest odd number (rounding half away from zero, like #round).
  def oddize_round
    (self + 1).oddize_floor
  end
end

I’m not too fond of these method names, which come from the original thread, though I’m not sure what all would be better (except perhaps making evenize_round, oddize_round into something like round_to_even, round_to_odd). Any suggestions on names that might be more appropriate?


Nov 15 2009

blank? with nested nested attributes

This one has been giving me grief for a while. I was dealing with a model that accepts_nested_attributes_for a second model, which accepts_nested_attributes_for a third model, and I was running into trouble with validations.

Now, ideally I shouldn’t have been running into validation errors at all, because if the input doesn’t pass :reject_if, it doesn’t even get as far as being validated. Of course, my :reject_if was wrong.

The trouble is that this is the usual construction you’ll find if you want to :reject_if something is blank:

accepts_nested_attributes_for :bars, :reject_if => proc { |attributes| attributes.all? {|k,v| v.blank?} }

This is generally useful enough that :all_blank was added to Rails as a shortcut for that proc.

But this doesn’t necessarily work in a case where something with nested attributes itself has nested attributes. I had:

class Foo < ActiveRecord::Base
	has_many :bars

	accepts_nested_attributes_for :bars, :reject_if => proc { |attributes| attributes.all? {|k,v| v.blank?} }
end

class Bar < ActiveRecord::Base
	has_many :bazzes

	accepts_nested_attributes_for :bazzes, :reject_if => proc { |attributes| attributes.all? {|k,v| v.blank?} }

protected
	def validate
		if [bazzes, quux].all?(&:blank?)
		errors.add_to_base("quux or a baz must be specified")
	end
end

I meant it so that if you try to create a Foo with a Bar whose quux and bazzes are blank, it’d reject the Bar. Instead, it bypassed the :reject_if and threw the validation error.

Now, of course the reason is simple: the attributes in that case are not actually all blank. The presence of the third model in the hash throws things off:

>> { :foo => "", :bar => { "1" => {:baz => "" } } }.all? {|k,v| v.blank?}
=> false

So clearly that won’t work.

Since my validation was only checking for blanks anyway I did the moderately DRY thing and let the model decide:

class Foo < ActiveRecord::Base
	has_many :bars

	accepts_nested_attributes_for :bars, :reject_if => proc {|attrs| Bar.new(attrs).invalid? }
end

Really I think it is generally up to the model to decide whether it’s rejectable just as much as if it’s valid; if circumstances were more complicated I might put a rejectable? method in Bar. Edit: And in fact I ended up doing this, because ‘new’ wasn’t playing well with a form that also passed a “_delete” attribute.


Nov 4 2009

Unchaining collect statements

Here’s another exercise off refactormycode I ran across.

Say you have a hierarchy of models, where:

Man has_many :wives
Wife has_many :sacks and belongs_to :man
Sack has_many :cats and belongs_to :wife
Cat has_many :kits and belongs_to :sack
Kit belongs_to :cat

…and you want to find all of StIvesMan’s kits.

Probably the natural instinct—at least, it was for me—is to produce something to the effect of:

StIvesMan.collect(&:wives).flatten.collect(&:sacks).flatten.collect(&:cats).flatten.collect(&:kits)

…which may work, but is pretty suboptimal; you’ve got several calls to the database, for one.

Rails actually has a way to do this all at once built in:

Kit.find(:all,
	:joins => { :cat => { :sack => { :wife => :man } } }
	:conditions => { :men => { :id => StIvesMan.id } })

The :joins hash is essentially a ‘map’ connecting Kits and Men. Note that you’ll only pluralize in your :joins hash when your model has_many, but in :conditions you’ll always pluralize.

Rails will handle the INNER JOINs for the database to look it all up appropriately with one query, and you won’t have to think about the SQL… though if you’ve gotten to the point where you need to do this, you might want to start thinking about SQL anyway, ’cause there’s a pretty decent chance you’ll be needing it soon.

[Original question.]


Nov 1 2009

render versus redirect_to

So I had run across some trouble in my lexicon app where an “update and continue editing” control wasn’t passing across all the information I needed.

The trouble came about because of the difference between render and redirect_to. Google for information about them and you’ll usually be advised that you want to use redirect_to when you want to have the app give the browser a “302 Found” redirect response code. And, since the semantic of that wasn’t what I was looking for, I went for render, and ran into bugs.

The issue is that render :action, despite its name, will only call the template; it won’t call the corresponding action in the controller.

# foo_controller.rb
def update
	respond_to do |format|
		format.html { render :action => "edit" }
	end
end

def edit
	# Any code here won't get called when #update does render :action
	# You need to duplicate the code to the update method,
	# or have #update call redirect_to instead
end

If you want to use redirect_to but you’re a stickler and find “302 Found” doesn’t apply, you can use the :status parameter to return a more appropriate code.