Op 6 feb 2014, om 16:46 heeft Simon Slavin het volgende geschreven:


On 6 Feb 2014, at 7:15am, big stone <stonebi...@gmail.com> wrote:

If we wish to have SQLite + Python combination to become "reference choice"
in education, I would think that priority list should be :

Just to remind you that you're posting to the SQLite list. Most of those are things that would be done by the Python maintainers, not the SQLite maintainers.

Simon.

I find the subject of Sudoku solving still interesting and have an other quey here. This derives from Bigstone's 1st solution, defining a neighbourhood relation between sudoku cells. New is that I tried bitmaps instead of a characterstring to represent the sudoku. Below is the result. Conclusions
- bitmaps are hard to debug as they can not be easily viewed
- but the solution is much fater (four times)
- the recursion tends to go breath first by default which is not optimal for speed. - using a seperate (temporary) table for a non-trivial sub-queriy, instead of a CTE. is worth when used at several places.

create temporary table ind (
        ind integer primary key, -- sudoku cell (1..81)
        word0, -- bitmap of ind, bits 1..54
        word1, -- bitmap of ind, bits 55..81
        neighbours0, neighbours1) -- bitmap of neighbour cells
;
/*
initializing the neighbour bitmaps was the
most tricky part: one must probably turn the
soduku upside down and view it through a mirror
to see the x,y coordinates as used here.
*/
insert into ind
select  ind,
        case when iword=0 then 1<<ibit else 0 end AS word0,
        case when iword=1 then 1<<ibit else 0 end AS word1,
        --neighbours0
            --horizontal
            CASE WHEN iword=0
            THEN (512-1)<<(y*9)
            ELSE 0
            END |
            --vertical
            ((1+512*(1+512*(1+512*(1+512*(1+512)))))<<x) |
            --box
            CASE WHEN iword=0
            THEN ((8-1)*(1+512*(1+512)))<<(y/3*3*9+x/3*3)
            ELSE 0
            END
            AS neighbours0,
        --neighbours1
            --horizontal
            CASE WHEN iword=1
            THEN (512-1)<<((y%6)*9)
            ELSE 0
            END |
            --vertical
            ((1 + 512 * (1 + 512)) << x) |
            --box
            CASE WHEN iword=1
            THEN ((8-1)*(1+512*(1+512)))<<((y%6)/3*3*9+x/3*3)
            ELSE 0
            END
            AS neighbours1
from    (
with xy AS (SELECT 0 AS xy UNION ALL SELECT xy+1 FROM xy WHERE xy < 80)
    select  xy+1 AS ind,
            xy%9 AS x,
            xy/9 AS y,
            xy/54 AS iword,
            xy%54 AS ibit
    from    xy
        )
;
.mode line

with z AS (
    SELECT 0 AS z -- zero is used for fixed input
    UNION ALL
    SELECT z+1 FROM z WHERE z < 9
        )
,
input as (
    select  sud,
            cast (substr (sud, 1, 1) as int) as z,
            1 as ind,
            0 as w0, 0 as w1, -- bitmap covering all digits
            0 as w10, 0 as w11, -- bitmap of 1's
            0 as w20, 0 as w21, -- bitmap of 2's
            0 as w30, 0 as w31, -- bitmap of 3's
            0 as w40, 0 as w41, -- bitmap of 4's
            0 as w50, 0 as w51, -- bitmap of 5's
            0 as w60, 0 as w61, -- bitmap of 6's
            0 as w70, 0 as w71, -- bitmap of 7's
            0 as w80, 0 as w81, -- bitmap of 8's
            0 as w90, 0 as w91 -- bitmap of 9's
    from    (
        select
--'53 .. 7 .... 6 ..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79' '1 .... 7.9 .. 3..2...8..96..5....53..9...1..8...26....4...3......1..4......7..7...3..'
                    as sud
            ) sud
    union all
    select  sud,
            cast (substr (sud, ind.ind+1, 1) as int),
            ind.ind+1,
            w0 | case when z>0 then word0 else 0 end,
            w1 | case when z>0 then word1 else 0 end,
            w10 | case when z=1 then word0 else 0 end,
            w11 | case when z=1 then word1 else 0 end,
            w20 | case when z=2 then word0 else 0 end,
            w21 | case when z=2 then word1 else 0 end,
            w30 | case when z=3 then word0 else 0 end,
            w31 | case when z=3 then word1 else 0 end,
            w40 | case when z=4 then word0 else 0 end,
            w41 | case when z=4 then word1 else 0 end,
            w50 | case when z=5 then word0 else 0 end,
            w51 | case when z=5 then word1 else 0 end,
            w60 | case when z=6 then word0 else 0 end,
            w61 | case when z=6 then word1 else 0 end,
            w70 | case when z=7 then word0 else 0 end,
            w71 | case when z=7 then word1 else 0 end,
            w80 | case when z=8 then word0 else 0 end,
            w81 | case when z=8 then word1 else 0 end,
            w90 | case when z=9 then word0 else 0 end,
            w91 | case when z=9 then word1 else 0 end
    from    input
    join    ind
    on      ind.ind = input.ind
        )
