您的位置:首页 > 编程语言 > Ruby

180行ruby代码搞定游戏2048

2016-01-17 15:44 555 查看
最今在玩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

后记:

一篇博客介绍c++版命令行2048居然写了500多行,见http://blog.csdn.net/yc7369/article/details/29416819, 恰恰证明了ruby的简洁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: