April 2010

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

development
java

Permalink

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…

Continue Reading »

development
ruby

Permalink

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:

Continue Reading »

development
ruby

Permalink

(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

Continue Reading »

general

Permalink

#thelegendofchung

krysvs Once, @heisenthought coded a dating site in binary because he was bored. #thelegendofchung
about 9 hours ago from Swift

jaymcgavren @krysvs I heard @heisenthought’s favorite tool for searching server logs is “cat”. #thelegendofchung
about 8 hours ago from web

squanderingtime @jaymcgavren @krysvs I heard @heisenthought could bring a box out of kernel panic by glaring at it. #thelegendofchung
about 8 hours ago from Tweetie

alandd RT @jaymcgavren: @krysvs I heard @heisenthought’s favorite tool for searching server logs is “cat”. #thelegendofchung
about 8 hours ago from web

jaymcgavren I heard @heisenthought has to overclock his computer to play Quake… since it’s a restored UNIVAC. #thelegendofchung
about 7 hours ago from web

krysvs @squanderingtime @jmcgavren Bill Gates once personally apologized to @heisenthought (for everything). #thelegendofchung
about 7 hours ago from Swift

squanderingtime I heard @heisenthought could make a fully functional webserver using only a Speak & Spell #thelegendofchung
about 7 hours ago from Tweetie

jaymcgavren I heard @heisenthought had a client beg him to do Search Engine Optimization… it was Google. #thelegendofchung
about 7 hours ago from web

krysvs I heard @heisenthought doesn’t have an SSN; he has a MAC address. #thelegendofchung
about 6 hours ago from Swift

development
friends

Permalink