2048というゲームがなかなかプレイするのにも、AIを作るのにも面白そうだったので、
自分でいじれるように書いて見ました。
require "curses" def make_board() board = Array.new(4).map!{ Array.new( 4, nil ) } end def available_pos(board) pos = [] board.each_with_index do |row, y| board.each_with_index do |cell, x| if board[y][x] == nil pos << [x, y] end end end return pos end def init_board(board) pos = available_pos(board) init_pos = pos.sample(2) init_pos.each do |p| x, y = p board[y][x] = 2 end return board end def insert_random(board) pos = available_pos(board) insert_pos = pos.sample x, y = insert_pos board[y][x] = (rand(2) + 1) * 2 return board end def show_board(board) board.each do |row| puts "+------+------+------+------+" print "|" row.each do |cell| c = cell.nil? ? " " : cell print " #{c.to_s.center(4)} |" end puts "" end puts "+------+------+------+------+" end def sum_list(row) if (row.size == 0) return [[],0] elsif(row.size < 2) return [row,0] else if not (row[0].nil? or row[1].nil?) and (row[0] == row[1]) rest_row, rest_score = sum_list(row[2..-1]) return [[row[0] * 2] + rest_row + [nil], row[0] + rest_score] else rest_row, rest_score = sum_list(row[1..-1]) return [[row[0]] + rest_row, rest_score] end end end def shift_row(row, dir) #Collect values values = row.select {|i| not i.nil? } if (dir == :left) sumed_values, score = sum_list(values) return [(sumed_values + [nil] * (4 - values.size)), score] else tmp_values, score = sum_list(values.reverse) return [([nil] * (4 - values.size) + tmp_values.reverse), score] end end def shift_board(board, dir) new_board = Array.new(4).map!{Array.new(4, nil)} score = 0 board.each_with_index do |row, y| new_board_val, s = shift_row(row, dir) new_board[y] = new_board_val score += s end return [new_board, score] end def turn_left(board) new_board = Array.new(4).map!{Array.new(4, nil)} board.each_with_index do |row, y| row.each_with_index do |cell, x| new_board[3 - x][y] = cell end end return new_board end def turn_right(board) new_board = Array.new(4).map!{Array.new(4, nil)} board.each_with_index do |row, y| row.each_with_index do |cell, x| new_board[x][3 - y] = cell end end return new_board end def update_board(board, dir) case dir when :left updated_board,score = shift_board(board, dir) when :right updated_board,score = shift_board(board, dir) when :up tmp_board,score = shift_board(turn_left(board), :left) updated_board = turn_right(tmp_board) when :down tmp_board, score = shift_board(turn_left(board), :right) updated_board = turn_right(tmp_board) end return [insert_random(updated_board),score] end class Game attr_accessor :board, :score def initialize() @board = init_board(make_board()) @score = 0 end def update(dir) @board, s = update_board(@board, dir) @score += s end def show_board_curses() Curses.setpos(0, 0) Curses.addstr("Score: #{@score}") @board.each_with_index do |row, y| Curses.setpos(y * 2 + 1, 0) Curses.addstr("+------+------+------+------+") line_str = "|" row.each_with_index do |cell| c = cell.nil? ? " " : cell line_str += " #{c.to_s.center(4)} |" end Curses.setpos(y * 2 + 2, 0) Curses.addstr(line_str) end Curses.setpos(9, 0) Curses.addstr("+------+------+------+------+") end end def main() #Initialize screen Curses.init_screen #CreateBoard game = Game.new() #Running 2048 begin while true Curses.clear game.show_board_curses() Curses.refresh case Curses.getch when ?h game.update(:left) when ?l game.update(:right) when ?k game.update(:up) when ?j game.update(:down) else break end end ensure Curses.close_screen end end if __FILE__ == $0 main() end
そうさはvim方式のカーソル移動です。