180 lines of Ruby Code deal with game 2048

Source: Internet
Author: User

Currently, I am playing the 2048 game. The game logic is simple and is very suitable for new players like me to implement logic. So I chose the best Ruby language to implement the main logic of this game. It's quite simple. It takes about four hours to complete.

Code:


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 [email protected]_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

I wrote some tests:



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

Looks pretty good, see GitHub for the latest code: https://github.com/xumc/ruby_2048


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.