[QUIZ] Sokoban (#5)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.grayproductions.net/ruby_quiz/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Ruby isn't the only good thing to come out of Japan. The computer game Sokoban,
invented by Hiroyuki Imabayashi, was introduced by Thinking Rabbit of
Takarazuka, Japan in 1982. This simple game of logic puzzles was an instant
success. It won awards and spawned sequels. Over the years, Sokoban has been
ported to a huge number of platforms. Fan support remains strong and many of
those fans even produce new levels for the game.

This week's quiz is to implement the game of Sokoban with the interface of your
choosing and any extra features you would like to have.

Sokoban (which translates to "Warehouse Man") has simple rules, which basically
amount to push crates into their storage spots in the warehouse. The elements
of the levels are simple: The "man", crates, walls, open floor, and storage.
Different level designers use various symbols to represent these items in level
data files. Here's one possible mix:

  @ for the man
  o for crates
  # for walls
  <space> for open floor
  . for storage

Now because a man or a crate can also be on a storage space, we need special
conditions to represent those setups:

  * for crate on storage
  + for man on storage

Using this, we can build an extremely simple level:

  #####
  #.o@#
  #####

This level is completely surrounded by walls, as all Sokoban levels must be.
Walls are, of course, impassable. In the center we have from left to right: A
storage space, a crate (on open floor), and the man (also on open floor).

(The original Sokoban levels were 19 x 16, but later levels have varied in
size.)

The game is played by moving the man up, down, left and right. When the man
moves towards a crate, he may push it along in front of him as long as there is
no wall or second crate behind the one being pushed. A level is solved when all
crates are on storage spaces.

Given those rules, we can solve our level above with a single move to the left,
yielding:

  #####
  #*@ #
  #####

That simple system can lead to some surprisingly complicated mind benders, but
please don't take my word for it. Here are some levels to test your game engine
and your logic skills:

  http://www.grayproductions.net/ruby_quiz/sokoban_levels.txt

(Note: These levels are Copyrighted by Thinking Rabbit. You may play them but
not profit from them in any way.)

Be warned, Sokoban is extremely addictive!

Ruby Quiz wrote:

This week's quiz is to implement the game of Sokoban with the interface of your
choosing and any extra features you would like to have.

Interesting. In fact I did a cross between Sokoban and Dr. Mario (a nice variation of Tetris) for this year's first Ludum Dare 48 hour game development contest.

See http://www.ludumdare.com/user/1011/Infectoban.png for a screenshot of this.

The game itself is currently still available from http://noegnud.sourceforge.net/flgr/Infectoban-dll.zip (windows package) and http://noegnud.sourceforge.net/flgr/Infectoban-source.zip (linux package, requires ruby-sdl).

I also took part in this year's second contest -- that time I used Ruby/Gosu and did a cave exploration / flying / shooting style game with random maps. See http://www.mechanicalcat.net/tech/ld48/home/flgr/diary

Other Ruby entries for this year's second contest were a very addicting jump-and-flee (http://www.mechanicalcat.net/tech/ld48/home/jsb/diary\) and a game with a random world with different species of monsters (see http://www.mechanicalcat.net/tech/ld48/home/survivor\).

For anybody who hasn't created games with Ruby yet: It is surprisingly easy and combined with the productivity boost you get from the 48 hour contests it is a *lot* of fun. :slight_smile:

I'm glad you like this one.

I'm a pretty big game nut and I think there are a lot of interesting problems in the game space, so left to my own devices we'll probably see plenty game quizzes over time.

Of course, for those of you who don't like that you can just submit tons of quizzes, so I don't get a chance to run my own... :smiley:

James Edward Gray II

···

On Oct 29, 2004, at 8:19 AM, Florian Gross wrote:

For anybody who hasn't created games with Ruby yet: It is surprisingly easy and combined with the productivity boost you get from the 48 hour contests it is a *lot* of fun. :slight_smile:

Thank you for causing me to write my first ever game programme in any language.
I am including my solution here. (I don't know any better way }. I
could solve using the Curses Library example given in Pickaxe II
book.

# solution to [QUIZ] Sokoban (#5)
# G.D.Prasad , 1st Nov , 04 , 5.00 PM
# run as ---- ruby sokoban.rb sokobangame

#file sokoban.rb

require 'curses'
include Curses
$a=
i=0
file = File.new(ARGV[0],"r")
while line =file.gets
  lineArr=line.split("")
  $a << lineArr
  if lineArr.include?("@")
        $x= lineArr.index("@")
        $y= i
  end
  i += 1
end

  $M = '@'
  $C='o'
  $W='#'
  $F= " "
  $S='.'
  $CS='*'
  $MS='+'

class Store
  HEIGHT = 10
  STORE =$a
  def initialize
    @top = (Curses::lines - HEIGHT)/2
    draw
  end
  def left
  $x=STORE[$y].index("@") || STORE[$y].index("+")
  temp=STORE[$y][$x-1]
  case temp
        when $F
                if STORE[$y][$x-1,2]==[$F,$M]
                 STORE[$y][$x-1,2]=[$M,$F]
                elsif STORE[$y][$x-1,2]==[$F,$MS]
                 STORE[$y][$x-1,2]=[$M,$S]
                end
        when $C
                if STORE[$y][$x-2] == $F
                        STORE[$y][$x-2,3]=[$C,$M,$F]
                elsif STORE[$y][$x-2] == $S
                        STORE[$y][$x-2,3]=[$CS,$M,$F]
                end
        when $CS
                if STORE[$y][$x-2,3] == [$S,$CS,$M]
                        STORE[$y][$x-2,3]=[$CS,$M,$F]
                end
        when $S
                if STORE[$y][$x-2,3]==[$S,$S,$M]
                STORE[$y][$x-2,3]=[$S,$MS,$F]
                elsif STORE[$y][$x-1,2]==[$S,$MS]
                           STORE[$y][$x-1,2]=[$MS,$S]
                else
                        STORE[$y][$x-1,2]=[$MS,$F]
                end
        else beep
  end
  end

  def right
  $x=STORE[$y].index("@") || STORE[$y].index("+")
  temp=STORE[$y][$x+1]
  case temp
        when $F
                if STORE[$y][$x,2]==[$M,$F]
                 STORE[$y][$x,2]=[$F,$M]
                elsif STORE[$y][$x,2]==[$MS,$F]
                 STORE[$y][$x,2]=[$S,$M]
        end
        when $C
                if STORE[$y][$x+2] == $F
                        STORE[$y][$x,3]=[$F,$M,$C]
                elsif STORE[$y][$x+2] == $S
                        STORE[$y][$x,3]=[$F,$M,$CS]
                end
        when $CS
                if STORE[$y][$x,3] == [$M,$CS,$S]
                        STORE[$y][$x,3]=[$F,$MS,$CS]
                end
        when $S
                if STORE[$y][$x,3]==[$M,$S,$S]
                STORE[$y][$x,3]=[$F,$MS,$S]
                elsif STORE[$y][$x,2]==[$MS,$S]
                           STORE[$y][$x,2]=[$S,$MS]
                elsif STORE[$y][$x,2]==[$M,$S]
                           STORE[$y][$x,2]=[$F,$MS]
                end
        else beep
  end
  end
  def up
  $x=STORE[$y].index("@") || STORE[$y].index("+")
  temp=STORE[$y-1][$x]
  case temp
        when $F
                if [ STORE[$y][$x],STORE[$y-1][$x] ]==[$M,$F]
                 STORE[$y][$x],STORE[$y-1][$x]=$F,$M
                 $y -= 1
                elsif [ STORE[$y][$x],STORE[$y-1][$x] ]==[$MS,$F]
                 STORE[$y][$x],STORE[$y-1][$x]=$S,$M
                 $y -= 1
                end
        when $C
                if STORE[$y-2][$x] == $F
                 STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]=$F,$M,$C
                 $y -= 1
                elsif STORE[$y-2][$x] == $S
                 STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]=$F,$M,$CS
                 $y -= 1
                end
        when $CS
                if [STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]]==
[$M,$CS,$S]
STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]=$F,$MS,$CS
                 $y -= 1
                elsif
[STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]]== [$MS,$CS,$S]
                 STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]=$S,$MS,$CS
                 $y -= 1
                end
        when $S
                if [STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]]==[$M,$S,$S]
                STORE[$y][$x],STORE[$y-1][$x],STORE[$y-2][$x]=$F,$MS,$S
                 $y -= 1
                elsif [STORE[$y][$x],STORE[$y-1][$x]]==[$MS,$S]
                 STORE[$y][$x],STORE[$y-1][$x]=$S,$MS
                 $y -= 1
                elsif [STORE[$y][$x],STORE[$y-1][$x]]==[$M,$S]
                 STORE[$y][$x],STORE[$y-1][$x]=$F,$MS
                 $y -= 1
                end
        else beep
  end
  end
  def down
  $x=STORE[$y].index("@") || STORE[$y].index("+")
  temp=STORE[$y+1][$x]
  case temp
        when $F
                if [ STORE[$y][$x],STORE[$y+1][$x] ]==[$M,$F]
                 STORE[$y][$x],STORE[$y+1][$x]=$F,$M
                 $y += 1
                elsif [ STORE[$y][$x],STORE[$y+1][$x] ]==[$MS,$F]
                 STORE[$y][$x],STORE[$y+1][$x]=$S,$M
                 $y += 1
                end
        when $C
                if STORE[$y+2][$x] == $F
                 STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]=$F,$M,$C
                 $y += 1
                elsif STORE[$y+2][$x] == $S
                 STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]=$F,$M,$CS
                 $y += 1
                end
        when $CS
                if [STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]]==
