Blog      Support      Contact  
     Blog Categories
 - All
 - .NET
 - 4 Word Book Reviews
 - AllPodcasts
 - Business Thoughts
 - Clueless Idiocy
 - Development
 - Life
 - Norn Iron
 - Personal
 - Podcasting
 - PowerPack
 - Weird Interweb Stuff
 - What If...
 
     Web Tools
 - OPML Viewer
 - RSS Viewer
 - ASP.NET Colors
 - Base64 Encode
 - Base64 Decode
 - HTML Encode
 - HTML Decode
 - URL Encode
 - URL Decode
 - Crazy IPs
 - Whois

 
     Windows Tools

Source code for all these tools is on GitHub.

ADO.NET ConnTest
A simple, free Windows program to test ADO.NET connection strings.

Lines of C#
Ever wanted to know how many lines of C# code are in a file or folder hierarchy?  This free Windows program will tell you.

XmlTools
Free tools to process XML files from the command line.

 

I've been experimenting with the hyperlocal newsletter I mentioned. The results so far aren't promising.

Here's a screenshot of the latest version:

Screenshot of the current newsletter

(It’s a bit worrying that the Small Print takes up so much of the newsletter…)

Some stuff I'd like to put on the newsletter just isn't online. Local events like schools or churches having jumble sales or something. They're handled by leaflets to parents or the congregation, but they're rarely posted online.

Other stuff I'd like to put in is available online, but not in a format that can be automatically processed. (This normally means XML or JSON - I'm not going to do any screen-scraping because if they haven't deliberately chosen to syndicate their content I'm not going to use it.) Things that aren't available in a syndication format include Carrickfergus Borough Council's blog/news feed (seriously) or the several sources for "What's On" events.

Some stuff is sortof-online, like Carrickfergus Times' feed of events. Some events are indeed here, in XML, but there's no easy way to derive the date of the event. Sometimes it's there in the title as 'May 10', other times it's explained to be 'May Day Bank Holiday', other times it's not mentioned at all.

One feed that actually got the date concept right was the Parades Commission feed. I'm not even going to try and explain the reason we have a Parades Commission in the first place, but the feed used a separate <dc:date> tag to show the date of the event. Nice! Except the feed is now just returning a 404 after some site changes. So the one nice, useful event feed has disappeared.

Other stuff that's sortof-online is local planning applications that are up for approval or whatever happens with such things. They're online, but there's no fixed URL for them, and anyway they're only available as PDFs...

Then there's the stuff that is available online, and is in a suitable syndication format, but some utter fuckwit intervenes and makes it impossible to process. I'm still annoyed at the way the police make crime data available - there's no actual link you can go to to download the latest data, or download any particular data set. You have to go to a web page and click to generate the data set which then gives you a new, unique URL for the data set. You can't do this automatically, it all needs to be done through a web browser.

Then there's the bad XML which makes the whole file un-parseable. I may take a look at the parser I'm calling to see if I can make it more tolerant, but is XML-encoding < and > so hard?

Finally there's the data that's online, in a syndication format that I'm not allowed to use. I'm doing this as part of my company, so this is (potentially) a commercial venture. Some sites (like the Met Office) say their feeds are for personal use only. Some (like Google News) say if you want to use them for commercial purposes you should contact them - but then neglect to provide any actual way of contacting them!

Only a few things have been straightforward. OpenWeatherMap was nice to call, and available to use, but the weather forecasts for Carrickfergus just didn't seem to match the actual weather at all, so I'm trying Weather Underground and it seems nice (they do mandate the look of the credit notice, which may start to get ugly quickly if a few more start mandating different looks).



Posted by 'geoff' on Monday, 05 May 2014. No comments.


I was playing a bit with Scheme lately, but then I stopped for a break. I was in the middle of writing a Sudoku Solver and I figured I should put the code up here, partly in case anyone is interested, and partly so I remember to get back to it.

