Jay McGavren's Journal

2010-05-17

Someone's been there...

you’ve got to be the best

you’ve got to change the world

and use this chance to be heard

your time is now

don’t,

let yourself down

don’t let yourself go

your last chance has arrived

–Muse, “Butterflies and Hurricanes”

I don’t really like the song, but they’ve got another one titled “Thoughts of a Dying Atheist”.

Read more...
2010-04-24

Phoenix IGDA Game Jam - Lava Game

Our in-progress game for Android phones, where you move a character around and dig trenches for lava to flow through. Surprisingly easy work once you have the SDK installed and configured. Works great on both an emulator and the hardware.

We have the character movement and grid of dirt squares going. Artwork is, um, a placeholder. :)

lava_in_progress.png

Read more...
2010-04-18

Ruby tweets!

A while back I stumbled across a page of JAPHs, or Just Another Perl Hacker scripts. This was an ongoing competition Perl users had years ago to print the phrase “Just Another Perl Hacker” in the most convoluted way possible, utilizing little-known tricks of the language. They usually stuffed these mini-scripts into their Usenet signatures. I had always admired JAPHs, and decided to try my hand at a Ruby version. But I needed a forum, and I hadn’t been on Usenet in years.

So what’s the modern version? Why, Twitter, of course! The 140-character limit would provide an extra level of challenge, enough so that I didn’t feel a need restrict myself to printing “Just Another Ruby Hacker”.

I started simple, printing a wave to STDOUT.

ruby -e "i=0;loop{puts ' '*(29*(Math.sin(i)/2+1))+'|'*(29*(Math.cos(i)/2+1)); i+=0.1}" #ruby

Copy-paste that to a terminal, and hit Enter. (If you copy from Twitter, there’s no need to worry about line breaks or the Favorite star; the browser strips them.) You get something like this:

               |||||||||||||||||||||||||||||||||||||||||||
                   ||||||||||||||||||||||||||||||||||||||||||
                       ||||||||||||||||||||||||||||||||||||||||
                          ||||||||||||||||||||||||||||||||||||||
                            ||||||||||||||||||||||||||||||||||
                             ||||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||
                           |||||||||||||||||||||
                        ||||||||||||||||||
                     |||||||||||||||
                 ||||||||||||||
            ||||||||||||||
        |||||||||||||||
     ||||||||||||||||||
  |||||||||||||||||||||
|||||||||||||||||||||||||
||||||||||||||||||||||||||||||
 ||||||||||||||||||||||||||||||||||
   ||||||||||||||||||||||||||||||||||||||
       |||||||||||||||||||||||||||||||||||||||||
          ||||||||||||||||||||||||||||||||||||||||||
               |||||||||||||||||||||||||||||||||||||||||||
                   ||||||||||||||||||||||||||||||||||||||||||
                       ||||||||||||||||||||||||||||||||||||||||
                          |||||||||||||||||||||||||||||||||||||
                            ||||||||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||
                           |||||||||||||||||||||
...

Here’s a more-readable version:

#Have to initialize i before incrementing.
i=0;

#loop{} is a few characters less than 1000.times{}.
#People know where Ctrl-C is on their keyboards. :)
#Brackets cost less characters than do/end.
loop {

  #sin() and cos() range -1 to 1.
  #We change result to range 0 to 1.
  left_width = Math.sin(i) / 2 + 1
  wave_width = Math.cos(i) / 2 + 1

  #Indentation of wave's left side.
  print ' ' * (29*left_width)
  #Wave's width, which decides placement of right side.
  print '|' * (29*wave_width)

  print "n"

  #Increasing input for sin()/cos() makes wave undulate.
  i += 0.1

}

That’s still among my favorites. But anybody can use puts(). The next was more ambitious…

Read more...
2010-04-16

Name the Top X of All Time - go!

A friend asked for a quick script to help him sort a top-50 list of games. Here’s what I threw together:

#!/usr/bin/env ruby

# rank.rb - Rank a list of items, two at a time.

# Copyright (c) 2010 Jay McGavren
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


require 'fileutils'
require 'curses'

file_name = ARGV[0] or fail "Usage: #{__FILE__} filename.txt"

def random_index(list)
  rand(list.length)
end

def write_store(name, entries)
  File.open(name, 'w+') do |file|
    file.puts(entries)
  end
end

def read_store(name)
  entries = []
  File.open(name) do |file|
    entries = file.readlines
  end
  entries
end

entries = read_store(file_name)

Curses.noecho
Curses.init_screen
Curses.stdscr.keypad(true)

loop do
  # Pick 2 random items.
  indices = [0, 0]
  while (indices[0] == indices[1]) do
    indices = [random_index(entries), random_index(entries)]
  end
  indices.sort!
  # Present them.
  Curses.setpos(0, 0)
  Curses.addstr(<<-EOD)
    Which is better?
    1. #{entries[indices[0]]}
    2. #{entries[indices[1]]}
    3. Exit
  EOD
  begin
    result = nil
    until ([?1, ?2, ?3].include?(result)) do
      result = Curses.getch
    end
    case result
    # Higher one chosen?
    when ?1
      # Do nothing.
    # Otherwise:
    when ?2
      # Swap them.
      entries[indices[0]], entries[indices[1]] = entries[indices[1]], entries[indices[0]]
    # Exit chosen?
    when ?3
      # Exit loop.
      break
    else
      fail "wtf?"
    end
  end
  write_store("#{file_name}.bak", entries)
end

# Save.
FileUtils.mv("#{file_name}.bak", file_name)

Curses.close_screen

It picks two entries at random, and swaps their positions if you choose the later one as your favorite. Lather, rinse, repeat. Like a bubble sort without adjacent items.

Curses? Well, it was the quickest way to get Ruby to respond to a single keypress. And since you’re going to be making a lot of entries, I didn’t want you to have to hit Enter after every one.

So here you see my list of artists with 5-star songs, originally in alphabetical order, but with my favorites starting to bubble to the top:

Read more...
2010-04-10

(cackle)

# Settings specified here will take precedence over those in config/environment.rb

# In the development environment your application's code is reloaded on
# every request.  This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false

#...

class <<STDOUT
  def write(string)
    super(`banner -w 40 "#{string.gsub(/[^A-Za-z0-9]/, ' ')}"`)
  end
end

Read more...