【ruby】递归解决数独问题

shudu="
0 0 9 | 0 0 0 | 8 0 5
0 0 0 | 1 4 5 | 0 0 0
7 0 5 | 0 9 0 | 0 0 3
---------------------
0 7 0 | 0 3 0 | 0 4 0
0 0 0 | 4 0 6 | 0 0 0
0 3 0 | 0 2 0 | 0 6 0
---------------------
8 0 0 | 0 0 0 | 1 0 7
0 0 0 | 6 8 1 | 0 0 0
5 0 3 | 0 0 0 | 6 0 0
"
#转换关系
#  block = (line-1)/3*3+1+(row-1)/3
#  index = (line-1)%3*3+1+(row-1)%3
#  line = (block-1)/3*3+1+(index-1)/3
a = []
def init(a, shudu)
    #init arrary a[][]=[1...9]
    for index in 1..9
        a[index] = []
        for subindex in 1..9
            a[index][subindex]=[1,2,3,4,5,6,7,8,9]
        end
    end
    #fill the number into arrary
    inputlines=shudu.split("\n")
    cur = 1
    inputlines.each do |line|
        regex=/(\d) (\d) (\d) \| (\d) (\d) (\d) \| (\d) (\d) (\d)/
        arr = line.scan(regex)
        if(arr.size>0)
            arr[0].each_with_index{|m,i| 
                if(m.to_i!=0)
                    block = (cur-1)/3*3+1+i/3
                    index = (cur-1)%3*3+1+i%3
                    a[block][index]=m.to_i
                end
            }
        end
        if line=~ regex then cur = cur +1 end
    end
    #clear same number in same block/row/line
    for num in 1..9
        kitout(a,num)
    end
end

def kitout(a, num)
    for block in 1..9
        index = block_has_num(a, num, block)
        if(index > 0)
            delete_num_in_block(a, num, block)
            delete_num_in_same_line(a, num, block, index)
            delete_num_in_same_row(a, num, block, index)
        end
    end
end

def block_has_num(a, num, block)
    for index in 1..9
        return index if a[block][index] == num
    end
    return 0
end

def delete_num_in_block(a, num, block)
    for index in 1..9
        a[block][index].delete(num) if a[block][index].is_a?(Array)
    end
end

def delete_num_in_same_line(a, num, block, index)
    cur = (block-1)/3
    for i in cur*3+1..(cur+1)*3
        subcur=(index-1)/3
        for j in subcur*3+1..(subcur+1)*3
            a[i][j].delete(num) if a[i][j].is_a?(Array)
        end
    end
end

def delete_num_in_same_row(a, num, block, index)
    for i in 0..2
        cur = (block+2)%3 +1+ 3*i
        for j in 0..2
            subcur=index%3+3*j
            a[cur][subcur].delete(num) if a[cur][subcur].is_a?(Array)
        end
    end
end

def loop_find_and_delete(a)
    findcount = 0
    for num in 1..9
        findcount = findcount + findout(a, num)
    end
    return findcount
end
#对具体number进行遍历block确认
def findout(a, num)
    findCount = 0
    for block in 1..9
        index = find_block_certain_num(a, block, num)
        if(index > 0)
            a[block][index] = num
            delete_num_in_block(a, num, block)
            delete_num_in_same_line(a, num, block, index)
            delete_num_in_same_row(a, num, block, index)
            findCount = findCount + 1
        end
    end
    return findCount
end
#找到区块中确定的值
def find_block_certain_num(a, block, num)
    count = 0
    tempIndex = 0
    for index in 1..9
        return 0 if a[block][index] == num
        return index if(a[block][index]==[num])
        if (a[block][index].is_a?(Array)) and (a[block][index].include?(num))
            count = count +1
            tempIndex = index
        end
    end
    if(count == 1)
        return tempIndex
    end
    return 0
end
#填充一个数字时,相关行、列,小块做处理
def fill_a_num(a, block, index, num)
    a[block][index] = num
    delete_num_in_block(a, num, block)
    delete_num_in_same_line(a, num, block, index)
    delete_num_in_same_row(a, num, block, index)
end
#判断是否是正确结果
def check_result(a)
    failFlag = false
    numCount = 0
    for block in 1..9
        for index in 1..9
            if a[block][index].size == 0  # this kind []
                failFlag = true 
                break
            end
            numCount = numCount + 1 if a[block][index].is_a?(Integer) # calculate the total certain number
        end
    end
    return "back" if(failFlag)
    return "pass" if(numCount==81)
    return "next"
end

#从两个数中挑选一个进行尝试
def decide_one_num_between_two(a)
    check = check_result(a)
    if(check=="back")
        #puts "  ==fail=="
        return false
    end
    if(check=="pass")
        #puts "  ==pass=="
        print_result(a)
        return true
    end
    #puts "  ==next=="
    for block in 1..9
        for index in 1..9
            if a[block][index].size == 2
                numberList = a[block][index]
                for times in 0..1
                    # deepcopy array a
                    tempArray = a + []
                    for x in 1..9
                        tempArray[x] = a[x]+[]
                        for y in 1..9
                            tempArray[x][y] = a[x][y]+[] if a[x][y].is_a?(Array)
                            tempArray[x][y] = a[x][y] if a[x][y].is_a?(Integer)
                        end
                    end
                    #print "block:#{block} index:#{index} number:#{numberList[times]}"
                    #choose one number 
                    fill_a_num(tempArray, block, index, numberList[times])
                    while(loop_find_and_delete(tempArray)>0) do {} end
                    return if (decide_one_num_between_two(tempArray))
                end
                return
            end
        end
    end
end

def print_array(a)
    for index in 1..9
        puts "--#{index}"
        for subindex in 1..9
            puts "--|--#{subindex}:#{a[index][subindex]}"
        end
    end
end

def print_result(a)
    for i in 1..9
        for j in 1..9
            block = (i-1)/3*3+1+(j-1)/3
            index = (i-1)%3*3+1+(j-1)%3
            print "%d " % a[block][index] if a[block][index].is_a?(Integer)
            print "0 " if a[block][index].is_a?(Array)
            print "| " if j%3==0 and j < 8
        end
        print "\n"
        print "---------------------\n" if i%3==0 and i < 8
    end
    puts "*"*22
end


init(a, shudu)
#print_result(a)
while(loop_find_and_delete(a)>0)do{}end
#print_array(a)
decide_one_num_between_two(a)

测试结果
在这里插入图片描述

可运行文件下载链接:点我下载

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值