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.
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 # 답글
http://club.filltong.net/codingdojo/4170http://club.filltong.net/codingdojo/4233
http://club.filltong.net/codingdojo/4338
허진영 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번 영역의 코드가 나오는 경우가 많다고 생각합니다.