grid size now properly stored as part of grid. Lots of things need refactoring for speed.

This commit is contained in:
Nico 2022-04-05 11:14:06 +01:00
parent e84ee87d72
commit a9a34af605
2 changed files with 61 additions and 54 deletions

View File

@ -15,6 +15,12 @@
(line (point 4 3) (point 4 4) 0)
(line (point 3 4) (point 4 4) 0)) 6 6))
(test-case
"total-moves"
(check-equal? (total-moves (grid '() 2 2)) 4)
(check-equal? (total-moves (grid '() 4 5)) 31)
(check-equal? (total-moves (grid '() 2 6)) 16))
(test-case
"same-position?"
(check-true (same-position? (line (point 0 0) (point 0 1) 1)
@ -34,22 +40,14 @@
(check-false (valid-length? (line (point 0 0) (point 0 2) 1)))
(check-false (valid-length? (line (point 0 0) (point 0 2) 1))))
(test-case
"out-of-bounds?"
(check-false (out-of-bounds? (point 0 0)))
(check-false (out-of-bounds? (point 0 (- GRID-WIDTH 1))))
(check-true (out-of-bounds? (point GRID-WIDTH 0)))
(check-true (out-of-bounds? (point -2 0)))
(check-true (out-of-bounds? (point 0 -2))))
(test-case
"boxes-for"
(check-equal? (boxes-for (line (point 0 0) (point 0 1) 1)) (list (point 0 0)))
(check-equal? (boxes-for (line (point 2 1) (point 2 2) 1)) (list (point 2 1) (point 1 1)))
(check-equal? (boxes-for (line (point 0 0) (point 1 0) 1)) (list (point 0 0)))
(check-equal? (boxes-for (line (point 1 1) (point 2 1) 1)) (list (point 1 1) (point 1 0)))
(check-equal? (boxes-for (line (point 0 5) (point 1 5) 1)) (list (point 0 4)))
(check-equal? (boxes-for (line (point 5 0) (point 5 1) 0)) (list (point 4 0))))
(check-equal? (boxes-for (line (point 0 0) (point 0 1) 1) test-grid) (list (point 0 0)))
(check-equal? (boxes-for (line (point 2 1) (point 2 2) 1) test-grid) (list (point 2 1) (point 1 1)))
(check-equal? (boxes-for (line (point 0 0) (point 1 0) 1) test-grid) (list (point 0 0)))
(check-equal? (boxes-for (line (point 1 1) (point 2 1) 1) test-grid) (list (point 1 1) (point 1 0)))
(check-equal? (boxes-for (line (point 0 5) (point 1 5) 1) test-grid) (list (point 0 4)))
(check-equal? (boxes-for (line (point 5 0) (point 5 1) 0) test-grid) (list (point 4 0))))
(test-case
"completes-boxes"
@ -95,11 +93,11 @@
(test-case
"out-of-bounds?"
(check-false (out-of-bounds? (point 0 0)))
(check-false (out-of-bounds? (point 0 (- GRID-WIDTH 1))))
(check-true (out-of-bounds? (point GRID-WIDTH 0)))
(check-true (out-of-bounds? (point -2 0)))
(check-true (out-of-bounds? (point 0 -2))))
(check-false (out-of-bounds? (point 0 0) test-grid))
(check-false (out-of-bounds? (point 0 (- (grid-width test-grid) 1)) test-grid))
(check-true (out-of-bounds? (point (grid-width test-grid) 0) test-grid))
(check-true (out-of-bounds? (point -2 0) test-grid))
(check-true (out-of-bounds? (point 0 -2) test-grid)))
(test-case
"forwards?"

View File

@ -28,31 +28,29 @@
; name is the player's name.
(struct player (name func) #:transparent)
; width and height of the playing grid.
(define GRID-WIDTH 6)
(define GRID-HEIGHT 6)
; size of one grid position in pixels
(define GRID-SCALE 16)
; Number Number -> Image
; image representing the empty grid
(define EMPTY-GRID
(let* ([bitmap (make-bitmap (* GRID-WIDTH GRID-SCALE) (* GRID-HEIGHT GRID-SCALE))]
(define (grid-dots w h)
(let* ([bitmap (make-bitmap (* w GRID-SCALE) (* h GRID-SCALE))]
[dc (new bitmap-dc% [bitmap bitmap])])
(send dc set-brush "black" 'solid)
(for ([x (in-range GRID-WIDTH)])
(for ([y (in-range GRID-HEIGHT)])
(for ([x (in-range w)])
(for ([y (in-range h)])
(send dc draw-ellipse (* x GRID-SCALE) (* y GRID-SCALE) (/ GRID-SCALE 2) (/ GRID-SCALE 2))))
bitmap))
; Grid that contains all possible lines filled. Used for filtering valid moves. This is an ugly way, but i can't think of a better one right now.
(define FULL-GRID (grid
; Width Height -> Grid
; Generates a grid that contains all possible lines filled. Used for filtering valid moves. This is an ugly way, but i can't think of a better one right now.
(define (full-grid w h) (grid
(flatten
(for/list ([x (in-range GRID-WIDTH)])
(for/list ([y (in-range GRID-HEIGHT)])
(for/list ([x (in-range w)])
(for/list ([y (in-range h)])
(list
(if (< x (- GRID-WIDTH 1)) (line (point x y) (point (+ x 1) y) 1) '())
(if (< y (- GRID-HEIGHT 1)) (line (point x y) (point x (+ y 1)) 1) '()))))) GRID-WIDTH GRID-HEIGHT))
(if (< x (- w 1)) (line (point x y) (point (+ x 1) y) 1) '())
(if (< y (- h 1)) (line (point x y) (point x (+ y 1)) 1) '()))))) w h))
; Line Line -> Bool
; tests if two lines are in the same position
@ -75,7 +73,7 @@
; TODO optimise. This "filtering what is invalid out of all possible lines" method sucks.
; TODO write more tests
(define (valid-moves g)
(filter (lambda (move) (valid-move? move g)) (grid-lines FULL-GRID)))
(filter (lambda (move) (valid-move? move g)) (grid-lines (full-grid (grid-width g) (grid-height g)))))
; Point Grid -> Number
; given a point that is the top-left corner of a square on the grid, returns the amount of edges surrounding that square.
@ -104,14 +102,14 @@
(+ (abs (- (point-x (line-from line)) (point-x (line-to line))))
(abs (- (point-y (line-from line)) (point-y (line-to line)))))))
; Point -> Bool
; Point Grid -> Bool
; returns #t if a point is out of bounds (off the edge of the grid)
(define (out-of-bounds? p)
(define (out-of-bounds? p g)
(or
(> 0 (point-x p))
(> 0 (point-y p))
(< (- GRID-WIDTH 1) (point-x p))
(< (- GRID-WIDTH 1) (point-y p))))
(< (- (grid-width g) 1) (point-x p))
(< (- (grid-height g) 1) (point-y p))))
; Line Grid -> Bool
; returns #t if adding the given move to the grid is valid.
@ -121,8 +119,8 @@
(valid-length? line)
(forwards? line)
(and
(not (out-of-bounds? (line-from line)))
(not (out-of-bounds? (line-to line))))))
(not (out-of-bounds? (line-from line) grid))
(not (out-of-bounds? (line-to line) grid)))))
; a Player that plays random moves
(define random-player
@ -137,15 +135,15 @@
(define (append-move g l)
(if (valid-move? l g) (grid (append (grid-lines g) (list l)) (grid-width g) (grid-height g)) g))
; Line -> List of Points
; Line Grid -> List of Points
; returns the positions of boxes the given line affects, assuming a valid line.
; TODO this is messy as fuck, especially with that (filter). Racket must have some way to do this more nicely.
(define (boxes-for line)
(define (boxes-for line g)
(filter (lambda (x) (not (eq? x 0)))
(list
(if (and
(not (= (- GRID-WIDTH 1) (point-x (line-from line))))
(not (= (- GRID-HEIGHT 1) (point-y (line-from line))))) (line-from line) 0)
(not (= (- (grid-width g) 1) (point-x (line-from line))))
(not (= (- (grid-height g) 1) (point-y (line-from line))))) (line-from line) 0)
(if (and
(< (point-x (line-from line)) (point-x (line-to line))) ; horizontal line
(> (point-y (line-from line)) 0))
@ -157,12 +155,23 @@
; Grid Line -> bool or Number
; returns the number of boxes this completes
(define (completes-boxes grid l)
(define (completes-boxes gr l)
(let
([boxes (boxes-for l)]
[g (append-move grid l)])
([boxes (boxes-for l gr)]
[g (append-move gr l)])
(length (filter (lambda (b) (= (count-square b g) 4)) boxes))))
; Grid -> Number
; returns the total amount of moves possible for grid g.
; formula determined using a pen and paper to be:
; (width * (height-1) + (height * (width - 1))
(define (total-moves g)
(let ([w (grid-width g)]
[h (grid-height g)])
(+
(* w (- h 1))
(* h (- w 1)))))
; GameState -> GameState
; runs the game.
; If the game is over, returns the final game state
@ -171,7 +180,7 @@
(let ([g (GameState-grid s)]
[p (GameState-player s)])
(cond
[(= (length (grid-lines g)) (length (grid-lines FULL-GRID))) s] ; end of the game
[(= (length (grid-lines g)) (total-moves g)) s] ; end of the game when every possible line is played
[else
(let* ([move ((player-func (list-ref (GameState-players s) p)) g p)]
[new-grid (append-move g move)]
@ -185,10 +194,10 @@
; Grid -> Image
; renders grid to an image for showing humans the game.
(define (render-grid-bitmap grid)
(let* ([bitmap (make-bitmap (+ 10 (* GRID-WIDTH GRID-SCALE)) (+ 10 (* GRID-HEIGHT GRID-SCALE)))] ; add border for printing
(define (render-grid-bitmap g)
(let* ([bitmap (make-bitmap (+ 10 (* (grid-width g) GRID-SCALE) (+ 10 (* (grid-width g) GRID-SCALE))))] ; add border for printing
[dc (new bitmap-dc% [bitmap bitmap])])
(render-grid grid dc)
(render-grid g dc)
bitmap))
; Grid dc !
@ -207,7 +216,7 @@
(+ 4 (* GRID-SCALE (point-y (line-from l))))
(+ 4 (* GRID-SCALE (point-x (line-to l))))
(+ 4 (* GRID-SCALE (point-y (line-to l))))) ; draw the line
(let ([boxes (boxes-for l)])
(let ([boxes (boxes-for l g)])
(for ([b boxes])
(if (= (count-square b (grid passed (grid-width g) (grid-height g))) 4)
(send dc draw-text
@ -215,5 +224,5 @@
(+ 6 (* GRID-SCALE (point-x b)))
(+ 3 (* GRID-SCALE (point-y b))))
0))))
(send dc draw-bitmap EMPTY-GRID 0 0)) ; overlay dot grid
(send dc draw-bitmap (grid-dots (grid-width g) (grid-height g)) 0 0)) ; overlay dot grid