Ruby 180 行 ruby 代码搞定游戏 2048

hmilym · 2014年07月07日 · 最后由 felixkyang 回复于 2014年09月18日 · 4942 次阅读

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

如有错误,还望斧正。

四格缩进略感不习惯……

@hmilym 这个是用 rubymotion 运行吗?

#2 楼 @gsky 命令行界面,哈哈。打算再做一个 coco2d-js 版本的。

继续写个 ai 吧。

竟然需要 180 行

是挺简单的。

我也来一个,请无视逻辑部分

$score = 0
$changed = false

lines  = []; 4.times { lines << [nil, nil, nil, nil] }

helper        = -> {
                      puts "┌───────────────┐"
                      puts "│ Use your keyborad.           │"
                      puts "│ W: Up A:Left S:Down D:Right  │"
                      puts "│ Return: Next step            │"
                      puts "└───────────────┘"
                    }

score         = -> {
                      puts "┌───────────────┐"
                      puts "│Score:        #{"%016d" % $score}│"
                      puts "└───────────────┘"
                    }

header        = -> { puts "┌───┬───┬───┬───┐" }
block         = -> n { "_#{"_" * (4 - n.to_s.length)}#{n}_│" }
liner         = -> a { s = "│" ; a.each {|i| s += block.call i }; puts s}
footer        = -> { puts "└───┴───┴───┴───┘" }

new_num = -> {
                loop do
                  x, y = rand(4), rand(4)
                  if lines[x][y].nil?
                    lines[x][y] = rand < 0.8 ? 2 : 4
                    break
                  end
                end
              }

start = -> { 2.times { new_num.call } }

restart = -> {
                loop do
                  puts "Play again? (Y/N)"
                  str = gets
                  case str.rstrip.to_sym
                  when :Y, :y
                    lines.clear; 4.times { lines << [nil, nil, nil, nil] }
                    $score = 0; new_num.call
                    break
                  when :N, :n; exit; end
                end
              }

game_over     = -> {
                      puts "┌───────────────┐"
                      puts "│          Game Over!          │"
                      puts "└───────────────┘"
                      restart.call
                    }

congrulations = -> {
                      puts "┌───────────────┐"
                      puts "│Congrulations!You've got 2048!│"
                      puts "└───────────────┘"
                      restart.call
                    }

refresh = -> { score.call; header.call; lines.each {|l| liner.call l }; footer.call}

complement = -> l { (4 - l.size).times { l << nil } if l.size < 4 }

arrange = -> line {#, size {
                          case line.size
                          # when 0, 1
                          when 2
                            if line[0] == line[1]
                              line[0] += line[1]; line[1] = nil; $score += line[0]
                            end
                          when 3
                            if line[0] == line[1]
                              line[0] += line[1]; line[1], line[2] = line[2], nil; $score += line[0]
                            elsif line[1] == line[2]
                              line[1] += line[2]; line[2] = nil; $score += line[1]
                            end
                          when 4
                            if line[0] == line[1]
                              line[0] += line[1]; line[1], line[2], line[3] = line[2], line[3], nil; $score += line[0]
                            end
                            if line[1] == line[2]
                              line[1] += line[2]; line[2], line[3] = line[3], nil; $score += line[1]
                            end
                            if !line[2].nil? && line[2] == line[3]
                              line[2] += line[3]; line[3] = nil; $score += line[2]
                            end
                          end
                        }

process = -> args {
                    rows = []
                    if args[0]
                      rows = lines
                    else
                      4.times { |i| rows << [ lines[3][i], lines[2][i], lines[1][i], lines[0][i] ] }
                    end
                    rows.each do |row|
                      row.reverse! if args[1]
                      row.compact!
                      arrange.call row
                      complement.call row
                      row.reverse! if args[1]
                      4.times { |i| lines[3][i], lines[2][i], lines[1][i], lines[0][i] = rows[i] } unless args[0]
                    end
                  }

left  = -> { process.call [ true, false] }
down  = -> { process.call [false, false] }
right = -> { process.call [ true,  true] }
up    = -> { process.call [false,  true] }

check = -> {
              lines.each { |l| l.each { |b| congrulations.call if b == 2048 } }
              size = 0; lines.each { |line| size += line.compact.size }
              game_over.call if size == 16
            }

game = -> {
            helper.call
            start.call
            loop do
              $nums  = 0
              image = []; lines.each { |l| image << l.clone }
              refresh.call
              str = gets
              case str.rstrip.to_sym
              when :a; left.call
              when :s; down.call
              when :d; right.call
              when :w; up.call;
              else next; end
              check.call
              new_num.call if image != lines
            end
          }

game.call

gets 需要按回车,改成不用回车的吧

Ruby 其实可以写的更简单

https://gist.github.com/swordray/a04e9fda23107f26f284

class Game2048
  def initialize
    @array = 4.times.map { [ nil ] * 4 }
    2.times { fill }
  end

  def fill
    i, j = rand(4), rand(4)
    return fill if @array[i][j]
    @array[i][j] = [2, 2, 2, 2, 4].shuffle.first
  end

  def move(direction)
    @array = @array.transpose if %w[up down].include?(direction)
    @array.each(&:reverse!) if %w[right down].include?(direction)
    4.times do |i|
      a = @array[i].compact
      4.times { |x| a[x], a[x + 1] = a[x] * 2, nil if a[x].to_i == a[x + 1] }
      @array[i] = a.compact.concat([ nil ] * 4)[0..3]
    end
    @array.each(&:reverse!) if %w[right down].include?(direction)
    @array = @array.transpose if %w[up down].include?(direction)
  end

  def play
    puts @array.map { |line| "[%5s] " * 4 % line }
    move({ a: 'left', s: 'down', d: 'right', w: 'up' }[gets.strip.to_sym])
    fill && play if @array.flatten.include?(nil)
  end
end

Game2048.new.play

用 ruby 写就是简洁

需要 登录 后方可回复, 如果你还没有账号请 注册新账号