Find mines!! English Posting

Actually this quiz came from 'minesweeper' of programming challenges.

It's not difficult code, so skip explanation. And I have another idea that can reduce amount of memory usage when input data is huge size (for instance, 405060 X 405060). But I don't have enough space to write it :-). Anyway below code has only one if and one case statement. It's so cool, isn't it? :-)

class Board
  def initialize(rows, cols)
    @rows, @cols = rows, cols
    @blocks = []
    rows.times { @blocks << [] }
  end
 
  def add(block)
    @blocks[block.y][block.x] = block
    block.board = self
    block
  end
 
  def get_block(x,y)
    @blocks[y][x] if inside_board?(x,y)
  end
 
  def to_s
    @blocks.map{ |line| line.map(&:to_s).join }.join("\n")
  end
 
  def friends_of(block)
    candidates = []
    (block.x-1).upto(block.x+1) do |target_x|
      (block.y-1).upto(block.y) do |target_y|
        candidates << get_block(target_x, target_y)
      end
    end
    candidates.compact
  end
 
  #sometimes, minus index of Ruby array leads extra work. :-<
  def inside_board?(x,y)
    (x >= 0 and x < @cols and y >= 0 and y < @rows)
  end
end

class Block
  attr_accessor :board, :x, :y, :around_mine_number
 
  def self.make(type, x, y)
    case type
    when '*' then MineBlock.new(x, y)
    when '.' then NormalBlock.new(x, y)
    end
  end
 
  def initialize(x, y)
    @x, @y = x, y
    @around_mine_number = 0
  end
 
  def update_with_around_blocks
    @board.friends_of(self).each do |f|
      f.update_mine_status(self)
      self.update_mine_status(f)
    end
  end
end

class MineBlock < Block
  def to_s; '*'; end
 
  def update_mine_status(other)
    other.around_mine_number += 1
  end
end

class NormalBlock < Block
  def to_s; @around_mine_number; end
 
  def update_mine_status(other); end
end

inputs = "5 3  *..  *..  ... .*. ...".split(' ')

num_of_rows, num_of_cols = inputs.slice!(0..1).map(&:to_i)
board = Board.new(num_of_rows, num_of_cols)
num_of_rows.times do |row|
  marks = inputs.slice!(0).split('')
  num_of_cols.times do |col|
    assigned_block = board.add(Block.make(marks[col], col, row))
    assigned_block.update_with_around_blocks
  end
end

puts board

PS. Egloos is not good for code posing.

핑백

덧글

  • 2009/06/16 16:09 # 삭제 답글

    엘레강스 하지 않은걸요 ? ㅋㅋ
  • 허진영 2009/06/16 16:18 #

    이 정도면 충분하지 이녀석 ㅎㅎㅎㅎ. 심심하면 405060 X 405060 에나 도전해 보던가. ㅎㅎㅎㅎ
  • 애자일컨설팅 2009/06/29 17:08 # 답글

  • 허진영 2009/06/30 14:49 #

    안녕하시죠? J 는 정말 신기한 언어 같아요. 예전에 대안언어 축제 튜토리얼 세션때도 못 따라가면서도 참 신기한 물건이구나라고 생각했었는데 역시나네요. :-) 그나저나 링크의 코드를 J에 대한 공부 없이 이해해보려고 노력중인데 어렵네요. 꼭 석기시대 사람이 번개가 어떤 메커니즘으로 발생하고 동작하는가를 고민하는 것 같은?

    "A:어떻게 저렇게 풀 수 있지? B: J 니깐...." => "A:번개는 어떻게 나무에 불을 붙이는거지? B: 번개니깐...."

    이해하기 힘든 현상에 대해 신화나 전설, 괴담이 괜히 생겨나는 것은 아니였어요, ㅎㅎ. 어찌되었건 익숙한 언어, 안 익숙한 언어는 있어도 좋은 언어, 나쁜 언어는 없다고 생각하는 편인데 처음 코드를 봤을 때 반대의 생각이 순간 든건 어쩔 수 없더라구요. :-)
  • 애자일컨설팅 2009/07/01 01:37 #

    1년 전에 짠 코드네요. 요즘 짜라면 더 간결하게 짤 것 같습니다.

    언제 한 번 이 코드가 어떻게 돌아가는지 J 문외한도 이해할 수 있는 글을 블로그에 한 번 써보겠습니다.

    그리고 http://agile.egloos.com/5026291 이 글 참고. 저는 J에서 3번 영역의 코드가 나오는 경우가 많다고 생각합니다.
댓글 입력 영역