อัดซูโดกุ


35

งานของคุณคือการเขียนโปรแกรม (หรือสองโปรแกรมแยกต่างหาก) ในภาษาใด ๆ ที่:

  1. สามารถนำกระดาน Sudoku ที่เสร็จสมบูรณ์เป็นอินพุต (ในรูปแบบโลจิคัลใด ๆ ) และบีบอัดลงในชุดอักขระ
  2. สามารถใช้การบีบอัดสตริงเป็น input และขยายมันจะได้รับที่แน่นอนเดียวกันคณะกรรมการซูโดกุเสร็จ (การส่งออกในรูปแบบใด ๆ ของตรรกะ 9 แถว)

หมายเหตุ:ใช้กฎของ Sudoku เพื่อประโยชน์ของคุณ นั่นคือแนวคิดเบื้องหลังการท้าทายนี้
กฎของ Sudoku เกี่ยวกับ Wikipedia

กฎระเบียบ

  • อนุญาตเฉพาะอักขระ ASCII ที่พิมพ์ได้ (32 - 126) ในเอาต์พุตที่บีบอัด (เช่นไม่มีอักขระหลายไบต์ )
  • คุณสามารถสันนิษฐานได้ว่าอินพุตเป็นบอร์ด Sudoku 3x3 ที่ถูกต้อง (กฎปกติไม่มีการเปลี่ยนแปลง)
  • ฉันจะไม่กำหนดเวลา แต่อย่าสร้างอัลกอริธึมที่ดุร้าย หรือผู้ส่งควรทดสอบการส่งของตนก่อนโพสต์ (ขอบคุณ Jan Dvorak)

หากคุณมีคำถามหรือข้อสงสัยใด ๆ คุณสามารถขอคำชี้แจงหรือให้คำแนะนำในความคิดเห็นได้

เงื่อนไขการชนะ

คะแนน = ผลรวมของจำนวนตัวละครจากทั้งสิบกรณีทดสอบ

คะแนนต่ำสุดชนะ

กรณีทดสอบ

คุณสามารถใช้สิ่งเหล่านี้เพื่อทดสอบว่าโปรแกรมของคุณทำงานได้ดีเพียงใด

9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1

7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2

1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2

8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5

6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5

1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8

1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8

5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4

2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9

8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6

มอบเครดิตให้แก่http://www.opensky.ca/~jdhildeb/software/sudokugen/สำหรับบางส่วนของสิ่งเหล่านี้

หากคุณพบปัญหาใด ๆ กับกรณีทดสอบโปรดบอกฉัน


5
นอกจากนี้ควรมีการ จำกัด เวลาเพื่อป้องกันการแก้ปัญหาที่ระบุการกำหนดค่าของบอร์ดทุกอันและตรวจสอบว่าเป็นหนึ่งใน6670903752021072936960 ที่เป็นไปได้ของกริดซูโดกุที่แก้ไขได้หรือไม่
feersum

3
คุณอาจต้องการเปลี่ยนการให้คะแนน เพราะมันไม่มีอะไรหยุดยั้งฉันจากการ hardcoding กรณีทดสอบไปเป็นรหัส 1-char และเพียงแค่ใช้รหัส 81-char สำหรับทุกอย่างอื่น
TwiNight

4
@TwiNight นอกจากจะเป็นช่องโหว่มาตรฐานแล้วคุณหมายถึงอะไร?
John Dvorak

4
แม้จะมีคำตอบด้านล่างของฉัน แต่ฉันคิดว่าวิธีที่ดีที่สุดในการแก้ปัญหานี้ก็คือการเขียนตัวแก้ซูโดกุจากนั้นลบจำนวนสูงสุดของตัวเลขออกจากตารางเพื่อให้ปริศนายังคงละลายได้ (นั่นควรเป็นทั้งหมด จากนั้นทำการบีบอัด ตัวขยายการบีบอัดประกอบด้วยตัวแก้
abligh

4
@kasperd มันยากที่จะวาดเส้น (ดูfudgeรูทีนย่อยในคำตอบที่สองของฉันที่ได้รับ 12 คะแนน) การทดสอบที่ยุติธรรมจะต้องใช้ว่า (a) วิธีทดสอบใช้งานได้ (b) คะแนนจาก Sudoku ที่สร้างขึ้น 1,000 รายการและหารคำตอบด้วย 100 ฉันเชื่อว่าวิธีที่ดีที่สุดที่สามารถทำได้กับข้อมูลแบบสุ่มคือประมาณ 110 จาก 10 x log-base-95 (6670903752021072936960)
abligh

คำตอบ:


26

Haskell, 107 คะแนน

import Control.Monad
import Data.List

type Elem = Char
type Board = [[Elem]]
type Constraints = ([Elem],[Elem],[Elem])

digits :: [Elem]
digits = "123456789"
noCons :: Constraints
noCons = ([],[],[])
disjointCons :: Constraints
disjointCons = ("123","456","789") -- constraints from a single block - up to isomorphism
triples :: [a] -> [[a]]
triples [a,b,c,d,e,f,g,h,i] = [[a,b,c],[d,e,f],[g,h,i]]
(+++) :: Constraints -> Constraints -> Constraints
(a,b,c) +++ (d,e,f) = (a++d,b++e,c++f)

maxB = 12096 
-- length $ assignments noCons disjointCons
maxC = 216 -- worst case: rows can be assigned independently
maxD = maxB
maxE = 448
-- foldl1' max [length $ assignments disjointCons colCons
--             | (_, colCons) <- map constraints $ assignments ([],[1],[1]) ([],[1],[1]),
--               let ([a,d,g],[b,e,h],[c,f,i]) = colCons,
--               a < d, d < g, b < e, e < h, c < f, f < i]
maxF = 2 ^ 3 -- for each row the relevant column constraints can be in the same column (no assignment), 
             -- or in two or three columns (two assignments)
maxG = maxC
maxH = maxF

-- constraints -> list of block solutions
assignments :: Constraints -> Constraints -> [[Elem]]
assignments (r1,r2,r3) (c1,c2,c3) = do
    a <- digits  \\ (r1 ++ c1); let digits1 = digits  \\ [a]
    b <- digits1 \\ (r1 ++ c2); let digits2 = digits1 \\ [b]
    c <- digits2 \\ (r1 ++ c3); let digits3 = digits2 \\ [c]
    d <- digits3 \\ (r2 ++ c1); let digits4 = digits3 \\ [d]
    e <- digits4 \\ (r2 ++ c2); let digits5 = digits4 \\ [e]
    f <- digits5 \\ (r2 ++ c3); let digits6 = digits5 \\ [f]
    g <- digits6 \\ (r3 ++ c1); let digits7 = digits6 \\ [g]
    h <- digits7 \\ (r3 ++ c2); let digits8 = digits7 \\ [h]
    i <- digits8 \\ (r3 ++ c3)
    return [a,b,c,d,e,f,g,h,i]

-- block solution -> tuple of constraints
constraints :: [Elem] -> (Constraints, Constraints)
constraints [a,b,c,d,e,f,g,h,i] = (([a,b,c],[d,e,f],[g,h,i]),([a,d,g],[b,e,h],[c,f,i]))

------------------------------------------------------------------------------------------

-- solution -> Integer
solution2ix :: Board -> Integer
solution2ix [a,b,c,d,e,f,g,h,i] =
    let (ar, ac) = constraints a
        (br, bc) = constraints b
        (_ , cc) = constraints c
        (dr, dc) = constraints d
        (er, ec) = constraints e
        (_ , fc) = constraints f
        (gr, _ ) = constraints g
        (hr, _ ) = constraints h
        (_ , _ ) = constraints i

        Just ixA = findIndex (a ==) $ assignments noCons      noCons
        Just ixB = findIndex (b ==) $ assignments ar          noCons
        Just ixC = findIndex (c ==) $ assignments (ar +++ br) noCons
        Just ixD = findIndex (d ==) $ assignments noCons      ac
        Just ixE = findIndex (e ==) $ assignments dr          bc
        Just ixF = findIndex (f ==) $ assignments (dr +++ er) cc
        Just ixG = findIndex (g ==) $ assignments noCons      (ac +++ dc)
        Just ixH = findIndex (h ==) $ assignments gr          (bc +++ ec)
        Just ixI = findIndex (i ==) $ assignments (gr +++ hr) (cc +++ fc)

    in foldr (\(i,m) acc -> fromIntegral i + m * acc) (fromIntegral ixA)
     $ zip [ixH, ixG, ixF, ixE, ixD, ixC, ixB] [maxH, maxG, maxF, maxE, maxD, maxC, maxB]

--    list of rows 
-- -> list of threes of triples
-- -> three triples of threes of triples 
-- -> three threes of triples of triples
-- -> nine triples of triples
-- -> nine blocks
toBoard :: [[Elem]] -> Board
toBoard = map concat . concat . map transpose . triples . map triples

toBase95 :: Integer -> String
toBase95 0 = ""
toBase95 ix = toEnum (32 + fromInteger (ix `mod` 95)) : toBase95 (ix `div` 95)

------------------------------------------------------------------------------------------