[$M,$CS,$S]
STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]=$F,$MS,$CS
                 $y += 1
                end
        when $S
                if [STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]]==[$M,$S,$S]
                STORE[$y][$x],STORE[$y+1][$x],STORE[$y+2][$x]=$F,$MS,$S
                 $y += 1
                elsif [STORE[$y][$x],STORE[$y+1][$x]]==[$MS,$S]
                 STORE[$y][$x],STORE[$y+1][$x]=$S,$MS
                 $y += 1
                elsif [STORE[$y][$x],STORE[$y+1][$x]]==[$M,$S]
                 STORE[$y][$x],STORE[$y+1][$x]=$F,$MS
                 $y += 1
                end
        else beep
  end
  end
  def draw
    setpos(@top-1, 0)
    addstr(STORE.to_s)
    refresh
  end
end

init_screen
begin
  crmode
  noecho
  stdscr.keypad(true)
   
  store = Store.new

  loop do
    case getch
    when ?Q, ?q : break
    when Key::LEFT : store.left
    when Key::RIGHT : store.right
    when Key::UP : store.up
    when Key::DOWN : store.down
    else beep
    end
    store.draw
  end
ensure
  close_screen
end

···

On Fri, 29 Oct 2004 22:19:03 +0900, Florian Gross <flgr@ccan.de> wrote:

Ruby Quiz wrote:

> This week's quiz is to implement the game of Sokoban with the interface of your
> choosing and any extra features you would like to have.

---------------------------------------
#file sokobangame
    #####
    # #
    #o #
  ### o##
  # o o #
### # ## # ######
# # ## ##### ..#
# o o ..#
##### ### #@## ..#
    # #########
    #######

Florian Gross wrote:

Ruby Quiz wrote:

This week's quiz is to implement the game of Sokoban with the interface of your
choosing and any extra features you would like to have.

Interesting. In fact I did a cross between Sokoban and Dr. Mario (a nice variation of Tetris) for this year's first Ludum Dare 48 hour game development contest.

And here's my solution to this quiz. I used Ruby/Gosu again. It's very simplistic and doesn't even include a turn counter, but it should still be playable and work correctly.

You can use cursor left / right / up / down to move. ESC restarts the current level.

Windows executable: http://noegnud.sourceforge.net/.flgr/sokoban.zip
Linux package: http://noegnud.sourceforge.net/.flgr/sokoban.tar.gz

I've also attached the source code to this mail for convenience.

game.rb (4.47 KB)

There is an interesting implementation of the Sobokan game as a
Ruby-GNOME2 sample:

http://ruby-gnome2.sourceforge.jp/hiki.cgi?Sokoban

Cheers,

···

On Fri, 29 Oct 2004 22:51:46 +0900, James Edward Gray II <james@grayproductions.net> wrote:

On Oct 29, 2004, at 8:19 AM, Florian Gross wrote:

> For anybody who hasn't created games with Ruby yet: It is surprisingly
> easy and combined with the productivity boost you get from the 48 hour
> contests it is a *lot* of fun. :slight_smile:

I'm glad you like this one.

I'm a pretty big game nut and I think there are a lot of interesting
problems in the game space, so left to my own devices we'll probably
see plenty game quizzes over time.

Of course, for those of you who don't like that you can just submit
tons of quizzes, so I don't get a chance to run my own... :smiley:

James Edward Gray II

--
Laurent

"G.Durga Prasad" <gdprasad@gmail.com> wrote...

require 'curses'

I'm rubying on Windows. Is there a way I can do this? Or something even a
little bit like it? I can't find any kind of terminal library for Ruby for
Windows.

Thanks,
Dave

I was very surprised when my company got contracted last year to write a simple game. People get paid to do this? I couldn't believe it, but I wrote it and they did pay me. Even more interesting, the game they wanted wasn't much more complicated than what we're playing with here.

James Edward Gray II

···

On Nov 1, 2004, at 5:41 AM, G.Durga Prasad wrote:

Thank you for causing me to write my first ever game programme in any language.

There's a minor bug in here somewhere. When I play the first level and push a crate into the middle row of storage, I can't then move above it and push it down, if that makes any sense.

Hope that helps.

James Edward Gray II

···

On Nov 1, 2004, at 5:41 AM, G.Durga Prasad wrote:

Thank you for causing me to write my first ever game programme in any language.
I am including my solution here. (I don't know any better way }. I
could solve using the Curses Library example given in Pickaxe II
book.

Compile pdcurses, then build curses.so linking against it.

···

On Mon, Nov 01, 2004 at 09:58:50PM +0900, Dave Burt wrote:

"G.Durga Prasad" <gdprasad@gmail.com> wrote...
> require 'curses'

I'm rubying on Windows. Is there a way I can do this? Or something even a
little bit like it? I can't find any kind of terminal library for Ruby for
Windows.

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com