osdir.com
mailing list archive F.A.Q. -since 2001!



Subject: Ruby Tetris (Expert 23 Solution) - msg#00138

List: lang.perl.qotw.discuss

Mail Archive Navigation:
by Date: Prev Next Date Index by Thread: Prev Next Thread Index

Since different language solutions are growing more common, I'll submit my Ruby solution.

I've been learning Ruby these past few weeks, so it's still probably rough around the edges. That would be my fault, not Ruby's, which is a fun language that I think is worth a look.

My solution only implements the first milestone, because that was a lot of work and I'm tired now. <laughs>

I built it with Ruby 1.8.2 preview 2, but I BELIEVE it will run on 1.6.x (standard in the mentioned Mac OS X testing environment). All you would have to do is:

% ruby unix_term_tetris.rb

WARNING: As the name suggests, the interface I built only runs on Unix. It would be trivial to convert it to Windows, but since I'm not a Windows guy it's someone else's triviality. <laughs>

My solution uses two files, which should be placed in the same directory.

Enjoy.

James Edward Gray II

=== unix_term_tetris.rb ===

#!/usr/bin/ruby -w

require "io/wait"

require "tetris"

system "stty raw -echo"

game = Tetris::Game.new

system "clear"
puts game.draw

game.start

loop do
if game.run
system "clear"
puts game.draw
end

break if game.over?

if STDIN.ready?
case STDIN.getc
when ?q, ?Q, ?\C-c
break
when ?z, ?Z
game.move_left
when ?x, ?X
game.move_right
when ?/, ??
game.move_drop
when ?', ?"
game.move_rotate
end
system "clear"
puts game.draw
end
end

END { system "stty -raw echo" }

__END__

=== tetris.rb ===

#!/usr/bin/ruby

module Tetris
class Block
@@blocks = [ [ ["#", "#"],
["#", "#"] ],
[ [" ", "@", "@"],
["@", "@", " "] ],
[ ["%", "%", " "],
[" ", "%", "%"] ],
[ ["*", "*", "*"],
["*", " ", " "] ],
[ ["&", "&", "&"],
[" ", " ", "&"] ],
[ ["$", "$", "$"],
[" ", "$", " "] ],
[ ["+", "+", "+", "+"] ] ]

attr_reader :x, :y

def initialize(x = nil, y = nil, type = rand(7))
@x = if x.nil?
if type == 6
3
else
4
end
else
x
end
@y = if x.nil?
if type == 6
0
else
-1
end
else
y
end
@dir = 1

@type = type
@block = @@blocks[@type]
end

def drop
@y += 1
end

def move_left
@x -= 1
end

def move_right
@x += 1
end

def rotate
copy = [ ]
@block[0].size.times { copy.push((" " * @block.size).split
"") }
@block.each_with_index do |row, y|
row.each_with_index do |square, x|
copy[x][copy[0].size - 1 - y] = square
end
end
@block = copy
@dir = if @dir == 4 then 1 else @dir + 1 end

case @type
when 6
case @dir
when 1, 3
@x -= 2
@y += 2
when 2, 4
@x += 2
@y -= 2
end
when 1, 2
case @dir
when 1, 3
@x -= 1
@y += 1
when 2, 4
@x += 1
@y -= 1
end
when 3, 4, 5
case @dir
when 1
@x -= 1
@y += 1
when 2
@y -= 1
when 4
@x += 1
end
end
end

def to_a
return Marshal.load(Marshal.dump(@block))
end

def to_s
str = ""
@block.each do |row|
str += row.join() + "\r\n"
end
return str
end
end

class Board
attr_reader :line_count, :touch_count

def initialize(block = Block.new, next_block = Block.new)
@board = [ ]
1.upto 20 do
row = (" " * 10).split ""
@board << row
end

@block = block
@next_block = next_block

@line_count = 0
@touch_count = 0
end

def block=(block)
@board = to_a

@line_count = 0
0.upto @board.size - 1 do |i|
unless @board[i].include? " "
@board.delete_at i
@board.unshift((" " * 10).split "")
@line_count += 1
end
end

@touch_count = 0
count_block = @block.to_a
count_block.each_with_index do |row, i|
next if @block.y + i < 0
row.each_with_index do |square, j|
if row[j] != " "
if j == 0 and ( @block.x - 1 ==
-1 or
@board[@block.y + i][@block.x - 1] !=
" " )
@touch_count += 1
end
if j == row.size - 1 and (
@block.x + 1 + j >= 10 or
@board[@block.y + i][@block.x + 1 + j]
!= " " )
@touch_count += 1
end
if i == 0 and ( @block.y - 1 ==
-1 or
@board[@block.y - 1][@block.x + j] !=
" " )
@touch_count += 1
end
if i == count_block.size - 1 and
( @block.y + 1 + i >= 20 or
@board[@block.y + 1 + i][@block.x + j]
!= " " )
@touch_count += 1
end
end
end
end

@block = @next_block
@next_block = block
end

def can_drop?
block = @block.to_a
block.each_with_index do |row, i|
next if @block.y + 1 + i < 0
return false if @block.y + 1 + i > 19
row.each_with_index do |square, j|
if row[j] != " " and
@board[@block.y + 1 + i][@block.x + j] !=
" "
return false
end
end
end

return true
end

def can_left?
block = @block.to_a
block.each_with_index do |row, i|
next if @block.y + i < 0
row.each_with_index do |square, j|
return false if @block.x - 1 + j < 0
if row[j] != " " and
@board[@block.y + i][@block.x - 1 + j] !=
" "
return false
end
end
end

return true
end