,
sudoku as (
    select  1 as ind,
            w0, w1,
            w10, w11,
            w20, w21,
            w30, w31,
            w40, w41,
            w50, w51,
            w60, w61,
            w70, w71,
            w80, w81,
            w90, w91
    from    input
    where   ind>81
    union all
    select  sudoku.ind+1,
            w0 | word0,
            w1 | word1,
            w10 | case when z=1 then word0 else 0 end,
            w11 | case when z=1 then word1 else 0 end,
            w20 | case when z=2 then word0 else 0 end,
            w21 | case when z=2 then word1 else 0 end,
            w30 | case when z=3 then word0 else 0 end,
            w31 | case when z=3 then word1 else 0 end,
            w40 | case when z=4 then word0 else 0 end,
            w41 | case when z=4 then word1 else 0 end,
            w50 | case when z=5 then word0 else 0 end,
            w51 | case when z=5 then word1 else 0 end,
            w60 | case when z=6 then word0 else 0 end,
            w61 | case when z=6 then word1 else 0 end,
            w70 | case when z=7 then word0 else 0 end,
            w71 | case when z=7 then word1 else 0 end,
            w80 | case when z=8 then word0 else 0 end,
            w81 | case when z=8 then word1 else 0 end,
            w90 | case when z=9 then word0 else 0 end,
            w91 | case when z=9 then word1 else 0 end
    from    sudoku
    join    ind on ind.ind = sudoku.ind
    join    z on
            case when w0&word0 OR w1&word1
            then z=0
            else
                case z
                when 1 then not neighbours0&w10 and not neighbours1&w11
                when 2 then not neighbours0&w20 and not neighbours1&w21
                when 3 then not neighbours0&w30 and not neighbours1&w31
                when 4 then not neighbours0&w40 and not neighbours1&w41
                when 5 then not neighbours0&w50 and not neighbours1&w51
                when 6 then not neighbours0&w60 and not neighbours1&w61
                when 7 then not neighbours0&w70 and not neighbours1&w71
                when 8 then not neighbours0&w80 and not neighbours1&w81
                when 9 then not neighbours0&w90 and not neighbours1&w91
                end
            end
    order by ind desc --go depth first
        )
,
output as (
    select  1 as ind,
            w10, w11,
            w20, w21,
            w30, w31,
            w40, w41,
            w50, w51,
            w60, w61,
            w70, w71,
            w80, w81,
            w90, w91,
            '' as sudoku
    from    sudoku
    where   ind>81
    union all
    select  output.ind + 1,
            w10, w11,
            w20, w21,
            w30, w31,
            w40, w41,
            w50, w51,
            w60, w61,
            w70, w71,
            w80, w81,
            w90, w91,
            sudoku || replace (cast (
                case 1
                when w10&word0 OR w11&word1 then 1
                when w20&word0 OR w21&word1 then 2
                when w30&word0 OR w31&word1 then 3
                when w40&word0 OR w41&word1 then 4
                when w50&word0 OR w51&word1 then 5
                when w60&word0 OR w61&word1 then 6
                when w70&word0 OR w71&word1 then 7
                when w80&word0 OR w81&word1 then 8
                when w90&word0 OR w91&word1 then 9
                else 0
                end
                as char), '0', '.')
    from    output
    join    ind on ind.ind = output.ind
        )
select  substr (sudoku, 1*9-8, 9) as line1,
        substr (sudoku, 2*9-8, 9) as line2,
        substr (sudoku, 3*9-8, 9) as line3,
        substr (sudoku, 4*9-8, 9) as line4,
        substr (sudoku, 5*9-8, 9) as line5,
        substr (sudoku, 6*9-8, 9) as line6,
        substr (sudoku, 7*9-8, 9) as line7,
        substr (sudoku, 8*9-8, 9) as line8,
        substr (sudoku, 9*9-8, 9) as line9
from    output
where   ind>81
;


_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to