ix2solution :: Integer -> Board
ix2solution ix =
    let (ixH', ixH) = ix   `divMod` maxH
        (ixG', ixG) = ixH' `divMod` maxG
        (ixF', ixF) = ixG' `divMod` maxF
        (ixE', ixE) = ixF' `divMod` maxE
        (ixD', ixD) = ixE' `divMod` maxD
        (ixC', ixC) = ixD' `divMod` maxC
        (ixA , ixB) = ixC' `divMod` maxB

        a = assignments noCons      noCons      !! fromIntegral ixA
        (ra, ca) = constraints a
        b = assignments ra          noCons      !! fromIntegral ixB
        (rb, cb) = constraints b
        c = assignments (ra +++ rb) noCons      !! fromIntegral ixC
        (_ , cc) = constraints c
        d = assignments noCons      ca          !! fromIntegral ixD
        (rd, cd) = constraints d
        e = assignments rd          cb          !! fromIntegral ixE
        (re, ce) = constraints e
        f = assignments (rd +++ re) cc          !! fromIntegral ixF
        (_ , cf) = constraints f
        g = assignments noCons      (ca +++ cd) !! fromIntegral ixG
        (rg, _ ) = constraints g
        h = assignments rg          (cb +++ ce) !! fromIntegral ixH
        (rh, _ ) = constraints h
        [i] = assignments (rg +++ rh) (cc +++ cf)
    in  [a,b,c,d,e,f,g,h,i]

--    nine blocks
-- -> nine triples of triples
-- -> three threes of triples of triples
-- -> three triples of threes of triples
-- -> list of threes of triples
-- -> list of rows
fromBoard :: Board -> [[Elem]]
fromBoard = map concat . concat . map transpose . triples . map triples

fromBase95 :: String -> Integer
fromBase95 ""     = 0
fromBase95 (x:xs) = (toInteger $ fromEnum x) - 32 + 95 * fromBase95 xs

------------------------------------------------------------------------------------------

main = do line <- getLine
          if length line <= 12
             then putStrLn $ unlines $ map (intersperse ' ') $ fromBoard $ ix2solution $ fromBase95 line
             else do nextLines <- replicateM 8 getLine
                     putStrLn $ toBase95 $ solution2ix $ toBoard $ map (map head.words) $ line:nextLines

ผลการทดสอบกรณี:

q`3T/v50 =3,
^0NK(F4(V6T(
d KTTB{pJc[
B]^v[omnBF-*
WZslDPbcOm7'
)
ukVl2x/[+6F
qzw>GjmPxzo%
KE:*GH@H>(m!
SeM=kA`'3(X*

รหัสไม่สวย แต่ใช้งานได้ พื้นฐานของอัลกอริทึมคือในขณะที่การแจงนับโซลูชันทั้งหมดจะใช้เวลานานเกินไปการแจกแจงโซลูชันทั้งหมดภายในบล็อกเดียวนั้นค่อนข้างรวดเร็ว - อันที่จริงแล้วมันเร็วกว่าการแปลงที่ตามมาเป็น base95 ทุกอย่างทำงานภายในไม่กี่วินาทีในล่ามในเครื่องต่ำสุดของฉัน โปรแกรมที่คอมไพล์แล้วจะเสร็จในทันที

solution2ixฟังก์ชั่นการยกอย่างหนักนั้นทำโดยฟังก์ชั่นซึ่งในแต่ละบล็อค 3x3 จะสร้างการเรียงสับเปลี่ยนที่เป็นไปได้ทั้งหมดภายใต้ข้อ จำกัด จากทางซ้ายและจากด้านบนจนกระทั่งพบการเข้ารหัสในการเข้ารหัส จากนั้นจะรวมดัชนีโดยใช้น้ำหนักที่คำนวณล่วงหน้าแล้วและรูปแบบของ Horner

ในอีกทางหนึ่งix2solutionฟังก์ชันจะแยกดัชนีออกเป็นเก้าค่า จากนั้นสำหรับแต่ละบล็อกมันจะจัดทำดัชนีรายการของการเรียงสับเปลี่ยนที่เป็นไปได้ด้วยค่าที่เกี่ยวข้องจากนั้นแยกข้อ จำกัด สำหรับบล็อกถัดไป

assignmentsเป็นการสอบถามซ้ำแบบเรียบง่าย แต่ไม่น่าเกลียดโดยใช้รายการ monad มันสร้างรายการของการเรียงสับเปลี่ยนที่กำหนดข้อ จำกัด

พลังที่แท้จริงมาจากขอบเขตที่ จำกัด ในความยาวของรายการการเปลี่ยนแปลง:

  • มุมซ้ายบนไม่มีข้อ จำกัด 9!จำนวนพีชคณิตเป็นเพียง ค่านี้ไม่เคยถูกใช้ยกเว้นเพื่อค้นหาขอบเขตบนของความยาวเอาต์พุต
  • บล็อกที่อยู่ถัดจากมันจะมีข้อ จำกัด เพียงชุดเดียว - จากด้านบนซ้าย ขอบเขตบนที่ไร้เดียงสา6*5*4*6!นั้นเลวร้ายยิ่งกว่าการนับจริงที่พบโดยการแจงนับเจ็ดเท่า:12096
  • มุมขวาบนถูก จำกัด สองครั้งจากซ้าย แต่ละแถวสามารถมีการเปลี่ยนลำดับได้หกครั้งเท่านั้นและในกรณีที่แย่ที่สุด (จริง ๆ แล้วในทุกกรณีที่ถูกต้อง) การมอบหมายนั้นเป็นอิสระ ในทำนองเดียวกันสำหรับมุมซ้ายล่าง
  • ชิ้นกลางเป็นสิ่งที่ยากที่สุดในการประเมิน กำลังดุร้ายชนะอีกครั้ง - นับการเปลี่ยนแปลงของแต่ละเซตของข้อ จำกัด ที่เป็นไปได้ของมอร์ฟิซึ่มส์ ใช้เวลาสักครู่ แต่จำเป็นเพียงครั้งเดียวเท่านั้น
  • ชิ้นส่วนกึ่งกลางด้านขวามีข้อ จำกัด สองด้านจากด้านซ้ายซึ่งบังคับให้แต่ละแถวขึ้นกับการเปลี่ยนแปลง แต่ยังมีข้อ จำกัด เดียวจากด้านบนซึ่งทำให้มั่นใจได้เพียงสองวิธีต่อแถวเป็นไปได้จริง ในทำนองเดียวกันสำหรับชิ้นส่วนกลางด้านล่าง
  • มุมขวาล่างถูกกำหนดโดยเพื่อนบ้านอย่างเต็มที่ การเปลี่ยนแปลงเพียงอย่างเดียวไม่เคยตรวจสอบจริงเมื่อคำนวณดัชนี การบังคับให้ประเมินผลนั้นง่ายมันไม่จำเป็นเลย

ผลิตภัณฑ์ของขีด จำกัด เหล่านี้คือ71025136897117189570560~ = 95^11.5544ซึ่งหมายความว่าไม่มีรหัสใดยาวกว่า 12 ตัวอักษรและเกือบครึ่งหนึ่งควรเป็น 11 ตัวหรือน้อยกว่า ฉันตัดสินใจที่จะไม่แยกแยะความแตกต่างระหว่างสายที่สั้นกว่าและสายที่มีเบาะขวามีช่องว่าง ช่องว่างที่อื่นมีความสำคัญ

ขีด จำกัด ทางทฤษฎีของประสิทธิภาพการเข้ารหัสสำหรับรหัสที่ไม่มีคำนำหน้า - ฐานลอการิทึม 95 ของ6670903752021072936960- คือ11.035หมายความว่าแม้อัลกอริทึมที่ดีที่สุดไม่สามารถหลีกเลี่ยงการสร้างเอาต์พุตความยาว -12 ถึงแม้ว่ามันจะผลิตได้เพียง 3.5% ของทุกกรณี การอนุญาตให้ความยาวมีความสำคัญ (หรือเทียบเท่าการเพิ่มช่องว่างต่อท้าย) จะเพิ่มรหัสสองสาม (1% ของจำนวนเงินทั้งหมด) แต่ไม่เพียงพอที่จะกำจัดความต้องการรหัสความยาว -12


คุณคิดว่าการทำงานเป็นกลุ่มมีประสิทธิภาพมากกว่าแถวหรือไม่?
xnor

@xnor ง่ายขึ้นแน่นอนในการตรวจสอบข้อ จำกัด ด้วยวิธีนี้
John Dvorak

... และเพื่อ จำกัด ขอบเขตการเปลี่ยนแปลงซึ่งสำคัญยิ่งกว่าที่นี่
John Dvorak

@xnor ยิ่งบล็อกยิ่งใหญ่เท่าไหร่ การจัดการกับสามอันดับแรกในหนึ่งครั้งจากนั้นอีกสามช่วงต่อไปในคราวเดียวและในที่สุดอันสุดท้ายนั้นอาจเป็นขั้นตอนต่อไปในการปรับปรุงคะแนน
ปีเตอร์เทย์เลอร์

@PeterTaylor 9! ^ 3 = 4.8e16 มันสูงเกินไปเล็กน้อย แต่การจัดการแถวแรกเป็นตัวเลขแล้วแจกแจงอีกสองสามถัดไปและสุดท้ายอาจเป็นไปได้ ฉันอาจลองดู
John Dvorak

10

Python 130 คะแนน

j1:4}*KYm6?D
h^('gni9X`g'#
$2{]8=6^l=fF!
BS ;1;J:z"^a"
\/)gT)sixb"A+
WI?TFvj%:&3-\$
*iecz`L2|a`X0
eLbt<tf|mFN'&
;KH_TzK$erFa!
7T=1*6$]*"s"!

อัลกอริทึมทำงานโดยการเข้ารหัสแต่ละตำแหน่งในกระดานทีละหนึ่งเป็นจำนวนเต็มขนาดใหญ่ สำหรับแต่ละตำแหน่งจะคำนวณค่าที่เป็นไปได้ที่ได้รับมอบหมายทั้งหมดที่เข้ารหัสไว้ ดังนั้นหาก [1,3,7,9] เป็นค่าที่เป็นไปได้สำหรับตำแหน่งที่กำหนดจะใช้เวลา 2 บิตในการเข้ารหัสทางเลือก

สิ่งที่ดีเกี่ยวกับรูปแบบนี้คือถ้าตำแหน่งมีเพียงตัวเลือกเดียวที่เหลืออยู่ก็ไม่ต้องใช้พื้นที่ในการเข้ารหัส

เมื่อเรามีจำนวนเต็มใหญ่แล้วเราก็เขียนมันออกมาในฐาน 95

อาจมีการเรียงลำดับการเข้ารหัสที่ดีกว่าพจนานุกรมเล็ก แต่ฉันไม่ได้คิดมากเกี่ยวกับมัน

Encoder:

import sys

sets = [range(i*9, i*9+9) for i in xrange(9)]
sets += [range(i, 81, 9) for i in xrange(9)]
sets += [[i/3*27+i%3*3+j/3*9+j%3 for j in xrange(9)] for i in xrange(9)]

M = []
for line in sys.stdin.readlines():
    M += [int(x) for x in line.split()]

A = 0
m = 1
for i in xrange(81):
    allowed = set(xrange(1,10))
    for s in sets:
        if i in s:
            for j in s:
                if j < i: allowed.discard(M[j])
    allowed = sorted(allowed)
    A += m * allowed.index(M[i])
    m *= len(allowed)

s=''
while A != 0:
    s+='%c'%(32+A%95)
    A /= 95
print s

ถอดรหัส:

sets = [range(i*9, i*9+9) for i in xrange(9)]
sets += [range(i, 81, 9) for i in xrange(9)]
sets += [[i/3*27+i%3*3+j/3*9+j%3 for j in xrange(9)] for i in xrange(9)]

s=raw_input()
A=0
m=1
while s != '':
    A += m * (ord(s[0])-32)
    s = s[1:]
    m *= 95

M=[]
for i in xrange(81):
    allowed = set(xrange(1,10))
    for s in sets:
        if i in s:
            for j in s:
                if j < i: allowed.discard(M[j])
    allowed = sorted(allowed)
    M += [allowed[A%len(allowed)]]
    A /= len(allowed)

for i in xrange(9):
    print ' '.join(str(x) for x in M[i*9:i*9+9])

เรียกใช้เช่นนี้:

> cat sudoku1 | ./sudokuEnc.py | ./sudokuDec.py
9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1

กรณีทดสอบเอาท์พุทอะไร? แค่สงสัย. คะแนนนั้นน่าประทับใจเนื่องจากรหัสสั้นเมื่อเทียบกับของฉัน
John Dvorak

@JanDvorak: ฉันได้เพิ่มบอร์ดที่เข้ารหัสแล้ว
Keith Randall

7

perl - คะแนน115 113 103 113

เอาท์พุท:

"#1!A_mb_jB)
FEIV1JH~vn"
$\\XRU*LXea.
EBIC5fPxklB
5>jM7(+0MrM
!'Wu9FS2d~!W
":`R60C"}z!k
:B&Jg[fL%\j
"L28Y?3`Q>4w
o0xPz8)_i%-

เอาท์พุท:

                  # note this line is empty
S}_h|bt:za        
%.j0.6w>?RM+
:H$>a>Cy{7C
'57UHjcWQmcw
owmK0NF?!Fv
# }aYExcZlpD
nGl^K]xH(.\
9ii]I$voC,x
!:MR0>I>PuTU

ไม่มีบรรทัดใดที่มีช่องว่างสิ้นสุด โปรดทราบว่าบรรทัดแรกว่างเปล่า

อัลกอริทึมนี้ทำงานดังนี้ ในการบีบอัด:

  1. เริ่มต้นด้วยสตริง 'ปัจจุบัน' ที่ว่างเปล่าซึ่งเป็นตัวแทนของตาราง Sudoku

  2. พิจารณาเพิ่มแต่ละหลัก 1 .. 9 ไปยังสายนั้นและกำหนดที่ทำงานได้

  3. รับตัวเลขถัดไปจากตารางคำตอบ (และเพิ่มลงในปัจจุบัน)

  4. หากมีเพียงคนเดียวที่ทำงานได้ก็ไม่มีอะไรให้เขียนโค้ด

  5. หากมีมากกว่าหนึ่งตัวเลือกให้นับจำนวนตัวเลือกที่ทำงานได้เรียงลำดับและรหัสหลักที่เป็นดัชนีลงในอาร์เรย์ที่เรียงลำดับ บันทึกตัวเลขและจำนวนที่ทำงานได้เป็น 2-tuple ในอาร์เรย์

  6. เมื่อทำเสร็จแล้วให้เขียนโค้ด 2-tuples (เรียงตามลำดับกลับกัน) ในหมายเลขตามตัวแปรที่จัดเก็บไว้เป็นใหญ่

  7. แสดง bigint ในฐาน 95

ในการถอดรหัส:

  1. เริ่มต้นด้วยสตริง 'ปัจจุบัน' ที่ว่างเปล่าซึ่งเป็นตัวแทนของตาราง Sudoku

  2. ถอดรหัสหมายเลข base95 ให้เป็นใหญ่

  3. พิจารณาเพิ่มแต่ละหลัก 1 .. 9 ไปยังสายนั้นและกำหนดที่ทำงานได้

  4. หากมีเพียงคนเดียวที่ทำงานได้ก็ไม่มีอะไรที่จะต้องเขียนโค้ด เพิ่มตัวเลือกนั้นในกริด

  5. หากมีมากกว่าหนึ่งตัวเลือกให้นับจำนวนตัวเลือกที่ทำงานได้เรียงลำดับและรหัสหลักที่เป็นดัชนีลงในอาร์เรย์ที่เรียงลำดับ

  6. ถอดรหัสฐานตัวแปรขนาดใหญ่โดยใช้จำนวนตัวเลือกที่ทำงานได้เป็นฐานและโมดูลัสเป็นดัชนีในอาร์เรย์และส่งออกตัวเลขนั้นเป็นค่าเซลล์

เพื่อกำหนดจำนวนของตัวเลือกที่ทำงานได้ Games :: Sudoku :: Solver จะถูกใช้ นั่นคือเพื่อความชัดเจนเป็นหลักเนื่องจากมีนักแก้ปัญหา Sudoku 3 บรรทัดในเว็บไซต์นี้

ในการทำทั้งหมด 10 ใช้เวลา 8 วินาทีในแล็ปท็อปของฉัน

การfudgeดำเนินการเรียงลำดับอาร์เรย์แตกต่างกันเพื่อให้ได้ค่าน้อยที่สุดสำหรับกรณีทดสอบ ตามเอกสารแล้วนี่เป็นเรื่องเหลวไหล เหลวไหลลดคะแนนจาก 115 เป็น 103 มันเป็นงานฝีมือเพื่อให้แน่ใจว่ารหัส bigint สำหรับการทดสอบครั้งแรกคือ 0 คะแนนกรณีที่เลวร้ายที่สุดสำหรับซูโดกุใด ๆ คือ 12 ให้คะแนน 120 ฉันจึงไม่คิดว่านับ เป็นการเข้ารหัสที่ยาก ค่อนข้างจะปรับให้เหมาะสมสำหรับข้อมูลการทดสอบ หากต้องการดูว่ามันทำงานได้โดยปราศจากสิ่งนี้ให้เปลี่ยนsort fudgeเป็นsortทั้งสองแห่ง

รหัสดังต่อไปนี้:

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use bigint;
use Games::Sudoku::Solver qw (:Minimal set_solution_max count_occupied_cells);

# NOTE THIS IS NOT USED BY DEFAULT - see below and discussion in comments
my @fudgefactor = qw (9 7 3 5 8 1 4 2 6 5 2 6 4 7 3 1 9 8 1 8 4 2 9 6 7 5 3 2 4 7 8 6 5 3 1 9 3 9 8 1 2 4 6 7 5 6 5 1 7 3 9 8 4 2 8 1 9 3 4 2 5 6 7 7 6 5 9 1 8 2 3 4 4 3 2 6 5 7 9 8 1);
my $fudgeindex=0;
my $fudging=0; # Change to 1 to decrease score by 10

sub isviable
{
    no bigint;
    my $current = shift @_;
    my @test = map {$_ + 0} split(//, substr(($current).("0"x81), 0, 81));
    my @sudoku;
    my @solution;
    set_solution_max (2);
    my $nsolutions;

    eval
    {
        sudoku_set(\@sudoku, \@test);
        $nsolutions = sudoku_solve(\@sudoku, \@solution);
    };
    return 0 unless $nsolutions;
    return ($nsolutions >=1);
}

sub getnextviable
{
    my $current = shift @_; # grid we have so far
    my %viable;

    for (my $i = 1; $i<=9; $i++)
    {
        my $n;
        my $solution;
        $viable{$i} = 1 if (isviable($current.$i));
    }
    return %viable;
}

sub fudge
{
    return $a<=>$b unless ($fudging);
    my $k=$fudgefactor[$fudgeindex];
    my $aa = ($a+10-$k) % 10;
    my $bb = ($b+10-$k) % 10;
    return $aa<=>$bb;
}


sub compress
{
    my @data;
    while (<>)
    {
        chomp;
        foreach my $d (split(/\s+/))
        {
            push @data, $d;
        }
    }

    my $code = 0;
    my $current = "";
    my @codepoints;
    foreach my $d (@data)
    {
        my %viable = getnextviable($current);
        die "Digit $d is unexpectedly not viable - is sudoku impossible?" unless ($viable{$d});

        my $nviable = scalar keys(%viable);
        if ($nviable>1)
        {
            my $n=0;
            foreach my $k (sort fudge keys %viable)
            {
                if ($k==$d)
                {
                    no bigint;
                    my %cp = ( "n"=> $n, "v"=> $nviable);
                    unshift @codepoints, \%cp;
                    last;
                }
                $n++;
            }
        }
        $fudgeindex++;
        $current .= $d;
    }

    foreach my $cp (@codepoints)
    {
        $code = ($code * $cp->{"v"})+$cp->{"n"};
    }

    # print in base 95
    my $out="";
    while ($code)
    {
        my $digit = $code % 95;
        $out = chr($digit+32).$out;
        $code -= $digit;
        $code /= 95;
    }

    print "$out";
}

sub decompress
{
    my $code = 0;

    # Read from base 95 into bigint
    while (<>)
    {
        chomp;
        foreach my $char (split (//, $_))
        {
            my $c =ord($char)-32;
            $code*=95;
            $code+=$c;
        }
    }

    # Reconstruct sudoku
    my $current = "";
    for (my $cell = 0; $cell <81; $cell++)
    {
        my %viable = getnextviable($current);
        my $nviable = scalar keys(%viable);
        die "Cell $cell is unexpectedly not viable - is sudoku impossible?" unless ($nviable);

        my $mod = $code % $nviable;
        $code -= $mod;
        $code /= $nviable;

        my @v = sort fudge keys (%viable);
        my $d = $v[$mod];
        $current .= $d;
        print $d.(($cell %9 != 8)?" ":"\n");
        $fudgeindex++;
    }
}

my $decompress;
GetOptions ("d|decompress" => \$decompress);


if ($decompress)
{
    decompress;
}
else
{
    compress;
}

5
"ฉันจึงไม่คิดว่าสิ่งนี้นับว่าเป็นการเข้ารหัสที่ยาก" เป็นคำสั่งที่ค่อนข้างเข้มการพิจารณากรณีทดสอบอย่างใดอย่างหนึ่งอยู่ในรหัสคำต่อคำของคุณ
Aaron Dufour

@AaronDufour คุณพลาดคำต่อไปนี้: "แต่มันเพิ่มประสิทธิภาพสำหรับข้อมูลการทดสอบ" ดูการอภิปรายภายใต้คำถาม ถ้าคุณปรับให้เหมาะสมคุณจะได้รับสัญลักษณ์ 0 ถึง 12 จาก 120 โดยโชคดีที่โซลูชันที่ไม่ได้เพิ่มประสิทธิภาพให้ 115 การชดเชยโมดูลัสคงที่แบบสุ่มใช้เวลาถึง 113 คุณสามารถลบได้มากถึง 12 เนื่องจากวิธีการทำประตู ฉันค่อนข้างมั่นใจว่าวิธีนี้ยังให้ขนาดโซลูชันที่ต่ำที่สุดโดยเฉลี่ยสำหรับชุดอินพุตแบบสุ่ม (ถ้าคุณคิดเกี่ยวกับมันต้องหรือต้องใกล้เคียงกับมันมาก) ซึ่งเป็นเหตุผลที่ฉันบอกว่ามันไม่ได้พึ่งพา การเข้ารหัส
abligh

1
ตัวเข้ารหัสที่สมบูรณ์แบบ (เช่นตัวที่ระบุ 6670903752021072936960 เคส) สามารถเพิ่มเข้าไปได้อย่างง่ายดายด้วยการเข้ารหัสอย่างหนักของทั้งสิบกรณีทดสอบส่งผลให้คะแนน 9 เพียงเพิ่ม 10 เป็นจำนวนเต็มขนาดใหญ่และแทนที่ด้วย 0..9 สำหรับกรณีพิเศษ 0 รหัสเป็นสตริงที่ว่างเปล่าและรหัสที่เหลือเป็นหนึ่งอักขระดังนั้นคะแนน 9 ผลกระทบของสิ่งนี้กับจำนวนอักขระเฉลี่ยต่อบอร์ดคือการเพิ่มขึ้น 3.3x10 ^ -22 ซึ่งไม่สามารถตรวจสอบได้
Mark Adler

... ซึ่งเป็นสาเหตุให้คะแนนที่นี่เสีย ฉันแนะนำทางเลือกอื่น
abligh

-1 สำหรับความเหลวไหล - ถึงแม้ว่ามันจะเป็นเพียงการแสดงให้เห็นปัญหาที่เกิดขึ้นกับการให้คะแนน ...
John Dvorak

6

CJam, 309 ไบต์

นี่เป็นเพียงโซลูชันพื้นฐานที่รวดเร็ว ฉันขอโทษฉันทำสิ่งนี้ในภาษากอล์ฟ แต่จริงๆแล้วมันเป็นวิธีที่ง่ายที่สุดที่จะทำ ฉันจะเพิ่มคำอธิบายของรหัสจริงในวันพรุ่งนี้ แต่ฉันได้อธิบายขั้นตอนวิธีด้านล่าง

Encoder

q~{);}%);:+:(9b95b32f+:c

ถอดรหัส

l:i32f-95b9bW%[0]64*+64<W%:)8/{_:+45\-+}%z{_:+45\-+}%z`

ทดสอบที่นี่

อินพุตของตัวเข้ารหัส (บน STDIN) และเอาต์พุตของตัวถอดรหัส (บน STDOUT) อยู่ในรูปแบบของอาร์เรย์ CJam ที่ซ้อนกัน เช่น

[[8 3 5 4 1 6 9 2 7] [2 9 6 8 5 7 4 3 1] [4 1 7 2 9 3 6 5 8] [5 6 9 1 3 4 7 8 2] [1 2 3 6 7 8 5 4 9] [7 4 8 5 2 9 1 6 3] [6 5 2 7 8 1 3 9 4] [9 8 1 3 4 5 2 7 6] [3 7 4 9 6 2 8 1 5]]

10 ผลการทดสอบคือ:

U(5wtqmC.-[TM.#aMY#k*)pErHQcg'{
EWrn"^@p+g<5XT5G[r1|bk?q6Nx4~r?
#489pLj5+ML+z@y$]8a@CI,K}B$$Mwn
LF_X^"-h**A!'VZq kHT@F:"ZMD?A0r
?gD;"tw<yG%8y!3S"BC:ojQ!#;i-:\g
qS#"L%`4yei?Ce_r`{@EOl66m^hx77
"EF?` %!H@YX6J0F93->%90O7T#C_5u
9V)R+6@Jx(jg@@U6.DrMO*5G'P<OHv8
(Ua6z{V:hX#sV@g0s<|!X[T,Jy|oQ+K
N,F8F1!@OH1%%zs%dI`Q\q,~oAEl(:O

อัลกอริทึมง่ายมาก:

  • ลบคอลัมน์และแถวสุดท้าย
  • ปฏิบัติต่อ 64 หลักที่เหลือเป็นตัวเลขฐาน 9 (หลังจากลดแต่ละหลักด้วย 1)
  • แปลงเป็นฐาน -95 เพิ่ม 32 เป็นหลักแต่ละตัวและเปลี่ยนเป็นอักขระ ASCII ที่สอดคล้องกัน
  • สำหรับการถอดรหัสให้ย้อนกลับการแปลงฐานและกรอกข้อมูลในคอลัมน์และแถวสุดท้ายด้วยตัวเลขที่หายไป

ฉันเพิ่มกรณีทดสอบ 10 ข้อ คะแนนคือผลรวมของจำนวนตัวอักษรในทั้ง 10 ตอนนี้
kukac67

@ kukac67 ใช่แล้วได้รับการแก้ไขแล้ว
Martin Ender

ฉันขอโทษฉันดูเหมือนว่าจะมีการเปลี่ยนแปลงกรณีทดสอบที่ 8 หลังจากที่คุณวิ่ง ฉันไม่เร็วพอ : D
kukac67

การถอดรหัสกรณีทดสอบที่ 7 ฉันสังเกตว่ามันไม่ทำงาน ฉันคิดว่าคุณมีข้อบกพร่อง "[[4 5 7 9 2 8 3 3 4] ... "
kukac67

@ kukac67 ควรได้รับการแก้ไข ฉันลืมใส่ผลลัพธ์ 64 หลักด้วย 0 ชั้นนำ
Martin Ender

6

Python 2.7, 107 ตัวอักษรทั้งหมด

TL; DRกำลังแจงนับโหดร้าย 3x3 กำลังสองพร้อมข้อ จำกัด ด้านบน + ซ้าย

กรณีทดสอบ:

import itertools

inputs = """
9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1

7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2

1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2

8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5

6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5

1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8

1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8

5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4

2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9

8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6
""".strip().split('\n\n')

ฟังก์ชั่นผู้ช่วยในการพิมพ์ซูโดกุ

def print_sudoku(m):
    for k in m:
        print' '.join(str(i) for i in k)

สร้างสี่เหลี่ยมที่เป็นไปได้ทั้งหมดที่กำหนดข้อ จำกัด ด้านบนและด้านซ้าย

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

def potential_squares(u1, u2, u3, l1, l2, l3):
    """
    returns generator of possible squares given lists of digits above and below

           u1 u2 u3
           |  |  |
    l1 --  a  b  c
    l2 --  d  e  f
    l3 --  g  h  i

    if no items exist the empty list must be given
    """
    for a, b, c, d, e, f, g, h, i in itertools.permutations(xrange(1, 10)):
        if a not in u1 and a not in l1 and b not in u2 and b not in l1 and c not in u3 and c not in l1 and d not in u1 and d not in l2 and e not in u2 and e not in l2 and f not in u3 and f not in l2 and g not in u1 and g not in l3 and h not in u2 and h not in l3 and i not in u3 and i not in l3:
            yield (a, b, c, d, e, f, g, h, i)

แยกสี่เหลี่ยมทั้งหมดออกจากกระดานซูโดกุเป็นสิ่งอันดับ

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

def board_to_squares(board):
    """
    finds 9 squares in a 9x9 board in this order:
    1 1 1 2 2 2 3 3 3
    1 1 1 2 2 2 3 3 3
    1 1 1 2 2 2 3 3 3
    4 4 4 5 5 5 6 6 6
    4 4 4 5 5 5 6 6 6
    4 4 4 5 5 5 6 6 6
    7 7 7 8 8 8 9 9 9
    7 7 7 8 8 8 9 9 9
    7 7 7 8 8 8 9 9 9

    returns tuple for each square as follows:
    a b c
    d e f   -->  (a,b,c,d,e,f,g,h,i)
    g h i
    """
    labels = [[3 * i + 1] * 3 + [3 * i + 2] * 3 + [3 * i + 3] * 3 for i in [0, 0, 0, 1, 1, 1, 2, 2, 2]]
    labelled_board = zip(sum(board, []), sum(labels, []))
    return [tuple(a for a, b in labelled_board if b == sq) for sq in xrange(1, 10)]

แปลงสี่เหลี่ยมกลับไปเป็นกระดานซูโดกุ

โดยทั่วไปการผกผันของฟังก์ชันข้างต้น

def squares_to_board(squares):
    """
    inverse of above
    """
    board = [[i / 3 * 27 + i % 3 * 3 + j / 3 * 9 + j % 3 for j in range(9)] for i in range(9)]
    flattened = sum([list(square) for square in squares], [])
    for i in range(9):
        for j in range(9):
            board[i][j] = flattened[board[i][j]]
    return board

ให้สี่เหลี่ยมทางซ้ายกลับข้อ จำกัด

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

def sum_rows(*squares):
    """
    takes tuples for squares and returns lists corresponding to the rows:
    l1 -- a b c   j k l
    l2 -- d e f   m n o  ...
    l3 -- g h i   p q r
    """
    l1 = []
    l2 = []
    l3 = []
    if len(squares):
        for a, b, c, d, e, f, g, h, i in squares:
            l1 += [a, b, c]
            l2 += [d, e, f]
            l3 += [g, h, i]
        return l1, l2, l3
    return [], [], []

กำหนดช่องสี่เหลี่ยมด้านบนส่งคืนข้อ จำกัด

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

def sum_cols(*squares):
    """
    takes tuples for squares and returns lists corresponding to the cols:

    u1 u2 u3
    |  |  |
    a  b  c
    d  e  f
    g  h  i

    j  k  l
    m  n  o
    p  q  r

      ...

    """
    u1 = []
    u2 = []
    u3 = []
    if len(squares):
        for a, b, c, d, e, f, g, h, i in squares:
            u1 += [a, d, g]
            u2 += [b, e, h]
            u3 += [c, f, i]
        return u1, u2, u3
    return [], [], []

ทำให้สตริง

def base95(A):
    if type(A) is int or type(A) is long:
        s = ''
        while A > 0:
            s += chr(32 + A % 95)
            A /= 95
        return s
    if type(A) is str:
        return sum((ord(c) - 32) * (95 ** i) for i, c in enumerate(A))

นี่คือรายการของการอ้างอิง hardcoded สำหรับแต่ละช่อง

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

"""
dependencies: every square as labeled
1 2 3
4 5 6
7 8 9
is dependent on those above and to the left

in a dictionary, it is:
square: ([above],[left])
"""
dependencies = {1: ([], []), 2: ([], [1]), 3: ([], [1, 2]), 4: ([1], []), 5: ([2], [4]), 6: ([3], [4, 5]),
                7: ([1, 4], []), 8: ([2, 5], [7]), 9: ([3, 6], [7, 8])}

นี่คือรายการ hardcoded ของจำนวนสูงสุดของตัวเลือกที่เป็นไปได้สำหรับแต่ละช่อง

ดูความคิดเห็นรหัสสำหรับรายละเอียดเพิ่มเติม

"""
max possible options for a given element

  9 8 7   ? ? ?   3 2 1
  6 5 4  (12096)  3 2 1
  3 2 1   ? ? ?   3 2 1

  ? ? ?   ? ? ?   2 2 1
 (12096)  (420)   2 1 1    (limits for squares 2,4 determined experimentally)
  ? ? ?   ? ? ?   1 1 1    (limit for square 5 is a pessimistic guess, might be wrong)

  3 3 3   2 2 1   1 1 1
  2 2 2   2 1 1   1 1 1
  1 1 1   1 1 1   1 1 1
"""
possibilities = [362880, 12096, 216, 12096, 420, 8, 216, 8, 1]

เหล่านี้รวมฟังก์ชั่นด้านบนและแปลงบอร์ดเป็นรายการจำนวนเต็ม

def factorize_sudoku(board):
    squares = board_to_squares(board)
    factors = []

    for label in xrange(1, 10):
        above, left = dependencies[label]
        u1, u2, u3 = sum_cols(*[sq for i, sq in enumerate(squares) if i + 1 in above])
        l1, l2, l3 = sum_rows(*[sq for i, sq in enumerate(squares) if i + 1 in left])
        for i, k in enumerate(potential_squares(u1, u2, u3, l1, l2, l3)):
            if k == squares[label - 1]:
                factors.append(i)
                continue
    return factors

และกลับไปที่กระดาน

def unfactorize_sudoku(factors):
    squares = []
    for label in xrange(1, 10):
        factor = factors[label - 1]
        above, left = dependencies[label]
        u1, u2, u3 = sum_cols(*[sq for i, sq in enumerate(squares) if i + 1 in above])
        l1, l2, l3 = sum_rows(*[sq for i, sq in enumerate(squares) if i + 1 in left])
        for i, k in enumerate(potential_squares(u1, u2, u3, l1, l2, l3)):
            if i == factor:
                squares.append(k)
                continue
    return squares

โอเคนั่นคือฟังก์ชั่นทั้งหมด

สำหรับแต่ละบอร์ดให้สร้างสตริงและพิมพ์

strings = []
for sudoku in inputs:
    board = [[int(x) for x in line.split()] for line in sudoku.strip().split('\n')]
    print_sudoku(board)
    factors = factorize_sudoku(board)

    i = 0
    for item, modulus in zip(factors, possibilities):
        i *= modulus
        i += item

    strings.append(base95(i))
    print 'integral representation:', i
    print 'bits of entropy:', i.bit_length()
    print 'base95 representation:', strings[-1]
    print ''

ตอนนี้พิมพ์ความยาวทั้งหมดของสตริงทั้งหมด

print 'overall output:', strings
print 'total length:', len(''.join(strings))
print ''

และยกเลิกการแปลงเพื่อพิสูจน์ว่าไม่ใช่การบีบอัดข้อมูลทางเดียว

for string in strings:
    print 'from:', string

    i = base95(string)
    retrieved = []
    for base in possibilities[::-1]:
        retrieved.append(i % base)
        i /= base

    squares = unfactorize_sudoku(retrieved[::-1])
    print_sudoku(squares_to_board(squares))
    print ''

เอาท์พุท:

9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1
integral representation: 65073646522550110083448
bits of entropy: 76
base95 representation: 23f!dvoR[pI+

7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2
integral representation: 45592184788002754998731
bits of entropy: 76
base95 representation: +gel3sJ?vL!(

1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2
integral representation: 3351617758498333760666
bits of entropy: 72
base95 representation: !"=W3R"`w|W

8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5
integral representation: 54077388556332388193975
bits of entropy: 76
base95 representation: zAu5Rvno.2P)

6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5
integral representation: 38664325462033435490761
bits of entropy: 76
base95 representation: ?8KJHGXS^hk&

1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8
integral representation: 9
bits of entropy: 4
base95 representation: )

1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8
integral representation: 2146071528999475941021
bits of entropy: 71
base95 representation: ]ib2[x.u*pC

5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4
integral representation: 31150627593616723824594
bits of entropy: 75
base95 representation: BFK1'H9}r9M%

2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9
integral representation: 9659549243898865961967
bits of entropy: 74
base95 representation: ;EOSPiy9T?b!

8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6
integral representation: 56473223126891371769434
bits of entropy: 76
base95 representation: 3TLSl3hPU3x)

overall output: ['23f!dvoR[pI+', '+gel3sJ?vL!(', '!"=W3R"`w|W', 'zAu5Rvno.2P)', '?8KJHGXS^hk&', ')', ']ib2[x.u*pC', "BFK1'H9}r9M%", ';EOSPiy9T?b!', '3TLSl3hPU3x)']
total length: 107

from: 23f!dvoR[pI+
9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1

from: +gel3sJ?vL!(
7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2

from: !"=W3R"`w|W
1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2

from: zAu5Rvno.2P)
8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5

from: ?8KJHGXS^hk&
6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5

from: )
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8

from: ]ib2[x.u*pC
1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8

from: BFK1'H9}r9M%
5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4

from: ;EOSPiy9T?b!
2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9

from: 3TLSl3hPU3x)
8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6

6

Mathematica คะแนน: 130 9

ปรับปรุง:

หลังจากคำตอบนี้ถูกโพสต์ก็เป็นแรงบันดาลใจช่องโหว่ใหม่ใกล้ชิด: "การเพิ่มประสิทธิภาพสำหรับกรณีทดสอบที่กำหนด" อย่างไรก็ตามฉันจะทิ้งคำตอบนี้ไว้เป็นตัวอย่างของช่องโหว่ รู้สึกฟรีเพื่อ downvote ฉันจะไม่เจ็บ


สิ่งนี้จะเข้ารหัสเซลล์ทีละครั้งตามลำดับแรสเตอร์และสำหรับแต่ละเซลล์จะกำหนดค่าของมันอย่างเหมาะสมสำหรับเซลล์ต่อ ๆ ไปโดยใช้กฎพื้นฐานของ Sudoku ตัวอย่างเช่นเมื่อเซลล์ถูกเข้ารหัสและมีความเป็นไปได้เพียงสี่อย่างดังนั้นฐาน 4 หลักจะถูกเพิ่มเข้าไปในจำนวนเต็มขนาดใหญ่ นอกจากนี้ยังเขียนรหัสกรณีทดสอบโดยตรงเป็นจำนวนเต็มขนาดเล็กยังคงถูกบีบอัดและคลายการบีบอัดบอร์ด Sudoku ที่ถูกต้องทั้งหมดที่มีความยาวเฉลี่ยการบีบอัดของ ~ 12.5 ตัวอักษร 1.5 มากกว่า 11.035 ที่ดีที่สุดด้วยรหัสที่ค่อนข้างง่าย

rule=({#}&/@Union[Join[
        Range[#+1,Ceiling[#,9]],Range[#+9,81,9],
        Flatten[Outer[Plus,Range[Floor[#+8,9],Ceiling[#,27]-9,9],
            Floor[Mod[#-1,9],3]+Range[3]]]]])&/@Range[81];

encode[board_]:=
Block[{step,code,pos},
    step[{left_,x_,m_},n_]:={
        MapAt[Complement[#,{board[[n]]}]&,left,rule[[n]]],
        x+m(FirstPosition[left[[n]],board[[n]]][[1]]-1),m Length[left[[n]]]};
    code=Fold[step,{Table[Range[9],{81}],0,1},Range[81]][[2]];
    pos=Position[{206638498064127103948214,1665188010993633759502287,
        760714067080859855534739,1454154263752219616902129,6131826927558056238360710,
        237833524138130760909081600,8968162948536417279508170,3284755189143784030943149,
        912407486534781347155987,556706937207676220045188},code];
    code=If[pos==={},code+10,pos[[1,1]]-1];
    FromCharacterCode[If[code==0,{},IntegerDigits[code,95]+32]]
]    

decode[str_]:=
Block[{step,code},
    code=FromDigits[ToCharacterCode[str]-32,95];
    code=If[code<10,{206638498064127103948214,1665188010993633759502287,
        760714067080859855534739,1454154263752219616902129,6131826927558056238360710,
        237833524138130760909081600,8968162948536417279508170,3284755189143784030943149,
        912407486534781347155987,556706937207676220045188}[[code+1]],code-10];
    step[{left_,x_,board_},n_]:=Function[z,{
        MapAt[Complement[#,{z}]&,left,rule[[n]]],Quotient[x,Length[left[[n]]]],
        Append[board,z]}][left[[n,Mod[x,Length[left[[n]]]]+1]]];
    Fold[step,{Table[Range[9],{81}],code,{}},Range[81]][[3]]
]

กรณีทดสอบที่เข้ารหัส:

     <- empty string
!
"
#
$
%
&
'
(
)

สิ่งนี้ไม่ได้ส่งผลให้มีการเข้ารหัสที่สมบูรณ์แบบ (โดยเฉลี่ย ~ 11) เนื่องจากกฎพื้นฐานไม่ได้ออกกฎตัวเลือกบางอย่างซึ่งในความเป็นจริงไม่มีวิธีแก้ปัญหา ประสิทธิภาพสามารถทำให้สมบูรณ์แบบ (เช่นจำนวนเต็มขนาดใหญ่จะน้อยกว่าบอร์ด Sudoku ที่เป็นไปได้เสมอ) โดยการตรวจสอบว่าไม่มีวิธีแก้ปัญหาสำหรับตัวเลือกในปัจจุบันที่ใช้ตัวแก้ Sudoku หรือไม่และกำจัดสิ่งเหล่านั้นด้วย


และใช่เป็นเรื่องน่าเสียดายที่กฎของการท้าทายนี้อนุญาตให้ใช้วิธีแก้ไขปัญหานี้
Mark Adler

1
ใช่ความท้าทายตามที่เขียนลงไปถึงกับดักนี้ แต่การเข้ารหัส
xnor

1
จากเมตาโพสต์นั้น"โปรแกรมของคุณคาดว่าจะทำงานได้ไม่เพียง แต่พิมพ์ผลการคำนวณล่วงหน้า" ในความเป็นจริงโปรแกรมนี้ทำงานทั้งหมดเพื่อบีบอัดผลการทดสอบแล้วทำการแมปจำนวนเต็มจำนวนมากที่เป็นตัวแทนของบอร์ดเหล่านั้นกับจำนวนเต็ม 0..9 เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด มีบอร์ดที่แมปกับจำนวนเต็มเหล่านั้นไม่ว่าจะเป็นอะไรก็ตาม ฉันแค่เลือกกรณีทดสอบเพื่อเป็นบอร์ดเหล่านั้น โปรแกรมเข้ารหัสและถอดรหัสบอร์ดที่เป็นไปได้ทั้งหมดดังนั้นจึงทำงานทั้งหมดที่จำเป็นในการท้าทาย
Mark Adler

คุณพูดถูกเมตาโพสต์นั้นไม่ครอบคลุม ใหม่เพิ่งโพสต์ให้ทำเช่นนั้น: meta.codegolf.stackexchange.com/a/2507/20260
xnor

4

J, 254 คะแนน

การอัด
fwrite&'sudoku.z' 1 u: u: 32 + (26$95) #: (9 $ !9x)#. A."1 (1&".);._2 stdin''
การบีบอัด
echo A.&(>:i.9)"1 (9 $ !9x) #: 95x #. 32 -~ 3 u: fread'sudoku.z'

I / O มาตรฐานค่อนข้างงุ่มง่ามใน J เนื่องจากjconsoleจริงๆแล้วเป็น REPL ดังนั้นฉันจึงใช้เสรีภาพในการเขียนเอาต์พุตที่บีบอัดไปยังไฟล์

ค้นหาดัชนีแอนนาแกรมของแต่ละบรรทัดปฏิบัติกับตัวเลขเก้าตัวที่เป็นผลเป็นฐาน - (9!) จากนั้นแปลงเป็นฐาน -95 เพิ่ม 32 และแปลงเป็น ASCII เหมือนกับโซลูชันของ Martin Büttner ดัชนีแอนนาแกรมของการเรียงสับเปลี่ยนของ1..nเป็นเพียงดัชนีของการเปลี่ยนแปลงในรายการเรียงลำดับของการเรียงสับเปลี่ยนทั้งหมดเช่น5 4 3 2 1มีดัชนีแอนนาแกรม5! - 1 = 119

การดำเนินการทั้งหมดมีผกผันได้ง่ายดังนั้นการบีบอัดจึงง่าย

โบนัสเป็นตัวอย่างที่อยู่ในรูปแบบที่เป็นมิตรกับ J ดังนั้นอินพุต / เอาต์พุตสำหรับซูโดกุที่คลายการบีบอัดจะเป็นไปตามที่ระบุในตัวอย่าง (แม้ว่าอินพุตไปยังตัวเข้ารหัสต้องขึ้นบรรทัดใหม่)


สตริงที่บีบอัดสำหรับ testcases:

#p8<!w=C6Cpgi/-+vn)FU]AHr\
"bC]wPv{8ze$l,+jkCPi0,e>-D
2}2EZZB;)WZQF@JChz}~-}}_<
#2Ofs0Mm]).e^raUu^f@sSMWc"
":kkCf2;^U_UDC?I\PC"[*gj|!
#TISE3?d7>oZ_I2.C16Z*gg
,@ CE;zX{.l\xRAc]~@vCw)8R
!oN{|Y6V"C.q<{gq(s?M@O]"]9
VORd2"*T,J;JSh<G=rR*8J1LT
#?bHF:y@oRI8e1Zdl5:BzYO.P.

หากคุณบีบอัดเฉพาะ 8 แถวแรกแถวที่ 9 นั้นง่ายต่อการคำนวณ
Keith Randall

@ KeithRandall ใช่ฉันก็คิดเช่นกัน ฉันคิดว่าเราสามารถทำได้ดียิ่งขึ้นโดยออกจากแถวที่ใหญ่ที่สุดเสมอแล้วเก็บดัชนีของแถวเพื่อคำนวณใหม่ ฉันไม่คิดว่าฉันจะกังวลที่จะใช้มันเพราะมันจะไม่ทำให้ฉันลงไปจนถึง 1xx
FireFly

3

Python 3, 120 คะแนน

โปรแกรมนี้แสดงรายการ 3x3 บล็อกที่เป็นไปได้ทั้งหมดและจดจำว่าหนึ่งในนั้นมีอยู่ใน Sudoku ดั้งเดิมจากนั้นนำตัวเลขทั้งหมดเหล่านั้นมารวมกันเป็นตัวแทน -95 แม้ว่านี่จะใกล้เคียงกับการเข้ารหัสอย่างหนัก แต่ก็บีบอัดและคลายตัวอย่างในเวลาประมาณ 5 วินาทีในเครื่องของฉัน

import functools

def readSudoku(s):
    values = [int(c) for c in s.split()]
    blocks = []
    for i in range(3):
        for j in range(3):
            block = []
            for k in range(3):
                for l in range(3):
                    block.append(values[i * 27 + k * 9 + j * 3 + l])
            blocks.append(block)
    return blocks

def writeSudoku(blocks):
    text = ""
    for i in range(9):
        for j in range(9):
            text += str(blocks[3 * (i // 3) + (j // 3)][3 * (i % 3) + (j % 3)]) + " "
        text += "\n"
    return text

def toASCII(num):
    chars = "".join(chr(c) for c in range(32, 127))
    if num == 0:
        return chars[0]
    else:
        return (toASCII(num // len(chars)).lstrip(chars[0]) + chars[num % len(chars)])

def toNum(text):
    chars = "".join(chr(c) for c in range(32, 127))
    return sum((len(chars) ** i * chars.index(c) for (i, c) in enumerate(text[::-1])))

def compress(sudoku):
    info = compressInfo(readSudoku(sudoku))
    return toASCII(functools.reduce(lambda old, new: (old[0] + new[0] * old[1], old[1] * new[1]), info, (0, 1))[0])

def compressInfo(sudoku):
    finished = [[0]*9]*9
    indices = [(-1, 0)]*9
    for (index, block) in enumerate(sudoku):
        counter = 0
        actual = -1
        for (location, solution) in enumerate(possibleBlocks(finished, index)):
            counter += 1
            if block == solution:
                actual = location
        if actual == -1:
            print(finished)
            print(block)
            raise ValueError
        finished[index] = block
        indices[index] = (actual, counter)
    return indices

def decompress(text):
    number = toNum(text)
    finished = [[0]*9]*9
    for i in range(9):
        blocks = list(possibleBlocks(finished, i))
        index = number % len(blocks)
        number //= len(blocks)
        finished[i] = blocks[index]
    return writeSudoku(finished)

def possibleBlocks(grid, index):
    horizontals = [grid[i] for i in (3 * (index // 3), 3 * (index // 3) + 1, 3 * (index // 3) + 2)]
    verticals = [grid[i] for i in (index % 3, index % 3 + 3, index % 3 + 6)]
    for i1 in range(1, 10):
        if any((i1 in a[0:3] for a in horizontals)) or\
           any((i1 in a[0::3] for a in verticals)):
            continue
        for i2 in range(1, 10):
            if i2 == i1 or\
               any((i2 in a[0:3] for a in horizontals)) or\
               any((i2 in a[1::3] for a in verticals)):
                continue
            for i3 in range(1, 10):
                if i3 in (i2, i1) or\
                   any((i3 in a[0:3] for a in horizontals)) or\
                   any((i3 in a[2::3] for a in verticals)):
                    continue
                for i4 in range(1, 10):
                    if i4 in (i3, i2, i1) or\
                       any((i4 in a[3:6] for a in horizontals)) or\
                       any((i4 in a[0::3] for a in verticals)):
                        continue
                    for i5 in range(1, 10):
                        if i5 in (i4, i3, i2, i1) or\
                           any((i5 in a[3:6] for a in horizontals)) or\
                           any((i5 in a[1::3] for a in verticals)):
                            continue
                        for i6 in range(1, 10):
                            if i6 in (i5, i4, i3, i2, i1) or\
                               any((i6 in a[3:6] for a in horizontals)) or\
                               any((i6 in a[2::3] for a in verticals)):
                                continue
                            for i7 in range(1, 10):
                                if i7 in (i6, i5, i4, i3, i2, i1) or\
                                   any((i7 in a[6:9] for a in horizontals)) or\
                                   any((i7 in a[0::3] for a in verticals)):
                                    continue
                                for i8 in range(1, 10):
                                    if i8 in (i7, i6, i5, i4, i3, i2, i1) or\
                                       any((i8 in a[6:9] for a in horizontals)) or\
                                       any((i8 in a[1::3] for a in verticals)):
                                        continue
                                    for i9 in range(1, 10):
                                        if i9 in (i8, i7, i6, i5, i4, i3, i2, i1) or\
                                           any((i9 in a[6:9] for a in horizontals)) or\
                                           any((i9 in a[2::3] for a in verticals)):
                                            continue
                                        yield [i1, i2, i3, i4, i5, i6, i7, i8, i9]

ฟังก์ชั่นหลักและcompress(sudoku)decompress(text)

ขาออก:

!%XIjS+]P{'Y
$OPMD&Sw&tlc
$1PdUMZ7K;W*
*=M1Ak9Oj6i\
!SY5:tDJxVo;
!F ]ki%jK>*R
'PXM4J7$s?#%
#9BJZP'%Ggse
*iAH-!9%QolJ
#&L6W6i> Dd6

3

Python 2.5, 116 คะแนน

รหัส:

emptysud=[[' ']*9 for l in range(9)]

def encconfig(dig,sud):
 conf1=[(sud[i].index(dig),i) for i in range(9)]; out=[]
 for xgroup in range(3):
  a=filter(lambda (x,y): xgroup*3<=x<(xgroup+1)*3, conf1)
  b=[x-xgroup*3 for (x,y) in sorted(a,key = lambda (x,y): y)]
  out.append([[0,1,2],[0,2,1],[1,0,2],[1,2,0],[2,0,1],[2,1,0]].index(b))
 for ygroup in range(3):
  a=filter(lambda (x,y): ygroup*3<=y<(ygroup+1)*3, conf1)
  b=[y-ygroup*3 for (x,y) in sorted(a,key = lambda (x,y): x)]
  out.append([[0,1,2],[0,2,1],[1,0,2],[1,2,0],[2,0,1],[2,1,0]].index(b))
 return sum([out[i]*(6**i) for i in range(6)])

def decconfig(conf,dig,sud=emptysud):
 inp=[]; conf1=[]; sud=[line[:] for line in sud]
 for i in range(6):
  inp.append([[0,1,2],[0,2,1],[1,0,2],[1,2,0],[2,0,1],[2,1,0]][conf%6]); conf/=6
 for groupx in range(3):
  for groupy in range(3):
   conf1.append((groupx*3+inp[groupx][groupy],groupy*3+inp[groupy+3][groupx]))
 for (x,y) in conf1: sud[y][x]=dig
 return sud

def compatible(sud,conf,dig):
 a=reduce(lambda x,y: x+y, sud)
 b=decconfig(conf,dig,sud)
 c=reduce(lambda x,y: x+y, b)
 return a.count(' ')-c.count(' ')==9

def encode(sud):
 k=[encconfig(str(i),sud) for i in range(1,10)]; m=k[0]; p=6**6
 cursud=decconfig(k[0],'1')
 for i in range(1,9):
  t=filter(lambda u: compatible(cursud,u,str(i+1)), range(6**6))
  m=m+p*t.index(k[i]); p*=len(t)
  cursud=decconfig(k[i],str(i+1),cursud)
 return m

def decode(n):
 k=[n%46656]; n/=46656; cursud=decconfig(k[-1],'1')
 for i in range(2,10):
  t=filter(lambda u: compatible(cursud,u,str(i)), range(6**6))
  k.append(n%len(t)); n/=len(t); cursud=decconfig(t[k[-1]],str(i),cursud)
 return cursud

def base95(n):
 out=''
 while n: out+=chr(32+n%95); n/=95
 return out[::-1]

def base10(s): s=s[::-1]; return sum([(ord(s[i])-32)*(95**i) for i in range(len(s))])

import time
t0=time.clock()
for part in file('sudoku.txt','rb+').read().split('\r\n\r\n'):
 sudoku=[line.split(' ') for line in part.split('\r\n')]
 encsud=base95(encode(sudoku)); sud2=decode(base10(encsud))
 print encsud,sud2==sudoku
print time.clock()-t0

ผล:

!|/FC,">;&3z
rUH">FLSgT|
)3#m|:&Zxl1c
jh _N@MG/zr
%Iye;U(6(p;0
!21.+KD0//yG
"O\B*O@8,h`y
A$`TUE#rsQu
J}ANCYXX*y5
".u2KV#4K|%a

ช้ามาก. ใช้เวลา 517 วินาทีในการเรียกใช้และตรวจสอบในเครื่องของฉัน

encconfigใช้บอร์ดซูโดกุและตัวเลขจาก 1-9 แสดงรายการพิกัด xy ที่ตัวเลขนั้นปรากฏขึ้นและส่งออกตัวเลขในช่วง (6 ** 6) ที่แสดงถึงพิกัดเหล่านั้น ("การกำหนดค่าตัวเลข")

decconfigเป็นฟังก์ชันย้อนกลับ ใช้ตัวเลขในช่วง (6 ** 6) ตัวเลขและกระดานซูโดกุ (ค่าเริ่มต้นคือว่างเปล่า) มันแสดงผลบอร์ดซูโดกุที่ซ้อนทับกับการกำหนดค่าหลัก หากหนึ่งในตำแหน่งในการกำหนดค่าตัวเลขถูกใช้ไปแล้วในบอร์ดซูโดกุที่ป้อนแล้วตัวเลขในตำแหน่งนั้นจะถูกเขียนทับโดยตัวเลขใหม่

ใช้งานร่วมกันได้จะใช้บอร์ดซูโดกุและการกำหนดค่าตัวเลข (กำหนดโดย conf และขุด) ซ้อนทับการตั้งค่าหลักบนบอร์ดซูโดกุและตรวจสอบความขัดแย้ง จากนั้นจะส่งกลับค่าจริงหรือเท็จขึ้นอยู่กับผลลัพธ์

encodeเป็นฟังก์ชั่นการบีบอัด มันต้องใช้บอร์ดซูโดกุและส่งออกตัวเลขที่เป็นตัวแทนของมัน ทำได้โดยการคัดลอกตำแหน่งของ 1 ไปยังบอร์ดว่างก่อนและสร้างรายการการกำหนดค่าทั้งหมดของหมายเลข 2 ที่เข้ากันได้กับการกำหนดค่า 1 (ซึ่งไม่ใช้สถานที่ใด ๆ 1) จากนั้นค้นหาคำสั่งของการกำหนดค่าจริง 2 ของบอร์ดในรายการและจัดเก็บจากนั้นคัดลอกการกำหนดค่าไปยังบอร์ดใหม่ซึ่งตอนนี้มีเพียง 1 และ 2 จากนั้นจะแสดงรายการการกำหนดค่าทั้งหมดของหมายเลข 3 ซึ่งเข้ากันได้กับตำแหน่งของ 1 และ 2 และอื่น ๆ

ถอดรหัสเป็นฟังก์ชั่นย้อนกลับ

Python 2.5


2

C #, 150 ไบต์

บีบอัดเอาท์พุท:

KYxnUjIpNe/YDnA
F97LclGuqeTcT2c
i6D1SvMVkS0jPlQ
32FOiIoUHpz5GGs
aAazPo2RJiH+IWQ
CwAA5NIMyNzSt1I
Cc2jOjU1+buCtVM
OgQv3Dz3PqsRvGA
eSxaW3wY5e6NGFc
olQvtpDOUPJXKGw

มันทำงานอย่างไร:

มันสร้างการเรียงสับเปลี่ยนที่เป็นไปได้ทั้งหมดของ 123456789 และจดจำได้ จากนั้นเปรียบเทียบพีชคณิตกับแถวในซูโดกุ เมื่อพบการเปลี่ยนแปลงการจับคู่สำหรับแถวการให้มันจะจดจำดัชนีของการเปลี่ยนแปลงนั้น หลังจากแต่ละแถวมันจะลบการเรียงสับเปลี่ยนทั้งหมดที่มีอย่างน้อยหนึ่งตัวอักษรในตำแหน่งเดียวกันกับแถวปัจจุบัน ทำให้แน่ใจว่าทุกหมายเลขจะไม่ซ้ำกันในคอลัมน์ จากนั้นจะใช้พีชคณิตทั้งหมดที่ไม่ทำงานอีกต่อไปตามเกณฑ์ของกล่อง เนื่องจากแถวสุดท้ายเป็นเรื่องเล็กน้อยมันจะสร้างตัวเลข 8 ตัว ฉันทดสอบว่าค่าสูงสุดของแต่ละตัวเลขเหล่านั้นจะเป็นเท่าใดและสร้างหน้ากากนับตัวเลขสำหรับแต่ละตำแหน่งของเหล่านั้น {6, 5, 3, 5, 3, 1, 2, 1, 1} เห็นได้ชัดว่าครั้งแรกที่ยาวที่สุดกับ 362880 พีชคณิต ใช้ digitmask ฉันสร้าง BigInteger กับ 1 นำเพื่อให้มันยาว 28 หลัก ผลลัพธ์นี้รวม 11 ไบต์ จากนั้นไบต์เหล่านั้นจะถูกแปลงเป็นเบส 64 หากต้องการบันทึกตัวอักษรหนึ่งตัวฉันจะลบเครื่องหมาย = ที่ส่วนท้าย

การคืนสภาพทำงานได้คล้ายกัน

มันสร้าง BigInteger ใหม่จาก base64 string แล้วเปลี่ยนเป็นสตริงอีกครั้งและแยกมันขึ้นมาอีกครั้งโดยใช้หน้ากากหน้ากากนับตัวเลข สตริงเหล่านั้นจะถูกแยกวิเคราะห์กลับไปที่ดัชนี

จากนั้นอัลกอริทึมก็เกือบจะเหมือนกันแทนที่จะค้นหาแถวในการเรียงสับเปลี่ยนที่เพิ่งใช้ดัชนีเพื่อให้ได้แถวที่เหลือทำงานเหมือนเดิม

น่าจะเป็นนี่อาจจะดีกว่าที่จะใช้ charachters ที่เป็นไปได้ 94 แบบแทนที่จะเป็น 64 เท่านั้น แต่ฉันขาด brainz ในการทำสิ่งนี้

แหล่งที่มา : คัดลอกและวางได้เพื่อให้ทำงานได้กับ 10 ตัวอย่าง .dotNet-Fiddle บอกฉันนี้เกิน memorylimit ดังนั้นคุณต้องเรียกใช้บนเครื่องของคุณเป็นข้อความ

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;

public class Programm
{
    public static void Main(string[] args)
    {
        string[] input = new[] {
            "973581426526473198184296753247865319398124675651739842819342567765918234432657981",
            "724865193169243875385197246896724351273951684451386927542639718618572439937418562", 
            "157682349432519687698347251825476193713928465964135728541293876289761534376854912", 
            "835416927296857431417293658569134782123678549748529163652781394981345276374962815", 
            "628451793594732681713689542247315869961827354385964217156243978439578126872196435", 
            "123456789456789123789123456214365897365897214897214365531648972648972531972531648", 
            "145792836376584192298361754731928645859647321462135987624873519587419263913256478",
            "527416938864329157139578642291854376348697521675132489712945863483261795956783214", 
            "246713985185496732937825146678542391493168257512379468824957613759631824361284579",
            "861294573475318692392567814236459781154783269987621345529176438648932157713845926" };

        string[] permutations = GetPermutations();
        foreach (string sudoku in input)
        {

            int[] indices = _compressSudoku(sudoku, permutations).ToArray();
            string compressedRepresentation = _toCompressedRepresentation(indices);

            Console.WriteLine(compressedRepresentation);
            indices = _fromCompressedRepresentation(compressedRepresentation);
            string decompressedSudoku = _decompressSudoku(indices, permutations);

            if (decompressedSudoku != sudoku)
                throw new Exception();
        }
        Console.ReadKey();
    }

    static int[] _digitMask = new int[] { 6, 5, 3, 5, 3, 1, 2, 1, 1 };

    private static int[] _fromCompressedRepresentation(string compressedRepresentation)
    {
        BigInteger big = new BigInteger(Convert.FromBase64String(compressedRepresentation + "="));

        string stringValue = big.ToString().Substring(1);

        List<int> indexes = new List<int>();
        int i = 0;
        while (stringValue.Length > 0)
        {
            int length = _digitMask[i++];
            string current = stringValue.Substring(0, length);
            stringValue = stringValue.Substring(length);
            indexes.Add(int.Parse(current));
        }
        return indexes.ToArray(); ;
    }

    private static string _toCompressedRepresentation(int[] indices)
    {
        StringBuilder builder = new StringBuilder("1");
        int i = 0;
        foreach (int index in indices)
        {
            string mask = "{0:D" + _digitMask[i++].ToString() + "}";
            builder.AppendFormat(mask, index);
        }

        string base64 = Convert.ToBase64String(BigInteger.Parse(builder.ToString()).ToByteArray());
        return base64.Substring(0, base64.Length - 1); // remove the = at the end.
    }

    private static IEnumerable<int> _compressSudoku(string input, string[] remainingPermutations)
    {
        string[] localRemainingPermutations = null;
        List<HashSet<char>> localUsed = null;
        for (int i = 0; i < 8; i++)
        {
            string currentRow = _getCurrentRow(input, i);
            if (i % 3 == 0)
            {
                localRemainingPermutations = remainingPermutations;
                localUsed = _initLocalUsed();
            }

            int index = 0;
            foreach (string permutation in localRemainingPermutations)
            {
                if (permutation == currentRow)
                {
                    yield return index;
                    break;
                }
                index++;
            }
            remainingPermutations = remainingPermutations.Where(permutation => _isStillValidPermutation(currentRow, permutation)).ToArray();
            if (i % 3 < 2)
            {
                for (int j = 0; j < 9; j++)
                    localUsed[j / 3].Add(currentRow[j]);
                localRemainingPermutations = localRemainingPermutations.Where(permutation => _isStillValidLocalPermutation(permutation, localUsed)).ToArray();
            }
        }
    }

    private static string _decompressSudoku(int[] indices, string[] remainingPermutations)
    {
        StringBuilder result = new StringBuilder();

        string[] localRemainingPermutations = null;
        List<HashSet<char>> localUsed = null;
        for (int i = 0; i < 9; i++)
        {
            if (i % 3 == 0)
            {
                localRemainingPermutations = remainingPermutations;
                localUsed = _initLocalUsed();
            }
            string currentRow = localRemainingPermutations[i < indices.Length ? indices[i] : 0];
            result.Append(currentRow);

            remainingPermutations = remainingPermutations.Where(permutation => _isStillValidPermutation(currentRow, permutation)).ToArray();
            if (i % 3 < 2)
            {
                for (int j = 0; j < 9; j++)
                    localUsed[j / 3].Add(currentRow[j]);
                localRemainingPermutations = localRemainingPermutations.Where(permutation => _isStillValidLocalPermutation(permutation, localUsed)).ToArray();
            }
        }
        return result.ToString();
    }

    private static string _getCurrentRow(string input, int i)
    {
        return new string(input.Skip(i * 9).Take(9).ToArray());
    }

    private static List<HashSet<char>> _initLocalUsed()
    {
        return new List<HashSet<char>> { new HashSet<char>(), new HashSet<char>(), new HashSet<char>() };
    }

    private static bool _isStillValidLocalPermutation(string permutation, List<HashSet<char>> localUsed)
    {
        for (int i = 0; i < 9; i++)
        {
            if (localUsed[i / 3].Contains(permutation[i]))
                return false;
        }
        return true;
    }

    private static bool _isStillValidPermutation(string currentRow, string permutation)
    {
        return permutation.Select((c, j) => c != currentRow[j]).All(b => b);
    }

    static string[] GetPermutations(char[] chars = null)
    {
        if (chars == null)
            chars = new[] { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
        if (chars.Length == 2)
            return new[] { new String(chars), new String(chars.Reverse().ToArray()) };
        return chars.SelectMany(c => GetPermutations(chars.Where(sc => sc != c).ToArray()), (c, s) => c + s).ToArray();
    }
}

1

Perl - 290 ตัวอักษร = 290 คะแนน

โปรแกรมนี้ไม่ใช้การเข้ารหัสที่ยากและน่าเชื่อถือบีบอัดกริดเป็น 29 ตัวอักษร (ในทางทฤษฎีแล้วมันจะเป็นไปได้ที่จะหาตัวที่เล็กกว่า)

นี่คือวิธีการทำงาน:

  • ก่อนอื่นแปลงอาร์เรย์ 9 x 9 เป็นตัวเลข 60 ซึ่งสามารถทำได้ในคอลัมน์สุดท้ายแถวสุดท้ายและตารางสุดท้ายของแต่ละเซลล์ขนาด 3 x 3 ที่สามารถดรอปได้

  • จากนั้นแปลงโดยใช้ bigint เป็นจำนวนเต็มเดียวโดยใช้องค์ประกอบ 9 ^ 60

  • จากนั้นแปลง bigint เป็นฐาน 95

คอมเพรสเซอร์และ decompressor:

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use bigint;

sub compress
{
    my @grid;
    my @nums;
    while (<>)
    {
        push @grid, [split];
    }

    # encode into 60 numbers omitting last from each row, column and 3 x 3 square
    my $i;
    my $j;
    for ($i=0; $i<=7; $i++)
    {
        for ($j=0; $j<=7; $j++)
        {
            push @nums, $grid[$i][$j] if (($i % 3 !=2 ) || ($j % 3 !=2));
        }
    }

    # encode into a big int
    my $code = 0;
    foreach my $n (@nums)
    {
        $code = $code * 9 + ($n-1);
    }

    # print in base 95
    my $out="";
    while ($code)
    {
        my $digit = $code % 95;
        $out = chr($digit+32).$out;
        $code -= $digit;
        $code /= 95;
    }

    print "$out";
}

sub decompress
{
    my @grid;
    my @nums;
    my $code = 0;

    # Read from base 95 into bigint
    while (<>)
    {
        chomp;
        foreach my $char (split (//, $_))
        {
            my $c =ord($char)-32;
            $code*=95;
            $code+=$c;
        }
    }

    # convert back to 60 numbers
    for (my $n = 0; $n<60; $n++)
    {
        my $d = $code % 9;
        $code -= $d;
        $code/=9;
        unshift @nums, $d+1;
    }

    # print filling in last column, row and 3 x 3 square
    for (my $i=0; $i<=8; $i++)
    {
        for (my $j=0; $j<=8; $j++)
        {
            if ($j == 8)
            {
                my $tot = 0;
                for (my $jj = 0; $jj<=7; $jj++)
                {
                    $tot += $grid[$i][$jj];
                }
                $grid[$i][$j]=45-$tot;
            }
            elsif ($i == 8)
            {
                my $tot = 0;
                for (my $ii = 0; $ii<=7; $ii++)
                {
                    $tot += $grid[$ii][$j];
                }
                $grid[$i][$j]=45-$tot;
            }
            elsif (($i % 3 == 2 ) && ($j % 3 == 2))
            {
                my $tot = 0;
                for (my $ii = $i-2; $ii<=$i; $ii++)
                {
                    for (my $jj = $j-2; $jj<=$j; $jj++)
                    {
                        next if (($ii % 3 == 2 ) && ($jj % 3 == 2));
                        $tot += $grid[$ii][$jj];
                    }
                }
                $grid[$i][$j]=45-$tot;
            }
            else
            {
                $grid[$i][$j] = shift @nums;
            }

            print $grid[$i][$j].(($j==8)?"":" ");
        }
        print "\n";
    }
}

my $decompress;
GetOptions ("d|decompress" => \$decompress);

if ($decompress)
{
    decompress;
}
else
{
    compress;
}

นั่นเป็นคะแนนไบต์หรือคะแนน?
Bill Woodger

@BillWoodger ฉันคิดว่า bytes (ดีตัวอักษร) = คะแนน?
abligh

1

PHP, 214

<?php
// checks each row/col/block and removes impossible candidates
function reduce($cand){
    do{
        $old = $cand;
        for($r = 0; $r < 9; ++$r){
        for($c = 0; $c < 9; ++$c){
            if(count($cand[$r][$c]) == 1){ // if filled in
                // remove values from row and col and block
                $remove = $cand[$r][$c];
                for($i = 0; $i < 9; ++$i){
                    $cand[$r][$i] = array_diff($cand[$r][$i],$remove);
                    $cand[$i][$c] = array_diff($cand[$i][$c],$remove);
                    $br = floor($r/3)*3+$i/3;
                    $bc = floor($c/3)*3+$i%3;
                    $cand[$br][$bc] = array_diff($cand[$br][$bc],$remove);
                }
                $cand[$r][$c] = $remove;
            }
        }}
    }while($old != $cand);
    return $cand;
}

// checks candidate list for completion
function done($cand){
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        if(count($cand[$r][$c]) != 1)
            return false;
    }}
    return true;
}

// board format: [[1,2,0,3,..],[..],..], $b[$row][$col]
function solve($board){
    $cand = [[],[],[],[],[],[],[],[],[]];
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        if($board[$r][$c]){ // if filled in
            $cand[$r][$c] = [$board[$r][$c]];
        }else{
            $cand[$r][$c] = range(1, 9);
        }
    }}
    $cand = reduce($cand);

    if(done($cand))  // goto not really necessary
        goto end;    // but it feels good to use it 
    else return false;

    end:
    // back to board format
    $b = [];
    for($r = 0; $r < 9; ++$r){
        $b[$r] = [];
        for($c = 0; $c < 9; ++$c){
            if(count($cand[$r][$c]) == 1)
                $b[$r][$c] = array_pop($cand[$r][$c]);
            else 
                $b[$r][$c] = 0;
        }
    }
    return $b;
}

function add_zeros($board, $ind){
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        $R = ($r + (int)($ind/9)) % 9;
        $C = ($c + (int)($ind%9)) % 9;
        if($board[$R][$C]){
            $tmp = $board[$R][$C];
            $board[$R][$C] = 0;
            if(!solve($board))
                $board[$R][$C] = $tmp;
        }   
    }}
    return $board;
}

function base95($str, $b, $z){
    $tmp = gmp_init($str, $b); $zero = gmp_init(0); $gmp95 = gmp_init(95);
    $out = '';
    while(gmp_cmp($tmp, $zero) > 0){
        $arr = gmp_div_qr($tmp, $gmp95);
        $tmp = $arr[0];
        $out .= chr(32+gmp_intval($arr[1]));
    }
    $out = chr((32+($z << 2))|($b - 10)) . strrev($out);
    return $out;
}

function encode($board, $ind){
    // remove last row+col
    $board[8] = [0,0,0,0,0,0,0,0,0];
    foreach($board as &$j) $j[8] = 0;

    // remove bottom corner of each box
    $board[2][2] = $board[2][5] = $board[5][2] = $board[5][5] = 0;

    $board = add_zeros($board, $ind);

    $str = '';$z=0;
    for($r = 0; $r < 8; ++$r){
        for($c = 0; $c < 8; ++$c){
            if(($r==2||$r==5)&&($c==2||$c==5)) continue;
            if($str == '' && !$board[$r][$c]) ++$z;
            else $str .= $board[$r][$c];
        }
    }

    $b10 = base95(rtrim($str,'0'), 10, $z);
    $b11 = base95(rtrim(str_replace(['00'],['A'],$str),'0'), 11, $z);
    $b12 = base95(rtrim(str_replace(['000','00'],['B','A'],$str),'0'), 12, $z);

    $l10 = strlen($b10);
    $l11 = strlen($b11);
    $l12 = strlen($b12);
    var_dump($z);
    if($l10 < $l11)
        if($l10 < $l12)
            return $b10;
        else 
            return $b12;
    else
        if($l11 < $l12)
            return $b11;
        else 
            return $b12;    
}

function decode($str){
    $fc = ord($str[0]);
    $base = 10 + ($fc & 3);
    $z = ($fc - 32) >> 2;

    $tmp = gmp_init(0);
    $zero = gmp_init(0); $gmp95 = gmp_init(95);
    while(strlen($str = substr($str, 1))){
        $tmp = gmp_mul($tmp, $gmp95);
        $tmp = gmp_add($tmp, gmp_init(ord($str[0])-32));
    }
    $str = gmp_strval($tmp, $base);
    $expanded = str_repeat('0', $z) . str_replace(['a','b'],['00','000'],$str) . str_repeat('0', 81);

    $board = [];
    $ind = 0;
    for($i = 0; $i < 8; ++$i){
        $board[$i] = [];
        for($j = 0; $j < 8; ++$j){
            if(($i == 2 || $i == 5) && ($j == 2 || $j == 5)) 
                $board[$i][$j] = 0;
            else
                $board[$i][$j] = (int)$expanded[$ind++];
        }
        $board[$i][8] = 0;
    }
    $board[8] = [0,0,0,0,0,0,0,0,0];
    return solve($board);
}

function printBoard($board){
    for($i = 0; $i < 9; ++$i){
        echo implode(' ', $board[$i]) . PHP_EOL;
    }
    flush();
}

function readBoard(){
    $board = [];
    for($r = 0; $r < 9; ++$r){
        $board[$r] = fscanf(STDIN, "%d%d%d%d%d%d%d%d%d");
    }
    return $board;
}
if(isset($argv[1])){
    if($argv[1] === 'enc'){
        $board = readBoard();
        $bests = ''; $bestl = 999;
        for($i = 0; $i < 71; ++$i){
            $str = encode($board, $i);
            $len = strlen($str);
            if($len < $bestl){
                $bestl = $len;
                $bests = $str;
            }
        }
        echo $bests . PHP_EOL;
    }else if($argv[1] === 'dec'){
        echo printBoard(decode(trim(fgets(STDIN))));
    }
}else{
    echo "Missing argument. Use `{$argv[0]} [enc|dec]`.\n";
}

การแก้ปัญหานี้จะทำการล้างคอลัมน์ด้านขวาและแถวล่างรวมถึงมุมด้านล่างขวาของแต่ละบล็อค 3x3 จากนั้นจะพยายามล้างเซลล์ หากมีวิธีแก้ไขปัญหาง่าย ๆ เซลล์จะยังคงว่างเปล่า

จากนั้นตารางซูโดกุจะถูกจัดรูปแบบเป็นสตริงจากซ้ายไปขวาและบนลงล่างไม่รวมคอลัมน์ขวาแถวล่างและมุมล่างขวา ศูนย์นำหน้าจะถูกนับ (ให้เป็นz) และลบออก ศูนย์ต่อท้ายจะถูกลบออกเช่นเดียวกัน

สตริงถูกจัดรูปแบบเป็นฐาน 10, 11 หรือ 12 จำนวนเต็ม (ให้ฐานนี้เป็นb) โดยมีAค่าศูนย์สองศูนย์และBสาม

นี้จะถูกแปลงเป็นฐาน-95 เป็นจำนวนเต็มและท้ายด้วยฐาน 95 z << 2 | (b - 10)บาทคิดเป็น

โทรphp sudoku-compress.php encเพื่อเข้ารหัสและphp sudoku-compress.php decถอดรหัส ตัวเข้ารหัสใช้รูปแบบที่กำหนดในคำถามพร้อมกับบรรทัดใหม่ต่อท้ายที่บังคับ

ผลการทดสอบ:

R'Ngxgi#Hu~+cR)0nE)+
Veu-b454j|:tRm(b-Xk'I
V.{mi;*6-/9Ufu[~GE"e>
F/YgX]PeyeKX5=M_+,z+Z
R&3mEHyZ6sSF'-$L<:VmX
"#b'npsIv0%L,t0yr^a.+'&
UNjx*#~I/siBGck7u9eaC%
Z!SuM^f{e<ji@F&hP-S<
*0:43tD r;=x8|&I0/k[&%
B1Mm-dx@G}[2lZId/-'h{zU

1

Java, 330 คะแนน

ก่อนที่ฉันจะถูกเยาะเย้ยด้วยคะแนนที่สูงขนาดนั้นฉันขอชี้แจงว่าฉันพยายามที่จะลองและแก้ไขมันด้วยวิธีที่แตกต่างกันโดยที่รู้ว่ามันอาจจะไม่เหมาะสมเท่าคำตอบที่ดีกว่าที่นี่ ฉันอยากรู้อยากเห็นมากขึ้นหรือน้อยลงถ้าฉันสามารถเข้าใกล้สิ่งที่ทำให้ฉันประหลาดใจฉันไม่ได้ตระหนักเลยว่ามันจะเลวร้ายเพียงใด นี่คือสิ่งที่ฉันกำลังทำอยู่ที่นี่:

  1. พัฒนาตัวละครสำหรับไขปริศนา Sudoku

  2. พัฒนาตัวผู้เล่นต่อสู้ที่สามารถแก้ไขได้ มันทำแบบนี้ค่อนข้างสุ่มในขณะที่ลบปมที่สามารถกำหนดได้เล็กน้อยก่อนถึงมือ ฉันสามารถไปถึงประมาณ 22 เบาะแสอย่างน่าเชื่อถือก่อนที่จะใช้เวลานานเกินไป

  3. เมื่อมีสัญญาณรบกวนปริศนาจะถูกแสดงโดย triplet ของเลขจำนวนเต็มหลักเดียวสำหรับแต่ละเงื่อนงำในกรณีของฉัน 22 สามในสามของ 3 ฉันคิดว่าถ้าฉันสามารถรวมเหล่านี้เป็นตัวเลข 66 หลักเดียวแล้ว base95 เข้ารหัสนี้แล้วฉันมีสิ่งที่ ถอดรหัสได้ง่าย

สตริงที่เข้ารหัสจบลงด้วยความยาวกว่าที่ฉันคาดไว้โดยทั่วไปประมาณ 33 ตัวอักษร ณ จุดนี้ฉันลองวิธีอื่นนอกเหนือจากการใช้ Java BigInteger ที่ฉันสร้างจำนวนมากจากรูปแบบ 81 บิตที่แสดงถึง 81 เซลล์ของตารางที่ 1 หมายถึงเงื่อนงำที่มีอยู่สำหรับเซลล์นี้ จากนั้นฉันรวม bitmask นั้นเข้ากับการแทนค่า 4 บิตของแต่ละค่าของเซลล์ตามลำดับต่อเนื่องปัดขึ้นเป็นไบต์และพบว่าฉันมีความยาวของสตริงที่เข้ารหัสเหมือนกันหลังจาก base95 เข้ารหัสแล้ว

ดังนั้นโดยทั่วไปฉันกำลังโพสต์รหัสของฉันในกรณีที่ใครสนใจวิธีการอื่นที่ไม่ได้ผล

คลาส Puzz

public class Puzz {

    enum By {
        Row, Column, Block
    }

    static final List<Integer> NUMBERS = Arrays.asList(new Integer[] { 1, 2, 3,
            4, 5, 6, 7, 8, 9 });

    List<Square> entries = new ArrayList<Square>();
    HashMap<Integer, List<Square>> squaresByRow = new HashMap<Integer, List<Square>>();
    HashMap<Integer, List<Square>> squaresByColumn = new HashMap<Integer, List<Square>>();
    HashMap<Integer, List<Square>> squaresByBlock = new HashMap<Integer, List<Square>>();

    public Puzz(int[][] data) {

        // Create squares put them in squares by row hashtable
        for (int r = 0; r < 9; r++) {
            List<Square> squaresInRow = new ArrayList<Square>();
            for (int c = 0; c < 9; c++) {
                Square square = new Square(r, c, data[r][c], this);
                entries.add(square);
                squaresInRow.add(square);
            }
            squaresByRow.put(r, squaresInRow);
        }

        // Put squares in column hash table
        for (int c = 0; c < 9; c++) {
            List<Square> squaresInColumn = new ArrayList<Square>();
            for (int r = 0; r < 9; r++) {
                squaresInColumn.add(squaresByRow.get(r).get(c));
            }
            squaresByColumn.put(c, squaresInColumn);
        }

        // Put squares in block hash table
        for (int i = 1; i < 10; i++) {
            squaresByBlock.put(i, new ArrayList<Square>());
        }
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                int block = getBlock(r, c);
                squaresByBlock.get(block).add(get(r, c));
            }
        }

        // Discover the possibilities
        updatePossibilities();
    }

    public void updatePossibilities() {
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                Square theSquare = get(r, c);
                if (theSquare.value != 0) {
                    theSquare.possibilities.removeAll(NUMBERS);
                    continue;
                } else {
                    theSquare.possibilities.addAll(NUMBERS);
                }
                int block = getBlock(r, c);
                HashSet<Square> squares = new HashSet<Square>();
                squares.addAll(squaresByRow.get(r));
                squares.addAll(squaresByColumn.get(c));
                squares.addAll(squaresByBlock.get(block));
                for (Square s : squares) {
                    if (s == theSquare)
                        continue;

                    theSquare.possibilities.remove(s.value);
                }
            }
        }
    }

    public int getValue(int row, int column) {
        return squaresByRow.get(row).get(column).value;
    }

    public Square get(int row, int column) {
        return squaresByRow.get(row).get(column);
    }

    public boolean set(int row, int column, int value) {
        if (value == 0) {
            squaresByRow.get(row).get(column).value = 0;
            updatePossibilities();
            return true;
        }

        if (isValid(row, column, value)) {
            squaresByRow.get(row).get(column).value = value;
            updatePossibilities();
            return true;
        } else {
            return false;
        }
    }

    public boolean isValidSubset(By subset, int row, int column, int value) {
        List<Dubs> dubss = new ArrayList<Dubs>();
        List<Trips> tripss = new ArrayList<Trips>();
        Square theSquare = get(row, column);
        int block = getBlock(row, column);
        List<Square> squares = new ArrayList<Square>();
        switch (subset) {
        case Row:
            squares.addAll(squaresByRow.get(row));
            break;
        case Column:
            squares.addAll(squaresByColumn.get(column));
            break;
        default:
            squares.addAll(squaresByBlock.get(block));
            break;
        }

        for (Square r : squares) {
            if (r == theSquare)
                continue;
            // if any of the impacted squares have this value then it is not a
            // valid value
            if (r.value == value)
                return false;

            if (r.possibilities.size() == 3) {
                List<Integer> poss = new ArrayList<Integer>(r.possibilities);
                tripss.add(new Trips(poss.get(0), poss.get(1), poss.get(2),
                        r.row, r.col));
            }

            if (r.possibilities.size() == 2) {
                List<Integer> poss = new ArrayList<Integer>(r.possibilities);
                dubss.add(new Dubs(poss.get(0), poss.get(1), r.row, r.col));
            }
        }

        // Find the trips and rule out the value if a triplet exists in squares
        List<Trips> tripsCopy = new ArrayList<Trips>(tripss);
        for (Trips trips : tripsCopy) {
            int countOfOccurrences = 0;
            for (Trips tr : tripss) {
                if (tr.equals(trips) && !(tr.row == row && tr.col == column))
                    countOfOccurrences++;
            }

            for (Dubs dubs : dubss) {
                if (trips.containedWithin(dubs)
                        && !(dubs.row == row && dubs.col == column))
                    countOfOccurrences++;
            }

            if (countOfOccurrences == 3 && trips.containedWithin(value))
                return false;
        }

        // Find the dubs and rule out the value if a double exists in squares
        List<Dubs> dubsCopy = new ArrayList<Dubs>(dubss);
        for (Dubs dubs : dubsCopy) {
            int countOfOccurrences = 0;
            for (Dubs du : dubss) {
                // Count occurrences of Dubs that are not the tested square
                if (du.equals(dubs) && !(du.row == row && du.col == column))
                    countOfOccurrences++;
            }

            if (countOfOccurrences == 2 && dubs.containedWithin(value))
                return false;
        }

        return true;
    }

    public boolean isValid(int row, int column, int value) {

        return isValidSubset(By.Row, row, column, value)
                && isValidSubset(By.Column, row, column, value)
                && isValidSubset(By.Block, row, column, value);
    }

    public int getBlock(int row, int column) {
        int blockRow = (int) Math.floor(row / 3);
        int columnRow = (int) Math.floor(column / 3) + 1;
        return (blockRow * 3) + columnRow;
    }

    public Puzz solve(Puzz arg, boolean top) throws Exception {
        // Make an original copy of the array
        Puzz p = (Puzz) arg.clone();
        for (int i = 1; i < 10; i++) {
            for (Square s : p.squaresByBlock.get(i)) {
                if (s.value == 0) {
                    for (Integer number : NUMBERS) {
                        if (p.set(s.row, s.col, number)) {
                            // System.out.println(p);
                            Puzz solved = solve(p, false);
                            if (solved != null)
                                return solved;
                        }
                    }
                    // no numbers fit here, return null and backtrack
                    p.set(s.row, s.col, 0);
                    return null;
                }
            }
        }

        // Check for remaining 0's
        for (Square s : p.entries) {
            if (s.value == 0)
                return null;
        }
        return p;
    }

    public Puzz scramble(int clues) throws Exception {
        Puzz p = (Puzz) clone();
        Random rand = new Random();
        int removed = 0;

        //Remove the last row, it is a freebie
        int toRemove = 81 - clues - 15;
        for (int c = 0; c < 9; c++) {
            p.set(8, c, 0);
        }
        p.set(0, 0, 0);
        p.set(0, 3, 0);
        p.set(0, 6, 0);
        p.set(3, 0, 0);
        p.set(3, 3, 0);
        p.set(3, 6, 0);

        // Keeping track of this because randomly removing squares can potentially create an 
        // unsolvable situation
        HashSet<Square> alreadyTried = new HashSet<Square>();
        while (removed < toRemove) {
            if (alreadyTried.size() >= ((toRemove + clues) - removed)) {
                // Start over
                removed = 0;
                alreadyTried = new HashSet<Square>();
                p = (Puzz)clone();
                for (int c = 0; c < 9; c++) {
                    p.set(8, c, 0);
                }
                p.set(0, 0, 0);
                p.set(0, 3, 0);
                p.set(0, 6, 0);
                p.set(3, 0, 0);
                p.set(3, 3, 0);
                p.set(3, 6, 0);
            }
            int randX = rand.nextInt((7) + 1);
            int randY = rand.nextInt((8) + 1);
            int existingValue = p.getValue(randX, randY);
            if (existingValue != 0) {
                p.set(randX, randY, 0);
                // confirm it is still solvable after removing this item
                Puzz psol = solve(p, true);
                if (psol != null && psol.equals(this)) {
                    removed++;
                    alreadyTried = new HashSet<Square>();
                    System.out.println("Clues Remaining: " + (81 - 15 - removed));
                } else {
                    // otherwise set it back to what it was and try again
                    p.set(randX, randY, existingValue);
                    Square s = new Square(randX, randY, existingValue, p);
                    alreadyTried.add(s);
                }
            }

        }
        p.updatePossibilities();
        return p;
    }

    public static String encode(Puzz p) { // Remove all zero'ed items
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 9; i++) {
            for (Square s : p.squaresByRow.get(i)) {
                if (s.value == 0)
                    continue;
                sb.append(s.row).append(s.col).append(s.value);
            }
        }

        // number mod 95 gives lowest digit, subtract that from original number
        BigInteger num = new BigInteger(sb.toString());
        byte[] numBytes = num.toByteArray();

        StringBuffer retVal = new StringBuffer();
        while (num.compareTo(BigInteger.ZERO) > 0) {
            int modu = num.mod(new BigInteger("95")).intValue();
            retVal.append((char) (modu + 32));
            num = num.subtract(new BigInteger("" + modu));
            num = num.divide(new BigInteger("95"));
        }
        return retVal.toString();
    }


    @Override
    public boolean equals(Object arg0) {
        if (arg0 == null || !(arg0 instanceof Puzz))
            return false;

        Puzz p = (Puzz) arg0;
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                int val1 = getValue(r, c);
                int val2 = p.getValue(r, c);
                if (val1 != val2)
                    return false;
            }
        }
        return true;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        int[][] data = new int[9][9];
        for (Square square : entries) {
            data[square.row][square.col] = square.value;
        }

        return new Puzz(data);
    }

    @Override
    public String toString() {
        if (entries == null)
            return "";
        StringBuffer sb = new StringBuffer();
        for (int r = 0; r < 9; r++) {
            for (int c = 0; c < 9; c++) {
                sb.append(getValue(r, c)).append(' ');
            }
            sb.append('\n');
        }
        return sb.toString();
    }

}

class Square {

    public Square(int row, int col, Puzz p) {
        this.row = row;
        this.col = col;
        this.p = p;
    }

    public Square(int row, int col, int value, Puzz p) {
        this(row, col, p);
        this.value = value;
    }

    int row;
    int col;
    int value;
    HashSet<Integer> possibilities = new HashSet<Integer>(Puzz.NUMBERS);
    Puzz p;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Square s = new Square(row, col, value, p);
        s.possibilities = new HashSet<Integer>();
        for (Integer val : possibilities) {
            s.possibilities.add(new Integer(val));
        }
        return s;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Square))
            return false;

        Square s = (Square) obj;
        return row == s.row && col == s.col && value == s.value
                && p.equals(s.p);
    }

    @Override
    public int hashCode() {
        return row ^ col ^ value ^ p.hashCode();
    }
}

class Dubs {
    int p1;
    int p2;

    int row, col;

    public Dubs(int p1, int p2) {
        this.p1 = p1;
        this.p2 = p2;
    }

    public Dubs(int p1, int p2, int row, int col) {
        this(p1, p2);
        this.row = row;
        this.col = col;
    }

    public boolean containedWithin(int value) {
        return (p1 == value || p2 == value);
    }

    @Override
    public boolean equals(Object arg0) {
        if (!(arg0 instanceof Dubs))
            return false;

        Dubs d = (Dubs) arg0;
        return (this.p1 == d.p1 || this.p1 == d.p2)
                && (this.p2 == d.p1 || this.p2 == d.p2);
    }
}

class Trips {
    int p1;
    int p2;
    int p3;
    int row, col;

    public Trips(int p1, int p2) {
        this.p1 = p1;
        this.p2 = p2;
    }

    public Trips(int p1, int p2, int p3) {
        this(p1, p2);
        this.p3 = p3;
    }

    public Trips(int p1, int p2, int p3, int row, int col) {
        this(p1, p2, p3);
        this.row = row;
        this.col = col;
    }

    public boolean containedWithin(int value) {
        return (p1 == value || p2 == value || p3 == value);
    }

    public boolean containedWithin(Dubs d) {
        return (d.p1 == p1 || d.p1 == p2 || d.p1 == p3)
                && (d.p2 == p1 || d.p2 == p2 || d.p2 == p3);
    }

    public boolean equals(Object arg0) {
        if (!(arg0 instanceof Trips))
            return false;

        Trips t = (Trips) arg0;
        return (this.p1 == t.p1 || this.p1 == t.p2 || this.p1 == t.p3)
                && (this.p2 == t.p1 || this.p2 == t.p2 || this.p2 == t.p3)
                && (this.p3 == t.p1 || this.p3 == t.p2 || this.p3 == t.p3);
    }
}

กรณีทดสอบของฉัน

public class TestCompression extends TestCase {

    public static int[][] test1 = new int[][] {
            new int[] { 9, 7, 3, 5, 8, 1, 4, 2, 6 },
            new int[] { 5, 2, 6, 4, 7, 3, 1, 9, 8 },
            new int[] { 1, 8, 4, 2, 9, 6, 7, 5, 3 },
            new int[] { 2, 4, 7, 8, 6, 5, 3, 1, 9 },
            new int[] { 3, 9, 8, 1, 2, 4, 6, 7, 5 },
            new int[] { 6, 5, 1, 7, 3, 9, 8, 4, 2 },
            new int[] { 8, 1, 9, 3, 4, 2, 5, 6, 7 },
            new int[] { 7, 6, 5, 9, 1, 8, 2, 3, 4 },
            new int[] { 4, 3, 2, 6, 5, 7, 9, 8, 1 } };
    public static int[][] test2 = new int[][] {
            new int[] { 7, 2, 4, 8, 6, 5, 1, 9, 3 },
            new int[] { 1, 6, 9, 2, 4, 3, 8, 7, 5 },
            new int[] { 3, 8, 5, 1, 9, 7, 2, 4, 6 },
            new int[] { 8, 9, 6, 7, 2, 4, 3, 5, 1 },
            new int[] { 2, 7, 3, 9, 5, 1, 6, 8, 4 },
            new int[] { 4, 5, 1, 3, 8, 6, 9, 2, 7 },
            new int[] { 5, 4, 2, 6, 3, 9, 7, 1, 8 },
            new int[] { 6, 1, 8, 5, 7, 2, 4, 3, 9 },
            new int[] { 9, 3, 7, 4, 1, 8, 5, 6, 2 } };
    public static int[][] test3 = new int[][] {
            new int[] { 1, 5, 7, 6, 8, 2, 3, 4, 9 },
            new int[] { 4, 3, 2, 5, 1, 9, 6, 8, 7 },
            new int[] { 6, 9, 8, 3, 4, 7, 2, 5, 1 },
            new int[] { 8, 2, 5, 4, 7, 6, 1, 9, 3 },
            new int[] { 7, 1, 3, 9, 2, 8, 4, 6, 5 },
            new int[] { 9, 6, 4, 1, 3, 5, 7, 2, 8 },
            new int[] { 5, 4, 1, 2, 9, 3, 8, 7, 6 },
            new int[] { 2, 8, 9, 7, 6, 1, 5, 3, 4 },
            new int[] { 3, 7, 6, 8, 5, 4, 9, 1, 2 } };
    public static int[][] test4 = new int[][] {
            new int[] { 8, 3, 5, 4, 1, 6, 9, 2, 7 },
            new int[] { 2, 9, 6, 8, 5, 7, 4, 3, 1 },
            new int[] { 4, 1, 7, 2, 9, 3, 6, 5, 8 },
            new int[] { 5, 6, 9, 1, 3, 4, 7, 8, 2 },
            new int[] { 1, 2, 3, 6, 7, 8, 5, 4, 9 },
            new int[] { 7, 4, 8, 5, 2, 9, 1, 6, 3 },
            new int[] { 6, 5, 2, 7, 8, 1, 3, 9, 4 },
            new int[] { 9, 8, 1, 3, 4, 5, 2, 7, 6 },
            new int[] { 3, 7, 4, 9, 6, 2, 8, 1, 5 } };
    public static int[][] test5 = new int[][] {
            new int[] { 6, 2, 8, 4, 5, 1, 7, 9, 3 },
            new int[] { 5, 9, 4, 7, 3, 2, 6, 8, 1 },
            new int[] { 7, 1, 3, 6, 8, 9, 5, 4, 2 },
            new int[] { 2, 4, 7, 3, 1, 5, 8, 6, 9 },
            new int[] { 9, 6, 1, 8, 2, 7, 3, 5, 4 },
            new int[] { 3, 8, 5, 9, 6, 4, 2, 1, 7 },
            new int[] { 1, 5, 6, 2, 4, 3, 9, 7, 8 },
            new int[] { 4, 3, 9, 5, 7, 8, 1, 2, 6 },
            new int[] { 8, 7, 2, 1, 9, 6, 4, 3, 5 } };
    public static int[][] test6 = new int[][] {
            new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
            new int[] { 4, 5, 6, 7, 8, 9, 1, 2, 3 },
            new int[] { 7, 8, 9, 1, 2, 3, 4, 5, 6 },
            new int[] { 2, 1, 4, 3, 6, 5, 8, 9, 7 },
            new int[] { 3, 6, 5, 8, 9, 7, 2, 1, 4 },
            new int[] { 8, 9, 7, 2, 1, 4, 3, 6, 5 },
            new int[] { 5, 3, 1, 6, 4, 8, 9, 7, 2 },
            new int[] { 6, 4, 8, 9, 7, 2, 5, 3, 1 },
            new int[] { 9, 7, 2, 5, 3, 1, 6, 4, 8 } };
    public static int[][] test7 = new int[][] {
            new int[] { 1, 4, 5, 7, 9, 2, 8, 3, 6 },
            new int[] { 3, 7, 6, 5, 8, 4, 1, 9, 2 },
            new int[] { 2, 9, 8, 3, 6, 1, 7, 5, 4 },
            new int[] { 7, 3, 1, 9, 2, 8, 6, 4, 5 },
            new int[] { 8, 5, 9, 6, 4, 7, 3, 2, 1 },
            new int[] { 4, 6, 2, 1, 3, 5, 9, 8, 7 },
            new int[] { 6, 2, 4, 8, 7, 3, 5, 1, 9 },
            new int[] { 5, 8, 7, 4, 1, 9, 2, 6, 3 },
            new int[] { 9, 1, 3, 2, 5, 6, 4, 7, 8 } };
    public static int[][] test8 = new int[][] {
            new int[] { 5, 2, 7, 4, 1, 6, 9, 3, 8 },
            new int[] { 8, 6, 4, 3, 2, 9, 1, 5, 7 },
            new int[] { 1, 3, 9, 5, 7, 8, 6, 4, 2 },
            new int[] { 2, 9, 1, 8, 5, 4, 3, 7, 6 },
            new int[] { 3, 4, 8, 6, 9, 7, 5, 2, 1 },
            new int[] { 6, 7, 5, 1, 3, 2, 4, 8, 9 },
            new int[] { 7, 1, 2, 9, 4, 5, 8, 6, 3 },
            new int[] { 4, 8, 3, 2, 6, 1, 7, 9, 5 },
            new int[] { 9, 5, 6, 7, 8, 3, 2, 1, 4 } };
    public static int[][] test9 = new int[][] {
            new int[] { 2, 4, 6, 7, 1, 3, 9, 8, 5 },
            new int[] { 1, 8, 5, 4, 9, 6, 7, 3, 2 },
            new int[] { 9, 3, 7, 8, 2, 5, 1, 4, 6 },
            new int[] { 6, 7, 8, 5, 4, 2, 3, 9, 1 },
            new int[] { 4, 9, 3, 1, 6, 8, 2, 5, 7 },
            new int[] { 5, 1, 2, 3, 7, 9, 4, 6, 8 },
            new int[] { 8, 2, 4, 9, 5, 7, 6, 1, 3 },
            new int[] { 7, 5, 9, 6, 3, 1, 8, 2, 4 },
            new int[] { 3, 6, 1, 2, 8, 4, 5, 7, 9 } };
    public static int[][] test10 = new int[][] {
            new int[] { 8, 6, 1, 2, 9, 4, 5, 7, 3 },
            new int[] { 4, 7, 5, 3, 1, 8, 6, 9, 2 },
            new int[] { 3, 9, 2, 5, 6, 7, 8, 1, 4 },
            new int[] { 2, 3, 6, 4, 5, 9, 7, 8, 1 },
            new int[] { 1, 5, 4, 7, 8, 3, 2, 6, 9 },
            new int[] { 9, 8, 7, 6, 2, 1, 3, 4, 5 },
            new int[] { 5, 2, 9, 1, 7, 6, 4, 3, 8 },
            new int[] { 6, 4, 8, 9, 3, 2, 1, 5, 7 },
            new int[] { 7, 1, 3, 8, 4, 5, 9, 2, 6 } };

    @Test
    public void test2() throws Exception {
        int encodedLength = 0;
        Puzz expected = new Puzz(test1);
        Puzz test = (Puzz) expected.clone();

        long start = System.currentTimeMillis();
        test = test.scramble(22);
        long duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        String encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();


        expected = new Puzz(test2);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test3);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test4);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test5);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test6);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test7);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test8);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test9);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

        encoded = Puzz.encode(test);

        System.out.println("Encoded Length with BigInteger: " + encoded.length());
        encodedLength += encoded.length();

        expected = new Puzz(test10);
        test = (Puzz) expected.clone();

        start = System.currentTimeMillis();
        test = test.scramble(22);
        duration = System.currentTimeMillis() - start;
        System.out.println("Duration of scramble for 22 clue puzzle: " + duration);
        System.out.println("Scrambled");
        System.out.println(test);

encoded = Puzz.encode(test);
encodedLength += encoded.length();

        System.out.println("Final Result: " + encodedLength); 
    }

}

ทดสอบผลลัพธ์

Duration of scramble for 22 clue puzzle: 427614
Scrambled
0 0 3 0 0 0 0 0 6 
0 2 0 0 0 0 0 9 0 
0 0 0 0 9 6 7 5 0 
0 4 0 0 0 5 0 1 0 
0 0 0 1 0 0 0 0 0 
0 5 0 0 0 0 8 4 0 
0 0 0 3 0 0 5 0 7 
7 0 0 9 0 8 0 3 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: U5[XZ+C6Bgf)}O."gDE)`\)kNv7*6}1w+
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 167739
Scrambled
0 2 4 0 0 0 0 0 0 
1 6 0 0 4 0 8 0 5 
0 0 5 0 9 7 2 0 0 
0 0 0 0 2 4 0 0 1 
0 0 3 9 0 0 0 0 0 
0 0 0 0 0 0 0 0 7 
0 4 0 0 0 0 0 0 8 
0 1 0 5 0 0 0 3 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: 7\c^oE}`H6@P.&E)Zu\t>B"k}Vf<[0a3&
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 136364
Scrambled
0 0 7 0 8 0 0 0 0 
0 3 2 0 0 9 6 0 0 
0 0 0 0 0 0 2 5 0 
0 2 0 0 0 6 0 0 0 
0 0 0 9 0 0 0 0 0 
0 0 4 1 0 5 7 2 0 
5 0 1 0 0 0 0 7 0 
2 8 9 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: [S#bHlTDwS,&w,moQ{WN}Z9!{1C>.vN{-
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 392150
Scrambled
0 0 0 0 0 6 0 0 0 
0 9 0 0 0 0 0 0 1 
4 0 0 0 0 3 6 0 8 
0 0 0 0 0 0 0 8 0 
0 0 3 0 7 8 0 0 9 
7 0 0 0 0 0 0 0 3 
6 0 2 0 0 0 0 9 0 
9 0 1 3 4 0 2 0 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: T-yKJ2<d)Dj~[~>]334*9YpxM<JQNf2|<
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 169355
Scrambled
0 0 0 0 0 1 0 0 0 
0 9 4 7 0 0 0 8 0 
0 1 3 0 0 0 5 0 2 
0 0 0 0 0 0 0 0 9 
0 0 0 0 2 7 3 5 4 
0 8 0 0 0 0 0 1 0 
0 0 0 0 4 0 9 0 8 
0 0 0 5 0 0 0 0 6 
0 0 0 0 0 0 0 0 0 

Building encoded string: 5@.=FmOKws7jl5*hWMQqqou\lv'e^Q}D:
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 786
Scrambled
0 2 3 0 0 6 0 0 0 
0 5 0 7 0 0 1 2 3 
0 8 0 0 2 0 0 0 0 
0 0 0 0 0 5 0 0 7 
0 6 5 8 0 0 0 0 0 
0 0 7 0 0 4 3 0 0 
0 3 0 0 4 0 0 0 2 
0 0 0 0 0 2 0 0 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: wY%(O9tOSDZu-PBaFl^.f0xH7C~e)=\3&
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 826530
Scrambled
0 0 0 0 9 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 9 0 3 0 1 7 0 0 
0 3 0 0 0 8 0 4 5 
0 0 9 0 0 7 3 0 0 
0 0 2 0 3 0 0 8 0 
6 0 0 0 0 0 0 0 9 
5 0 0 4 1 0 2 0 3 
0 0 0 0 0 0 0 0 0 

Building encoded string: K|>.Aa?,8e&NRL;*ut=+Iqk8E$@&-zlF9
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 4834
Scrambled
0 2 0 0 1 0 0 3 8 
8 6 0 3 0 0 1 0 0 
0 0 0 0 0 8 6 0 2 
0 0 0 0 0 0 0 7 0 
0 0 8 0 0 0 0 0 0 
0 0 0 0 3 0 0 0 0 
0 0 2 0 0 5 8 0 3 
4 0 0 0 0 1 7 9 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: GOS0!r=&HR5PZ|ezy>*l7 HWU`wIN7Q4&
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 42126
Scrambled
0 0 0 0 0 3 0 0 5 
0 0 5 4 0 0 0 3 2 
9 0 0 8 0 0 0 0 0 
0 0 0 0 0 2 0 0 0 
0 0 0 0 6 8 2 0 7 
5 1 0 0 7 0 0 0 8 
8 0 0 0 5 0 0 1 0 
7 0 0 0 0 0 0 0 4 
0 0 0 0 0 0 0 0 0 

Building encoded string: [4#9D_?I1.!h];Y_2!iqLyngbBJ&k)FF;
Encoded Length with BigInteger: 33

Duration of scramble for 22 clue puzzle: 156182
Scrambled
0 6 0 0 0 0 0 7 0 
4 0 5 3 1 0 0 0 2 
0 0 0 0 6 0 0 0 0 
0 3 0 0 0 9 0 8 1 
0 0 0 0 0 0 0 0 0 
0 0 7 0 0 1 0 4 5 
5 0 9 0 0 0 0 0 8 
6 0 0 0 3 2 0 0 0 
0 0 0 0 0 0 0 0 0 

Building encoded string: r+a;I%hGj4YCA-pXz+n=ioRL:agzH'K<(
Encoded Length with BigInteger: 33
Final Result: 330

ฉันไม่รู้ว่าคุณกำลังทำสิ่งนี้อยู่หรือไม่ แต่แถวสุดท้ายของการแย่งชิงของคุณมักจะกลายเป็นศูนย์ทั้งหมดดังนั้นการเพิ่มประสิทธิภาพอย่างหนึ่งที่คุณสามารถทำได้คือรับแถวสุดท้ายเพื่อรับและเพียงแค่สมมติว่าเซลล์ใดหายไปจากจุดสิ้นสุด การเข้ารหัสของคุณเป็นศูนย์ทั้งหมด
kukac67

0

C ++ 241 คะแนน: 82 * 10 = 820

เพิ่ม '!' ถึงจุดเริ่มต้นของสตริงที่เข้ารหัสเพื่อกำหนดการดำเนินการที่จะดำเนินการ

Golfed 241 ตัวอักษร

void D(char i){static int x=0;cout<<(int)(i-'a')<<" ";if(x++%8==0) cout<<endl;}
int main()
{
int i=81;int n;string S;
char c=cin.peek();
if(c=='!'){cin>>S;for_each(S.begin()+1,S.end(),D);}
else{S.push_back('!');while(i--){cin>>n;S.push_back(n+'a');}cout<<S;}
}

Ungolfed 312 chars

void decode(char i) {
static int x=0;
cout<<(int)(i-'a')<<" ";
if(x++%8==0) cout<<endl;
}
int main()
{
int i=81;
int n;
string d;
char c=cin.peek();
if(c=='!'){
cin>>d;
for_each(d.begin()+1,d.end(),decode);
}
else{
d.push_back('!');
while(i--)
{
cin>>n;
d.push_back(n+'a');
}
cout<<d;
}
}

4
นี่ไม่ใช่รหัสกอล์ฟ จุดประสงค์ของความท้าทายนี้คือการลดความยาวของบอร์ดที่เข้ารหัสให้น้อยที่สุด ...
John Dvorak

1
ดังนั้นทุกตารางซูโดกุนั้นสามารถบีบอัดได้ถึง 82 ไบต์?
Beta Decay
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.