The Ruby Programming Language【chapter 1读书摘要】

 
#a sudoku solver in Ruby
module Sudoku
class Puzzle
ASCII=".123456789"
BIN="\000\001\002\003\004\005\006\007\010\011"

def initialize(lines)
	if(lines.respond_to?:join)
		s=lines.join
	else
		s=lines.dup
	end
	s.gsub!(/\s/,"")
	raise Invalid,"Grid is the wrong size" unless s.size==81

	if i=s.index(/[^123456789\.]/)
		raise Invalid,"Illegal character #{s[i,1]} in puzzle"
	end

	s.tr!(ASCII,BIN)
	@grid=s.unpack('c*')
	raise Invalid,"Initial puzzle has duplicates" if has_duplicates?
end

def to_s
	(0..8).collect{|r|@grid[r*9,9].pack('c9')}.join("\n").tr(BIN,ASCII)
end

def dup
	copy=super
	@grid=@grid.dup
	copy
end

def[](row,col)
	@grid[row*9+col]
end

def[]=(row,col,newvalue)
	unless (0..9).include? newvalue
		raise Invalid ,"illegal cell value"
	end
	@grid[row*9+col]=newvalue
end

BoxOfIndex=[
0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,
3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,
].freeze

def each_unknown
 0.upto 8 do |row|
  0.upto 8 do |col|
   index=row*9+col
   next if @grid[index]!=0
   box=BoxOfIndex[index]
   yield row,col,box
   end
  end
end

def has_duplicates?
	0.upto(8) {|row| return true if rowdigits(row).uniq!}  
	0.upto(8) {|col| return true if rowdigits(col).uniq!} 
	0.upto(8) {|box| return true if rowdigits(box).uniq!}
	false
end

AllDigits=[1,2,3,4,5,6,7,8,9].freeze

def possible(row,col,box)
	AllDigits-(rowdigits(row)+coldigits(col)+boxdigits(box))
end

private

def rowdigits(row)
	@grid[row*9]-[0]
end

def coldigits(col)
	result=[]
	col.step(80,9){|i|
		v=@grid[i]
		result<<v if (v!=0)
	}
	result
end

BoxToIndex=[0,3,6,27,30,33,54,57,60].freeze

def boxdigits(b)
	i=BoxToIndex[b]
	[
		@grid[i],@grid[i+1],@grid[i+2],
		@grid[i+9],@grid[i+10],@grid[i+11],
		@grid[i+18],@grid[i+19],@grid[i+20],
	]-[0]
	end
end

class Invalid<StandardError
end

class Impossible<StandardError
end

def Sudoku.scan(puzzle)
	unchanged=false
	until unchanged
		unchanged= true
		rmin,cmin,pmin=nil
		min=10 
		puzzle.each_unknown do |row,col,box|
			p=puzzle.possible(row,col,box)
			case p.size
			when 0
				raise Impossible
			when 1
				puzzle[row,col]=p[0]
				unchanged=false
			else
				if unchanged && p.size<min
					min=p.size
					rmin,cmin,pmin=row,col,p
				end
			end
		end
	end

	return rmin,cmin,pmin
end

def Sudoku.solve(puzzle)
	puzzle=puzzle.dup
	r,c,p=scan(puzzle)
	return puzzle if r==nil
	
	p.each do |guess|
		puzzle[r,c]=guess
		begin
			return solve(puzzle)
		rescue Impossible
			next
		end
	raise Impossible
	end
end	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值