首页 > 代码库 > 180行ruby代码搞定游戏2048

180行ruby代码搞定游戏2048

最今在玩2048这款小游戏,游戏逻辑简单,非常适合我这种对于游戏新入行的人来实现逻辑。于是选择了最拿手的ruby语言来实现这款小游戏的主要逻辑。还是挺简单的,加起来4小时左右搞定。

上代码:

require 'optparse'


module Help
	HELP_TEXT =<<HELP

press buttons for move
  l => move to left
  r => move to right
  t => move to top
  b => move to bottom
press e button to exit game

you can see this help text if your input ruby ruby_2048.rb --help
HELP
	def set_helps
		OptionParser.new do |opts|
			opts.on_tail("-h", "--help", 'This help text.') do
		  	puts HELP_TEXT
			exit!
		end
		end.parse!
	end

end


class Object
	def invoke(need, method)
		if need
			self.send(method) 
		else
			self
		end
	end
end

class R2048
	extend Help

	attr_reader :chessboard
	LEFT = "l"
	RIGHT = "r"
	TOP = "t"
	BOTTOM = "b"
	EXIT = "e"

	def initialize
		R2048.set_helps
	    @chessboard = Array.new(4){|x| Array.new(4){|y| 0}}
	    @init_moved = false
		1.upto(2){|i| generate_init_num}
	end

	def generate_init_num
		return false unless @chessboard.flatten.uniq.select{|chess| chess == 0}.count > 0

		rand_position = rand(16)
		x, y = rand_position/4, rand_position % 4
		until @chessboard[x][y] == 0
			rand_position = rand(16)
			x, y = rand_position/4, rand_position % 4
	    end
	    @chessboard[x][y] = [2, 4][rand(2)]

	end

	def check_and_merge(transpose, reverse)
		moved = false
		temp_chessboard = @chessboard.invoke(transpose, :transpose).map do |row|
			reversed_row = set_jump_step(row.invoke(reverse, :reverse)).invoke(reverse, :reverse)
			moved = true if reversed_row != row.invoke(reverse, :reverse)
			reversed_row
		end.invoke(transpose, :transpose)

		if moved
			@chessboard = temp_chessboard 
			true
		else
			if !@init_moved
				@init_moved = true
				true
			else
			 	false
			end
		end
	end

	def generate_new_num(transpose, pos)
		ungenerated = true

		right_positions = []
		@chessboard.invoke(transpose, :transpose).each_with_index{|row, i| right_positions << i if row[pos] == 0}
		right_position = right_positions[rand(right_positions.count)]

		row_index = 0
		@chessboard = @chessboard.invoke(transpose, :transpose).map do |row|
			if ungenerated && row_index == right_position
				ungenerated = false
				row[pos] = [2, 4][rand(2)]
			end
			row_index += 1
			row
		end.invoke(transpose, :transpose)
		!ungenerated
	end

	def set_jump_step(row)
	  pured = row.select{|chess| chess != 0 }.inject([]) do |sum, chess|
	  	if sum.last == chess
	  		sum.pop 
	  		sum << chess * 2
	  	else
	  		sum << chess
	  	end
	  end
	  pured.concat Array.new(4 - pured.count, 0)
	end

	def display
	  puts "==============================="
      @chessboard.each_with_index do |c, row|
      	puts "#{c[0]}	#{c[1]}	#{c[2]}	#{c[3]}"
      	puts
      end
	end

	def failure_display
		puts "you have failed!!!"
	end

	def run
		display
		key = nil
		until key == "e\n"
			key = gets
			key.gsub!("\n", "")
			return if key == EXIT

			if ![LEFT, RIGHT, TOP, BOTTOM].include? key
				puts "input error" 
				next
			end

			generate = case key
			when LEFT
				if check_and_merge(false, false)
					generate_new_num(false, 3)
				else
					nil
				end
			when RIGHT
				if check_and_merge(false, true)
					generate_new_num(false, 0)
				else
					nil
				end
			when TOP
				if check_and_merge(true, false)
					generate_new_num(true, 3)
				else
					nil
				end
			when BOTTOM
				if check_and_merge(true, true)
					generate_new_num(true, 0)
				else
					nil
				end
			end

			if generate == nil || generate
			  display
			else
			  failure_display
			  return
			end
		end
	end
end


R2048.new.run


写了一些测试:

require 'ruby_2048'

describe R2048 do
   before(:each) do
   	@r2048 = R2048.new
   end
   it "should jump to [2, 0, 0, 0] when input [0, 0, 0, 2]" do  
     @r2048.set_jump_step([0, 0, 0, 2]).should == [2, 0, 0, 0]
   end

   it "should jump to [2, 4, 0, 0] when input [2, 0, 4, 0]" do
   	@r2048.set_jump_step([2, 0, 4, 0]).should == [2, 4, 0, 0]
   end

   it "should jump to [4, 0, 0, 0] when input [2, 0, 2, 0]" do
   	@r2048.set_jump_step([2, 0, 2, 0]).should == [4, 0, 0, 0]
   end

   it "should jump to [2, 4, 4, 0] when input [2, 4, 2, 2]" do
   	@r2048.set_jump_step([2, 4, 2, 2]).should == [2, 4, 4, 0]
   end

   it "should jump to [4, 4, 0, 0] when input [2, 2, 2, 2]" do
   	@r2048.set_jump_step([2, 2, 2, 2]).should == [4, 4, 0, 0]
   end



   it "should + 1 chess if generate_init_num" do
   	expect { @r2048.generate_init_num }.to change{@r2048.chessboard.flatten.count{|chess| chess!= 0} }.by(1)  
   end

   it "should have already have two chess when inited" do
   	expect{@r2048.count} == 2
   end
end

貌似还不错,最新代码请见github:https://github.com/xumc/ruby_2048