<commit_before>require 'json'

class TwoZeroFourEight

  HI_SCORES = File.join('/tmp/hi_scores_2048')

  COLOR = {0    => [48, 5, 232], 2    => [48, 5, 237],
           4    => [48, 5, 58],  8    => [48, 5, 70],
           16   => [48, 5, 40],  32   => [48, 5, 49],
           64   => [48, 5, 21],  128  => [48, 5, 56],
           256  => [48, 5, 53],  512  => [48, 5, 160],
           1024 => [48, 5, 202], 2048 => [48, 5, 226],
           :off => [48, 5, 235], :on  => [48, 5, 255]}

  ANSI = -> num, *rest { 0x1b.chr << ?[ << [*COLOR[num], *rest].join(?;) << ?m }

  class Tile
    def initialize(value = 0) @value = value end
    def to_i;  @value end
    def clear; @value = 0 end
    def spawn; @value = (rand > 0.8 ? 4 : 2) end
    def zero?; @value.zero? end
    def nonzero?; !zero? end
    def block; ANSI[@value] << ?\s << ANSI[nil, 0] end
    def to_s
      ANSI[0, 1] << ( zero? ? (?\s*4) : ('%4d' % @value) ) << ANSI[nil, 0]
    end
  end

  attr_reader :turn, :score

  def border(direction = nil)
    ( @last == direction ? ANSI[:on] : ANSI[:off] ) << (?\s*2) << ANSI[nil, 0]
  end

  def add_border(string)
    string << border(:left) << yield << border(:right) << ?\n
  end

  def to_s
    ''.tap do |string|
      string << border << (border(:up)*16) << border << ?\n

      @tiles.each.with_index do |row, index|
        add_border(string) { row.map { |t| t.block*8 }.join }
        add_border(string) { row.map { |t| (t.block*2) << t.to_s << (t.block*2) }.join }
        add_border(string) { row.map { |t| t.block*8 }.join }
      end

      string << border << (border(:down)*16) << border << ?\n
    end
  end

  def compress(tiles)
    tiles = tiles.map.with_index do |tile, index|
      if ( other = tiles[index.next] ) && (tile.to_i == other.to_i)
        other.clear
        @score += tile.to_i

        Tile.new(tile.to_i * 2)
      else
        tile
      end
    end

    tiles.reject! &:zero?

    tiles.unshift Tile.new until tiles.count == 4
    tiles
  end

  def game_over?; win? || @overfilled end
  def win?; @tiles.flatten.any? { |t| t.to_i == 2048 } end

  def execute(direction)
    unless @last == direction
      @turn += 1
      case @last = direction
      when :up    then @tiles = @tiles.transpose.map! { |row| compress(row.reject(&:zero?).reverse).reverse }.transpose
      when :down  then @tiles = @tiles.transpose.map! { |row| compress(row.reject &:zero?) }.transpose
      when :left  then @tiles.map! { |row| compress(row.reject(&:zero?).reverse).reverse }
      when :right then @tiles.map! { |row| compress(row.reject &:zero?) }
      end

      tile = @tiles.flatten.select(&:zero?).sample and tile.spawn or @overfilled = true
    end
  end

  def gets
    begin
      old_state = `stty -g`.chomp
      system 'stty raw -echo'
      char = STDIN.getc
      if char == 0x1b.chr
        char << STDIN.getc
        char << STDIN.getc<commit_msg>allow only valid moves<commit_after>require 'pry'
require 'json'

class TwoZeroFourEight

  HI_SCORES = File.join('/tmp/hi_scores_2048')

  COLOR = {0    => [48, 5, 232], 2    => [48, 5, 237],
           4    => [48, 5, 58],  8    => [48, 5, 70],
           16   => [48, 5, 40],  32   => [48, 5, 49],
           64   => [48, 5, 21],  128  => [48, 5, 56],
           256  => [48, 5, 53],  512  => [48, 5, 160],
           1024 => [48, 5, 202], 2048 => [48, 5, 226],
           :off => [48, 5, 235], :on  => [48, 5, 255]}

  ANSI = -> num, *rest { 0x1b.chr << ?[ << [*COLOR[num], *rest].join(?;) << ?m }

  class Tile
    def initialize(value = 0) @value = value end
    def to_i;  @value end
    def clear; @value = 0 end
    def spawn; @value = (rand > 0.8 ? 4 : 2) end
    def zero?; @value.zero? end
    def nonzero?; !zero? end
    def block; ANSI[@value] << ?\s << ANSI[nil, 0] end
    def to_s
      ANSI[0, 1] << ( zero? ? (?\s*4) : ('%4d' % @value) ) << ANSI[nil, 0]
    end
  end

  attr_reader :turn, :score

  def border(direction = nil)
    ( @last == direction ? ANSI[:on] : ANSI[:off] ) << (?\s*2) << ANSI[nil, 0]
  end

  def add_border(string)
    string << border(:left) << yield << border(:right) << ?\n
  end

  def to_s
    ''.tap do |string|
      string << border << (border(:up)*16) << border << ?\n

      @tiles.each.with_index do |row, index|
        add_border(string) { row.map { |t| t.block*8 }.join }
        add_border(string) { row.map { |t| (t.block*2) << t.to_s << (t.block*2) }.join }
        add_border(string) { row.map { |t| t.block*8 }.join }
      end

      string << border << (border(:down)*16) << border << ?\n
    end
  end

  def compress(tiles)
    tiles = tiles.map.with_index do |tile, index|
      if ( other = tiles[index.next] ) && (tile.to_i == other.to_i)
        other.clear
        @score += tile.to_i

        Tile.new(tile.to_i * 2)
      else
        tile
      end
    end

    tiles.reject! &:zero?
    tiles.unshift Tile.new until tiles.count == 4
    tiles
  end

  def game_over?; win? || @overfilled end
  def win?; @tiles.flatten.any? { |t| t.to_i == 2048 } end

  def execute(direction)
    @turn += 1

    state = @tiles.map { |row| row.map &:to_i }

    case @last = direction
    when :up    then @tiles = @tiles.transpose.map { |row| compress(row.reject(&:zero?).reverse).reverse }.transpose
    when :down  then @tiles = @tiles.transpose.map { |row| compress(row.reject &:zero?) }.transpose
    when :left  then @tiles.map! { |row| compress(row.reject(&:zero?).reverse).reverse }
    when :right then @tiles.map! { |row| compress(row.reject &:zero?) }
    end

    if state.flatten.inject(&:+).zero? || state != @tiles.map { |row| row.map &:to_i }
      if tile = @tiles.flatten.select(&:zero?).sample
        tile.spawn
      else
        @overfilled = true
      end
    else
      @overfilled = true unless @tiles.flatten.any?(&:zero?)
    end
  end

  def gets
    begin
      old_state = `stty -g`.chomp
      system 'stty raw -echo'
      char = STDIN.getc
      if char == 0x1b.chr
        char << STDIN.getc
        char << STDIN.getc
{'fraction_non_alphanumeric': 0.1816971713810316, 'fraction_numerical': 0.04692179700499168, 'mean_word_length': 2.231720430107527, 'pattern_counts': {'":': 0, '<': 103, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '25199', 'n_tokens_mistral': 2529, 'n_tokens_neox': 2283, 'n_words': 607}