def can_right?
block = @block.to_a
block.each_with_index do |row, i|
next if @block.y + i < 0
row.each_with_index do |square, j|
return false if @block.x + 1 + j >= 10
if row[j] != " " and
@board[@block.y + i][@block.x + 1 + j] !=
" "
return false
end
end
end

return true
end

def can_rotate?
begin
@block.rotate
block = @block.to_a
block.each_with_index do |row, i|
next if @block.y + i < 0
return false if @block.y + i > 19
row.each_with_index do |square, j|
return false if @block.x + j < 0
return false if @block.x + j >=
10
if row[j] != " " and
@board[@block.y + i][@block.x + j] !=
" "
return false
end
end
end

return true
ensure
3.times { @block.rotate }
end
end

def drop
if can_drop?
@block.drop
return true
else
return false
end
end

def full?
if @board[0].join("") !~ /^ {10}$/
return true
else
return false
end
end

def move_left
if can_left?
@block.move_left
return true
else
return false
end
end

def move_right
if can_right?
@block.move_right
return true
else
return false
end
end

def rotate
if can_rotate?
@block.rotate
return true
else
return false
end
end

def to_a
copy = Marshal.load(Marshal.dump(@board))

block = @block.to_a
block.each_with_index do |row, i|
next if @block.y + i < 0
row.each_with_index do |square, j|
next if row[j] == " "
copy[@block.y + i][@block.x + j] =
square
end
end

return copy
end

def to_s(level, lines, score)
str = ""
to_a.each do |row|
str += "|" + row.join() + "|\r\n"
end
str += ("-" * 12) + "\r\n"

details = [ "Level #{level}", "Lines #{lines}", "Score
#{score}",
"", "Next", "" ]
@next_block.to_a.each do |row|
details.push(row.join(""))
end
details.push("")

display = str.split(/\r\n/).zip(details)
display.collect! do |e|
if e[1].nil?
e[0] + "\r\n"
else
e[0] + " " + e[1] + "\r\n"
end
end

return display.join("");
end
end

class Game
attr_reader :board

def initialize
@board = Board.new

@piece_floating = false

@level = 1
@lines = 0
@score = 0
end

def draw
return @board.to_s(@level, @lines, @score)
end

def move_drop
@board.drop
end

def move_left
@board.move_left
end

def move_right
@board.move_right
end

def move_rotate
@board.rotate
end

def over?
return @board.full?
end

def run
if (@last_drop + (1 / 1.3 ** (@level - 1))) - Time.now
<= 0
unless @board.drop
if @piece_floating
@board.block = Block.new
@lines += @board.line_count
@score += @board.touch_count
@score += @board.line_count *
10 * @level
@level += 1 if @lines > 0 and
@lines % 10 == 0
@piece_floating = false
else
@piece_floating = true
end
end
@last_drop = Time.now
return true
end
return false
end

def start
@last_drop = Time.now
end
end
end

__END__




Thread at a glance:

Previous Message by Date:

Re: Solutions and Discussion for Perl Quiz of the Week #23

Mark Jason Dominus wrote: On Fri, Sep 10, 2004 at 05:07:21PM -0400, Daniel Martin wrote: The problem with his code was that when Matthew Walton posted it to the mailing list, an extra space was inserted into the source. Since haskell is (or at least, is usually) a language where indentation is significant, this meant it didn't compile. D'oh! Haskell's base definition includes curly brace delimiters for the blocks, similar to Perl or C. It only becomes whitespace-sensitive if you leave out the delimiters; then the indentation is used to infer the block structure. I'll use curly brace syntax next time!

Next Message by Date:

[SPOILER] Solution Expert Quiz 23 in Ruby/Tk

Hi, I implemented tetris in ruby with Ruby/Tk. Since im not an tk-expert, there is still much space for improvement of the interface (it's still very simply and slow). My version has two parts, a server and client. I didn't implement the 2-player variant of the 2nd milestone but another one: Two players play against each other. If one player deletes two or more lines, the opponent gets some extra lines. The player who crashes first loses the game. To start a game, first start the server with: ruby tserver.rb [-p port] and one or two clients with ruby tclient.rb -n nick [-a server-address] [-p port] The interface is very incomplete but does the job for this quiz, I think. I put the files as attachment to this mail because the are a little large, hope this is ok. Gruß Frank tcore.rb Description: Text document tclient.rb Description: Text document tserver.rb Description: Text document

Previous Message by Thread:

minor problem in summary

I was reading through Sample solutions and discussion Perl Quiz of The Week #23 (20040901) and saw """ The results for the Perl code are: ... dalke.py B N L U ... The results for the non-Perl code are: dalke.py skip """ How did that come about? Since there are timings for my program, I'll assume that it did run, and I know it wasn't in Perl. :) Andrew dalke-DxsMES/F/+GyoL73aWPbVUEOCMrvLtNR@xxxxxxxxxxxxxxxx

Next Message by Thread:

[SPOILER] Solution Expert Quiz 23 in Ruby/Tk

Hi, I implemented tetris in ruby with Ruby/Tk. Since im not an tk-expert, there is still much space for improvement of the interface (it's still very simply and slow). My version has two parts, a server and client. I didn't implement the 2-player variant of the 2nd milestone but another one: Two players play against each other. If one player deletes two or more lines, the opponent gets some extra lines. The player who crashes first loses the game. To start a game, first start the server with: ruby tserver.rb [-p port] and one or two clients with ruby tclient.rb -n nick [-a server-address] [-p port] The interface is very incomplete but does the job for this quiz, I think. I put the files as attachment to this mail because the are a little large, hope this is ok. Gruß Frank tcore.rb Description: Text document tclient.rb Description: Text document tserver.rb Description: Text document
blog comments powered by Disqus

Home | News | Sitemap | FAQ | advertise | OSDir is an Inevitable website. GBiz is too!