The plan is to create a solver that works in a reasonable time, but to keep the algorithms as simple (and dumb) as possible. (I may try to make it smarter once it’s done, but that’s not a goal right now.)

At the minute the code has a basic understanding of what a sudoku is and how to iterate over it, and how to iterate over all the peers of a cell. That’s it. There’s no actual solving in here yet. One bit that was interesting (to me at least) is the unit test code – the define-testsuite had to be a macro/syntax because of the way it monkeys with the flow of control.

Here’s the code:

(define *grid-rows* '(0 1 2 3 4 5 6 7 8))
(define *grid-columns* '(0 1 2 3 4 5 6 7 8))
(define *all-tests* (list))


;;;; Some 'easy' sudokus are here: http://norvig.com/easy50.txt
(define *grid*
  #(
    #(0 0 3 0 2 0 6 0 0)
    #(9 0 0 3 0 5 0 0 1)
    #(0 0 1 8 0 6 4 0 0)
    #(0 0 8 1 0 2 9 0 0)
    #(7 0 0 0 0 0 0 0 8)
    #(0 0 6 7 0 8 2 0 0)
    #(0 0 2 6 0 9 5 0 0)
    #(8 0 0 2 0 3 0 0 9)
    #(0 0 5 0 1 0 3 0 0)
    )
  )

;;;; A simple foreach loop. Use it like:
;;;;(for-each value in: '(1 2 3)
;;;;          do:
;;;;          (display value)
;;;;          (newline))
(define-syntax for-each
  (syntax-rules (in: do:)
    ((_ current in values-list do body ...)
     (map (lambda (param)
            (let ((current param)) (begin body ...)))
          values-list))))

(define item-accessor (lambda (grid row column) (vector-ref (vector-ref grid row) column)))

(define outer-inner-list-creator (lambda (all-outer-items all-inner-items)
                                   (let outer-loop ((outer-items all-outer-items))
                                     (cond
                                      ((null? outer-items) '())
                                      (else
                                       (append
                                        (let inner-loop ((inner-items all-inner-items))
                                          (cond
                                           ((null? inner-items) '())
                                           (else
                                            (cons
                                             (cons (car outer-items)
                                                   (cons (car inner-items) '()))
                                             (inner-loop (cdr inner-items))))))
                                        (outer-loop (cdr outer-items))))))))

(define print-grid (lambda (grid)
                        (print-grid-item grid (outer-inner-list-creator *grid-rows* *grid-columns*))))

(define print-grid-item (lambda (grid indices)
                            (if (null? indices)
                                #t
                                (let ((row (caar indices)) (column (cadar indices)))
                                  (if (and (> row 0) (= 0 (remainder row 3)) (= 0 column))
                                      (print-line "---------------------")
                                      #t)
                                  (if (and (> column 0) (= 0 (remainder column 3)))
                                      (print-all "| ")
                                      #t)
                                  (print-all (item-accessor grid row column) " ")
                                  (if (= 8 column)
                                      (print-line)
                                      #t)
                                  (print-grid-item grid (cdr indices))))))

(define row-except-current (lambda (grid row column current)
                             (cond
                              ((eq? column 9) '())
                              ((eq? column current) (row-except-current grid row (+ column 1) current))
                              (else (cons (item-accessor grid row column)
                                          (row-except-current grid row (+ column 1) current))))))

(define column-except-current (lambda (grid row column current)
                                (cond
                                 ((eq? row 9) '())
                                 ((eq? row current) (column-except-current grid (+ row 1) column current))
                                 (else (cons (item-accessor grid row column)
                                             (column-except-current grid (+ row 1) column current))))))

(define unit-triple-for-index (lambda (index)
                                (let ((offset (* 3 (quotient index 3))))
                                  (list (+ 0 offset) (+ 1 offset) (+ 2 offset)))))

(define unit-except-current (lambda (grid current-row current-column)
                              (let row-loop ((row-indices (unit-triple-for-index current-row)))
                                (if (null? row-indices)
                                    '()
                                    (append
                                     (let ((row-index (car row-indices)))
                                       (let column-loop ((column-indices (unit-triple-for-index current-column)))
                                         (if (null? column-indices)
                                             '()
                                             (let ((column-index (car column-indices)))
                                               (if (and (eq? row-index current-row) (eq? column-index current-column))
                                                   (column-loop (cdr column-indices))
                                                   (cons (item-accessor grid row-index column-index)
                                                     (column-loop (cdr column-indices))))))))
                                     (row-loop (cdr row-indices)))))))

(define all-peers (lambda (grid current-row current-column)
                    (append (row-except-current grid current-row 0 current-column)
                            (column-except-current grid 0 current-column current-row)
                            (unit-except-current grid current-row current-column))))

(define is-valid-cell (lambda (grid row column)
                        (let ((current-cell-value (item-accessor grid row column)) (peers (all-peers grid row column)))
                          ;(print-line "Cell [" row ", " column "]: " current-cell-value " - " (is-not-in-list? current-cell-value (all-peers grid row column)))
                          (is-not-in-list? current-cell-value (all-peers grid row column)))))

(define is-not-in-list? (lambda (item list)
                          (if (null? list)
                              #t
                              (and (not (eq? item (car list))) (is-not-in-list? item (cdr list))))))

(define assert-each-cell (lambda (grid run-on-item)
                           (assert-each-cell-item grid run-on-item (outer-inner-list-creator *grid-rows* *grid-columns*))))

(define assert-each-cell-item (lambda (grid run-on-item indices)
                                (if (null? indices)
                                    #t
                                    (and (run-on-item grid (caar indices) (cadar indices))
                                     (assert-each-cell-item grid run-on-item (cdr indices))))))

(define is-valid-sudoku (lambda (grid)
                          (and
                           (assert-each-cell grid assert-not-unset)
                           (assert-each-cell grid is-valid-cell))))

(define assert-not-unset (lambda (grid row column)
                           (not (= 0 (item-accessor grid row column)))))

(define print-all (lambda args
                    (let loop ((to-print args))
                      (cond
                       ((null? to-print) #t)
                       (else
                        (display (car to-print))
                        (loop (cdr to-print)))))))

(define print-line (lambda args
                     (cond
                      ((null? args) #t)
                      ((and (pair? args) (null? (cdr args))) (print-all (car args)))
                      (else (print-all args)))
                     (newline)))

(define-syntax syntax-error
  (syntax-rules ()
    ((syntax-error) (syntax-error "Error: Bad syntax."))))

(define remove-test-member (lambda (name list)
                             (cond
                              ((null? list) '())
                              ((equal? name (caar list)) (cdr list))
                              (else (cons (car list) (remove-test-member name (cdr list)))))))

(define ensure-test-member (lambda (test-pair)
                             (set! *all-tests* (cons test-pair (remove-test-member (car test-pair) *all-tests*)))))

(define-syntax define-testsuite
  (syntax-rules (data: tests:)
    ((_ ()) (syntax-error "No name specified for test suite."))

    ((_ name data: let-data tests: test* ...)
     (ensure-test-member `(name ,(lambda ()
                                   (print-all 'name ": ")
                                   (let let-data
                                       (run-test test*) ...)
                                   (print-line)))))

    ((_ name tests: test* ...)
     (ensure-test-member `(name ,(lambda ()
                                   (print-all 'name ": ")
                                   (run-test test*) ...
                                   (print-line)))))

    ((_ name test* ...)
     (define-testsuite name tests: test* ...))

    ((_ non-list) (syntax-error "Not a list."))))

(define-syntax run-test
  (syntax-rules ()
    ((_ test)
     (let ((evaluated test))
       (if evaluated
           (begin
             (print-all ".")
             #t)
           (begin
             (print-all "\nFailed - value: " 'test " evaluated to: " evaluated "\n")
             #f))))))

(define run-all-tests (lambda ()
                        (let loop ((tests *all-tests*))
                          (if (null? tests)
                              #t
                              (begin
                                ((cadar tests))
                                (loop (cdr tests)))))))

(define run-testsuite (lambda (testsuite-name)
                        (let loop ((tests *all-tests*))
                          (cond
                           ((null? tests) (print-all "Error - test suite " testsuite-name " not found"))
                           ((equal? testsuite-name (caar tests)) ((cadar tests)))
                           (else (loop (cdr tests)))))))

(define-testsuite unit-triple-for-index-tests
  (equal? '(0 1 2) (unit-triple-for-index 0))
  (equal? '(0 1 2) (unit-triple-for-index 1))
  (equal? '(0 1 2) (unit-triple-for-index 2))
  (equal? '(3 4 5) (unit-triple-for-index 3))
  (equal? '(3 4 5) (unit-triple-for-index 4))
  (equal? '(3 4 5) (unit-triple-for-index 5))
  (equal? '(6 7 8) (unit-triple-for-index 6))
  (equal? '(6 7 8) (unit-triple-for-index 7))
  (equal? '(6 7 8) (unit-triple-for-index 8)))

(define-testsuite is-not-in-list-tests
  (is-not-in-list? 'a '(x y z))
  (is-not-in-list? 0 '())
  (is-not-in-list? 7 '(9 0 3 0 5 0 0 1 0 0 0 0 0 0 0 0 0 0 3 9 0 0 0 1))
  (not (is-not-in-list? 0 '(9 0 3 0 5 0 0 1 0 0 0 0 0 0 0 0 0 0 3 9 0 0 0 1))))

(define-testsuite row-except-current-tests
  data:
  ((test-grid #(
                #(1 2 3 4 5 6 7 8 9)
                #(2 2 2 2 2 2 2 2 2)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0))))
  tests:
  (equal? '(2 3 4 5 6 7 8 9) (row-except-current test-grid 0 0 0))
  (equal? '(1 3 4 5 6 7 8 9) (row-except-current test-grid 0 0 1))
  (equal? '(1 2 4 5 6 7 8 9) (row-except-current test-grid 0 0 2))
  (equal? '(1 2 3 5 6 7 8 9) (row-except-current test-grid 0 0 3))
  (equal? '(1 2 3 4 6 7 8 9) (row-except-current test-grid 0 0 4))
  (equal? '(1 2 3 4 5 7 8 9) (row-except-current test-grid 0 0 5))
  (equal? '(1 2 3 4 5 6 8 9) (row-except-current test-grid 0 0 6))
  (equal? '(1 2 3 4 5 6 7 9) (row-except-current test-grid 0 0 7))
  (equal? '(1 2 3 4 5 6 7 8) (row-except-current test-grid 0 0 8))
  (equal? '(2 2 2 2 2 2 2 2) (row-except-current test-grid 1 0 0)))

(define-testsuite column-except-current-tests
  data:
  ((test-grid #(
                #(1 3 0 0 0 0 0 0 0)
                #(2 3 0 0 0 0 0 0 0)
                #(3 3 0 0 0 0 0 0 0)
                #(4 3 0 0 0 0 0 0 0)
                #(5 3 0 0 0 0 0 0 0)
                #(6 3 0 0 0 0 0 0 0)
                #(7 3 0 0 0 0 0 0 0)
                #(8 3 0 0 0 0 0 0 0)
                #(9 3 0 0 0 0 0 0 0))))
  tests:
  (equal? '(2 3 4 5 6 7 8 9) (column-except-current test-grid 0 0 0))
  (equal? '(1 3 4 5 6 7 8 9) (column-except-current test-grid 0 0 1))
  (equal? '(1 2 4 5 6 7 8 9) (column-except-current test-grid 0 0 2))
  (equal? '(1 2 3 5 6 7 8 9) (column-except-current test-grid 0 0 3))
  (equal? '(1 2 3 4 6 7 8 9) (column-except-current test-grid 0 0 4))
  (equal? '(1 2 3 4 5 7 8 9) (column-except-current test-grid 0 0 5))
  (equal? '(1 2 3 4 5 6 8 9) (column-except-current test-grid 0 0 6))
  (equal? '(1 2 3 4 5 6 7 9) (column-except-current test-grid 0 0 7))
  (equal? '(1 2 3 4 5 6 7 8) (column-except-current test-grid 0 0 8))
  (equal? '(3 3 3 3 3 3 3 3) (column-except-current test-grid 0 1 0)))

(define-testsuite unit-except-current-tests
  data:
  ((test-grid #(
                #(1 2 3 4 4 4 0 0 0)
                #(4 5 6 4 4 4 0 0 0)
                #(7 8 9 4 4 4 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0)
                #(0 0 0 0 0 0 0 0 0))))
  tests:
  (equal? '(2 3 4 5 6 7 8 9) (unit-except-current test-grid 0 0))
  (equal? '(1 3 4 5 6 7 8 9) (unit-except-current test-grid 0 1))
  (equal? '(1 2 4 5 6 7 8 9) (unit-except-current test-grid 0 2))
  (equal? '(1 2 3 5 6 7 8 9) (unit-except-current test-grid 1 0))
  (equal? '(1 2 3 4 6 7 8 9) (unit-except-current test-grid 1 1))
  (equal? '(1 2 3 4 5 7 8 9) (unit-except-current test-grid 1 2))
  (equal? '(1 2 3 4 5 6 8 9) (unit-except-current test-grid 2 0))
  (equal? '(1 2 3 4 5 6 7 9) (unit-except-current test-grid 2 1))
  (equal? '(1 2 3 4 5 6 7 8) (unit-except-current test-grid 2 2))
  (equal? '(4 4 4 4 4 4 4 4) (unit-except-current test-grid 0 3)))

(define-testsuite is-valid-sudoku-tests
  data:
  ((test-grid1 #(
                 #(0 0 3 0 2 0 6 0 0)
                 #(9 0 0 3 0 5 0 0 1)
                 #(0 0 1 8 0 6 4 0 0)
                 #(0 0 8 1 0 2 9 0 0)
                 #(7 0 0 0 0 0 0 0 8)
                 #(0 0 6 7 0 8 2 0 0)
                 #(0 0 2 6 0 9 5 0 0)
                 #(8 0 0 2 0 3 0 0 9)
                 #(0 0 5 0 1 0 3 0 0)))
   (test-grid2 #(
                 #(4 8 3 9 2 1 6 5 7)
                 #(9 6 7 3 4 5 8 2 1)
                 #(2 5 1 8 7 6 4 9 3)
                 #(5 4 8 1 3 2 9 7 6)
                 #(7 2 9 5 6 4 1 3 8)
                 #(1 3 6 7 9 8 2 4 5)
                 #(3 7 2 6 8 9 5 1 4)
                 #(8 1 4 2 5 3 7 6 9)
                 #(6 9 5 4 1 7 3 8 2)))
   (test-grid3 #(
                 #(4 8 3 9 2 1 6 5 7)
                 #(9 6 7 3 4 5 8 2 1)
                 #(2 5 1 8 7 6 4 9 3)
                 #(5 4 8 1 3 2 9 7 6)
                 #(7 2 9 5 6 4 1 3 8)
                 #(1 3 6 7 9 8 2 4 5)
                 #(3 7 2 6 8 9 5 1 4)
                 #(8 1 4 2 5 3 7 6 9)
                 #(6 9 5 4 1 7 3 2 2))))
  tests:
  (equal? #f (is-valid-sudoku test-grid1))
  (equal? #t (is-valid-sudoku test-grid2))
  (equal? #f (is-valid-sudoku test-grid3)))



Posted by 'geoff' on Sunday, 21 July 2013. No comments.


RSS 2.0 Subscribe to the RSS 2.0 feed for Geoff's Blog.