|
osdir.com mailing list archive F.A.Q. -since 2001! |
|
|
|
Subject: Ruby Tetris (Expert 23 Solution) - msg#00138List: lang.perl.qotw.discuss
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 #23Mark 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/TkHi, 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 summaryI 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/TkHi, 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
|
|