Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Jul 2nd, 2006, 12:23 PM   #1
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 630
Rep Power: 4 Jessehk is on a distinguished road
[Ruby] Sudoku Solver

Everyone was doing it, so I had to as well. :p

My solution so far is long, but of about 5 different methods I want to employ to solve the puzzle, I've completed 1 to full working order.

I don't know much about computer algorithms (and related math), so my solution attempts to mimic a human solving the puzzle.

So far, the code will look through the supplied puzzle and replace all empty spaces with a class instance, SudokuSolver:pot. Each spot is supplied with an Array containing all the possibilities for that spot.

The program will then look in the rows and columns of that spot looking at the known numbers, and eliminating possibilities appropriately. At the end of this checking, if there is only one possibility, the number is filled in.

This is just one method I will use to solve the puzzle, but on an easy puzzle, like the one I supplied my program with, 2 spots are already solved.

Here's what I have so far:

solver.rb
require 'pp'

class SudokuSolver
    class Spot
        def initialize
            @possible = (1..9).to_a
            @number = @possible.length
        end

        def remove_possibility(n)
            @possible.delete(n)
            @number = @possible.length
        end

        def one_possibility?
            @number == 1
        end

        def known
            @possible[0]
        end

        attr_reader :possible, :number
    end 
        
    def initialize(board)
        @board = board.split(/\n/).collect! { |row| process_row(row.scan(/./)) }
        assess_board
    end

    def assess_board
        [:rows, :cols].each do |func|
            send(func) do |part|
                part.collect! { |spot| spot or Spot.new }
            end
        end
        remove_eliminated
    end
    
    def cols
        0.upto(8) do |x|
            col = []
            0.upto(8) do |y|
                col << @board[y][x]
            end
            yield col
        end
    end 
    
    def remove_eliminated
        [:rows, :cols].each do |func|
            send(func) do |part|
                part.each do |spot|
                    if (1..9).include?(spot)
                        part.select { |x| x.class == Spot }.each do |unknown|
                            unknown.remove_possibility(spot)
                        end
                    end
                end
            end
        end
        finalize_answers
    end

    def finalize_answers
        rows do |row|
            row.collect! do |spot|
                if spot.class == Spot
                    if spot.one_possibility?
                        spot.known
                    else
                        spot
                    end
                else
                    spot
                end
            end
        end
    end
                        
    def process_row(board)
        board.collect { |x| if x == '-' then nil else x.to_i end }
    end

    def rows
        @board.each { |row| yield row }
    end

    def display
        count = 0

        puts big_divider
        rows do |row|
            disp = replace_empty_with_spaces(row)
            
            to_show = "| #{disp.join(" | ")} |"
            insert_column_seperators(to_show)
            puts to_show

            count += 1
            if count == 3
                puts big_divider
                count = 0
            else
                puts little_divider
            end
        end
    end

    def big_divider
        "+#{"=" * 35}+"
    end

    def little_divider
        "|---|---|---=---|---|---=---|---|---|"
    end

    def replace_empty_with_spaces(row)
        row.collect { |x| if x.class == Spot then ' ' else x end }
    end

    def empty_spaces
        @board.flatten.select { |x| x.nil? or x.class == Spot }.length
    end

    def to_s
        puts "--> #{empty_spaces} empty spaces"
    end

    def insert_column_seperators(input)
        [12, 24].each { |x| input[x] = '=' }
    end

    attr_reader :board
end

and the main puzzle to test it out:
main.rb
$LOAD_PATH.unshift(File.dirname(__FILE__))

require 'solver'

$puzzle = <<-EOF
-8---16--
-7-4---21
5--396---
2-4-5-13-
--89-75--
-57-3-9-2
---563--9
31---2-5-
--58---4-
EOF

board = SudokuSolver.new($puzzle)
board.display

#inspect the board
sleep(2)
pp board
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS!
Jessehk is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 9:24 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC