PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sudoku_solver_online/core.clj

http://github.com/tzach/sudoku-solver-online
Clojure | 148 lines | 118 code | 23 blank | 7 comment | 14 complexity | 525fc8157509f290df485b12be32b02a MD5 | raw file
  1. (ns sudoku_solver_online.core
  2. (:require [appengine-magic.core :as ae]
  3. [compojure.response :as response]
  4. [compojure.route :as route])
  5. (:use sudoku_solver_online.sudoku
  6. compojure.core
  7. [ring.util.response :only [redirect]]
  8. [hiccup.core]
  9. [hiccup.page-helpers]
  10. [hiccup.form-helpers]
  11. ))
  12. ;;;; utils
  13. (defn parse-integer [str]
  14. (try (Integer/parseInt str)
  15. (catch NumberFormatException nfe 0)))
  16. (defn parse-digit [c]
  17. (if (Character/isDigit c)
  18. (Character/digit c 10) 0))
  19. (defn inter [colls]
  20. (partition (count colls) (apply interleave colls)))
  21. ;;; board utils
  22. (defn str-board [board]
  23. "convert board to string"
  24. (reduce str board))
  25. (defn unstr-board [s]
  26. "convert string to board"
  27. (vec (map parse-digit s)))
  28. (defn board? [b]
  29. "check if this is a sudoku board"
  30. (and (= 81 (count b))
  31. (every? #(and (<= % 9) (>= % 0)) b)))
  32. ;;;;
  33. ;;;; html
  34. (defn glink-to
  35. [url & content]
  36. (link-to (str "http://" url) content))
  37. (def *main-page* [:a {:href "/" } "Back to main page"])
  38. (def *css* [:link {:type "text/css" :rel "stylesheet" :href "/stylesheets/main.css"}])
  39. (def *hard* {1 "easy" 2 "not so easy" 3 "not easy at all" 4 "hard"})
  40. (def *empty-board-str* (str "/board/" (apply str (repeat 81 0))))
  41. (def *about*
  42. (html
  43. [:h5 "v.4b"]
  44. "Sudoku solver is a work in progress and an exercise in building a web service with "
  45. (glink-to "clojure.org" "Clojure") ", "
  46. (glink-to "compojure.org" "Compojure") ","
  47. (glink-to "github.com/weavejester/hiccup" "Hiccup") " and "
  48. (glink-to "https://github.com/gcv/appengine-magic" "appengine-magic")
  49. [:p] "The solver is an evolution of my old a Swing base Sudoku " (glink-to "code.google.com/p/sudoku-solver/" "solver")
  50. [:p] "If you want to use the solver API (maybe building a AJAX GUI for it?), help me with the CSS, or ask any question, just let me know."
  51. [:p] "tzach . livyatan at gmail ..."
  52. [:p][:p] (glink-to "sites.google.com/site/tzachlivyatan/Sudoku-solver-online-code" "site code")
  53. [:p][:p] "The following individuals have spent time and effort in reviewing and testing the site:"
  54. (unordered-list ["shirily bar-or"])
  55. [:p][:p][:p][:img {:src "http://code.google.com/appengine/images/appengine-noborder-120x30.gif" :alt "Powered by Google App Engine"}]
  56. ))
  57. ;;;;;
  58. (defn b-form [b]
  59. [:table {:class "external"}
  60. (for [r1 (partition 27 b)]
  61. [:tr {:class "ext-tr"}
  62. (for [c1 (p-9 r1)]
  63. [:td {:class "ext-td"}
  64. [:table {:class "internal"}
  65. (for [r2 (p-3 c1)]
  66. [:tr {:class "int-tr"}
  67. (for [c2 r2]
  68. [:td
  69. {:class "int-td"} [:input {:class (second c2)
  70. :name "board"
  71. :type 'text :maxlength 1 :size 1
  72. :value (if (zero? (first c2)) "" (first c2))
  73. }
  74. ]])])
  75. ]])
  76. ])])
  77. (defn board-form
  78. "main page"
  79. [s b]
  80. (html
  81. (doctype :html4)
  82. [:head *css* ]
  83. [:body
  84. [:h1 "Sudoku solver online"]
  85. [:h2 s]
  86. (form-to [:post "/board"]
  87. [:p] (b-form b)
  88. [:p] [:input {:type "submit" :value "Solve" :name "submit"}]
  89. [:p][:p][:p])
  90. [:p "generate a new Sudoku problem, on a scale of 1 to 4:"
  91. (unordered-list
  92. (for [[n h] *hard*] (link-to (str "/gen/" n) h)))
  93. (unordered-list [(link-to *empty-board-str* "empty board")])]
  94. [:hr]
  95. [:p] *about*
  96. ]))
  97. (defn illegal [text]
  98. (html (doctype :html4)
  99. [:body
  100. (str "My friend, you have " text)
  101. [:p] (link-to "javascript:history.back(-1)" "Back to Sudoku board")]))
  102. ;;;;;
  103. (defn solve [b]
  104. (if (legal? b)
  105. (if-let [s (mem-sodoku b)]
  106. (board-form "Sudoku Solution"
  107. (for [[x y] (inter [b s])]
  108. (if (= x y) [y "cell1"] [y "cell2"])))
  109. (illegal "sorry, this one is impossible!"))
  110. (illegal "input an illegal board")))
  111. (defroutes sudoku_solver_online_app_handler
  112. (GET "/" [] (redirect *empty-board-str*))
  113. (GET "/gen/:hard" [hard]
  114. (redirect (str "/board/" (str-board (generate-board (parse-integer hard))))))
  115. (GET "/board/:board" [board]
  116. (let [b (unstr-board board)]
  117. (if (board? b)
  118. (board-form "Sudoku Problem" (inter [b (repeat "cell1")]))
  119. (illegal "input an illegal string"))))
  120. (POST "/board" {params :params}
  121. (let [b (vec (map parse-integer (get params "board")))]
  122. "Solve" (solve b)))
  123. (route/not-found (html [:body "page not found" [:p] *main-page*] )))
  124. (ae/def-appengine-app sudoku_solver_online_app #'sudoku_solver_online_app_handler)
  125. ;;(ae/start sudoku_solver_online_app)