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 [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

写了一些测试:

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

180行ruby代码搞定游戏2048

时间: 2024-11-25 16:47:08

180行ruby代码搞定游戏2048的相关文章

5行js代码搞定导航吸顶效果

一.HTML布局 首先写HTML布局 <body> <div id="wrap"></div> </body> 二.CSS样式 给点简单的样式 <style> *{ margin: 0; padding: 0; } body{ height: 2000px; background-image: linear-gradient(-180deg, #15f09d 0%, #25A0FF 50%, #fca72b 100%); }

3kb jQuery代码搞定各种树形选择。

自制Jquery树形选择插件. 对付各种树形选择(省市,分类..)90行Jquery代码搞定,少说废话直接上插件代码.稍后介绍使用说明.是之前写的一个插件的精简版. 1.Jquery插件代码 /* * 2012年11月30日14:31:14 * haizi */ (function (j) { j.fn.attrs = function (option) { var root = this, data = []; //默认参数 var def = { url: '/ajax/GetSort/',

史上最牛逼的javascript俄罗斯方块,63行代码搞定啊

<!doctype html><html><head></head><body> <div id="box" style="width:252px;font:25px/25px 宋体;background:#000;color:#9f9;border:#999 20px ridge;text-shadow:2px 3px 1px #0f0;"></div> <script>

10行代码搞定移动web端自定义tap事件

发发牢骚 移动web端里摸爬滚打这么久踩了不少坑,有一定移动web端经验的同学一定被click困扰过.我也不列外.一路走来被虐的不行,fastclick.touchend.iscroll什么的都用过,各有优劣,都不能一步到位.最后实在是被逼无奈,翻阅了不少资料,自定义了一个tap. 效果预览 废话不多说先上效果 移动端预览 一探真假 真的只有10行 插件是基于jQuery的,上代码. //自定义tap $(document).on("touchstart", function(e) {

IOS 一句代码搞定启动引导页

前言引导页,一个酷炫的页面,自从微博用了之后一下就火起来了,对于现在来说一个app如果没有引导页似乎总显那么不接地气,那么为了让我们的app也“高大上”一次,我写了一个demo来实现启动引导页的实现,鉴于我的强迫症,使用起来也是尽可能的简单才算罢休,这不,一句代码就搞定了,而且支持版本更新后显示新的引导页,先看效果: LaunchIntroduction.gif demo中封装了两个方法以供调用,一个是在滚动视图的最后一个页面带有进入按钮,一个是不带按钮,直接滚动就可隐藏引导页. 特点1.使用简

两行代码搞定MFC清屏功能

MFC清除屏幕功能 不少人在使用MFC显示图像都遇到过解决清除屏幕的问题,网上有不少解决方案,但是这些方案都不是很简单,最近本文也遇到了同样的问题,因此对MFC的显示原理进行了深入的研究,找到了最简单的解决方案: (1)获取控件的句柄 (2)调用showWidnow(FALSE). (3)调用showWindow(TRUE); 两句简单的代码轻松搞定MFC清除屏幕功能! 代码如下: void CClearScreenMFCDlg::OnBnClickedLoadImage() { // TODO

Java一行代码搞定两个数互换

提到两个数互换,首先想到的应该是如何不引入第三个数实现,当然也有很多方法. 想到个有趣的事就是怎么用一行代码搞定互换,其实也不难. 先来两种小学生写法: a = a + b - (b = a); a = a * b / (b = a); 以上两句结果一样,就是把a,b值互换. 还有一种无赖写法: a = b + (b = a) * 0; 稍高端的写法是: a = a ^ b ^ (b = a); 这个原理就是一个数异或另一个数两次值不变.

一行代码搞定Adapter

15年Google I/O大会发不了三个重要支持库 >Material design (Android Support Design) >百分比布局:Percent support lib >数据绑定: Data Binding Library 如果你还不没用过Data Bind Library 没关系 那你知道ButterKnife吧 DataBindLibrary 和ButterKnife都是编译时期生成相应的注解文件 因此 在性能上不会有什么大的影响 因此放心的尝试吧.(个人感觉D

一行代码搞定所有屏幕适配

一行代码搞定所有屏幕适配AbViewUtil andbase框架 介绍:http://blog.csdn.net/menglele1314/article/details/46422409 andbase框架 下载:http://download.csdn.net/detail/menglele1314/8786989 导入andbase开源框架 1.首先在你的应用的application中设置: AbAppConfig.UI_WIDTH = 1080; AbAppConfig.UI_HEIGH