]> gitweb.factorcode.org Git - factor.git/commitdiff
minesweeper: adding a fun minesweeper game.
authorJohn Benediktsson <mrjbq7@gmail.com>
Sat, 10 Feb 2018 01:27:04 +0000 (17:27 -0800)
committerJohn Benediktsson <mrjbq7@gmail.com>
Sat, 10 Feb 2018 01:27:04 +0000 (17:27 -0800)
35 files changed:
extra/minesweeper/_resources/blank.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit-.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit0.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit1.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit2.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit3.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit4.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit5.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit6.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit7.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit8.gif [new file with mode: 0644]
extra/minesweeper/_resources/digit9.gif [new file with mode: 0644]
extra/minesweeper/_resources/flagged.gif [new file with mode: 0644]
extra/minesweeper/_resources/mine.gif [new file with mode: 0644]
extra/minesweeper/_resources/mineclicked.gif [new file with mode: 0644]
extra/minesweeper/_resources/misflagged.gif [new file with mode: 0644]
extra/minesweeper/_resources/open0.gif [new file with mode: 0644]
extra/minesweeper/_resources/open1.gif [new file with mode: 0644]
extra/minesweeper/_resources/open2.gif [new file with mode: 0644]
extra/minesweeper/_resources/open3.gif [new file with mode: 0644]
extra/minesweeper/_resources/open4.gif [new file with mode: 0644]
extra/minesweeper/_resources/open5.gif [new file with mode: 0644]
extra/minesweeper/_resources/open6.gif [new file with mode: 0644]
extra/minesweeper/_resources/open7.gif [new file with mode: 0644]
extra/minesweeper/_resources/open8.gif [new file with mode: 0644]
extra/minesweeper/_resources/question.gif [new file with mode: 0644]
extra/minesweeper/_resources/smiley.gif [new file with mode: 0644]
extra/minesweeper/_resources/smileylost.gif [new file with mode: 0644]
extra/minesweeper/_resources/smileyuhoh.gif [new file with mode: 0644]
extra/minesweeper/_resources/smileywon.gif [new file with mode: 0644]
extra/minesweeper/authors.txt [new file with mode: 0644]
extra/minesweeper/minesweeper.factor [new file with mode: 0644]
extra/minesweeper/resources.txt [new file with mode: 0644]
extra/minesweeper/summary.txt [new file with mode: 0644]
extra/minesweeper/tags.txt [new file with mode: 0644]

diff --git a/extra/minesweeper/_resources/blank.gif b/extra/minesweeper/_resources/blank.gif
new file mode 100644 (file)
index 0000000..5c50d90
Binary files /dev/null and b/extra/minesweeper/_resources/blank.gif differ
diff --git a/extra/minesweeper/_resources/digit-.gif b/extra/minesweeper/_resources/digit-.gif
new file mode 100644 (file)
index 0000000..025cd8a
Binary files /dev/null and b/extra/minesweeper/_resources/digit-.gif differ
diff --git a/extra/minesweeper/_resources/digit0.gif b/extra/minesweeper/_resources/digit0.gif
new file mode 100644 (file)
index 0000000..304bc14
Binary files /dev/null and b/extra/minesweeper/_resources/digit0.gif differ
diff --git a/extra/minesweeper/_resources/digit1.gif b/extra/minesweeper/_resources/digit1.gif
new file mode 100644 (file)
index 0000000..fdbdb9f
Binary files /dev/null and b/extra/minesweeper/_resources/digit1.gif differ
diff --git a/extra/minesweeper/_resources/digit2.gif b/extra/minesweeper/_resources/digit2.gif
new file mode 100644 (file)
index 0000000..f3e1b89
Binary files /dev/null and b/extra/minesweeper/_resources/digit2.gif differ
diff --git a/extra/minesweeper/_resources/digit3.gif b/extra/minesweeper/_resources/digit3.gif
new file mode 100644 (file)
index 0000000..5a79680
Binary files /dev/null and b/extra/minesweeper/_resources/digit3.gif differ
diff --git a/extra/minesweeper/_resources/digit4.gif b/extra/minesweeper/_resources/digit4.gif
new file mode 100644 (file)
index 0000000..d379d63
Binary files /dev/null and b/extra/minesweeper/_resources/digit4.gif differ
diff --git a/extra/minesweeper/_resources/digit5.gif b/extra/minesweeper/_resources/digit5.gif
new file mode 100644 (file)
index 0000000..589a1a1
Binary files /dev/null and b/extra/minesweeper/_resources/digit5.gif differ
diff --git a/extra/minesweeper/_resources/digit6.gif b/extra/minesweeper/_resources/digit6.gif
new file mode 100644 (file)
index 0000000..232f606
Binary files /dev/null and b/extra/minesweeper/_resources/digit6.gif differ
diff --git a/extra/minesweeper/_resources/digit7.gif b/extra/minesweeper/_resources/digit7.gif
new file mode 100644 (file)
index 0000000..56ab859
Binary files /dev/null and b/extra/minesweeper/_resources/digit7.gif differ
diff --git a/extra/minesweeper/_resources/digit8.gif b/extra/minesweeper/_resources/digit8.gif
new file mode 100644 (file)
index 0000000..aca981f
Binary files /dev/null and b/extra/minesweeper/_resources/digit8.gif differ
diff --git a/extra/minesweeper/_resources/digit9.gif b/extra/minesweeper/_resources/digit9.gif
new file mode 100644 (file)
index 0000000..f4ee44e
Binary files /dev/null and b/extra/minesweeper/_resources/digit9.gif differ
diff --git a/extra/minesweeper/_resources/flagged.gif b/extra/minesweeper/_resources/flagged.gif
new file mode 100644 (file)
index 0000000..46dc1b2
Binary files /dev/null and b/extra/minesweeper/_resources/flagged.gif differ
diff --git a/extra/minesweeper/_resources/mine.gif b/extra/minesweeper/_resources/mine.gif
new file mode 100644 (file)
index 0000000..f7b12c2
Binary files /dev/null and b/extra/minesweeper/_resources/mine.gif differ
diff --git a/extra/minesweeper/_resources/mineclicked.gif b/extra/minesweeper/_resources/mineclicked.gif
new file mode 100644 (file)
index 0000000..f7416c9
Binary files /dev/null and b/extra/minesweeper/_resources/mineclicked.gif differ
diff --git a/extra/minesweeper/_resources/misflagged.gif b/extra/minesweeper/_resources/misflagged.gif
new file mode 100644 (file)
index 0000000..cbbb32c
Binary files /dev/null and b/extra/minesweeper/_resources/misflagged.gif differ
diff --git a/extra/minesweeper/_resources/open0.gif b/extra/minesweeper/_resources/open0.gif
new file mode 100644 (file)
index 0000000..1ae6d3a
Binary files /dev/null and b/extra/minesweeper/_resources/open0.gif differ
diff --git a/extra/minesweeper/_resources/open1.gif b/extra/minesweeper/_resources/open1.gif
new file mode 100644 (file)
index 0000000..4c6b2bd
Binary files /dev/null and b/extra/minesweeper/_resources/open1.gif differ
diff --git a/extra/minesweeper/_resources/open2.gif b/extra/minesweeper/_resources/open2.gif
new file mode 100644 (file)
index 0000000..465aa36
Binary files /dev/null and b/extra/minesweeper/_resources/open2.gif differ
diff --git a/extra/minesweeper/_resources/open3.gif b/extra/minesweeper/_resources/open3.gif
new file mode 100644 (file)
index 0000000..58d96b5
Binary files /dev/null and b/extra/minesweeper/_resources/open3.gif differ
diff --git a/extra/minesweeper/_resources/open4.gif b/extra/minesweeper/_resources/open4.gif
new file mode 100644 (file)
index 0000000..ae123dc
Binary files /dev/null and b/extra/minesweeper/_resources/open4.gif differ
diff --git a/extra/minesweeper/_resources/open5.gif b/extra/minesweeper/_resources/open5.gif
new file mode 100644 (file)
index 0000000..e938967
Binary files /dev/null and b/extra/minesweeper/_resources/open5.gif differ
diff --git a/extra/minesweeper/_resources/open6.gif b/extra/minesweeper/_resources/open6.gif
new file mode 100644 (file)
index 0000000..8f79b0d
Binary files /dev/null and b/extra/minesweeper/_resources/open6.gif differ
diff --git a/extra/minesweeper/_resources/open7.gif b/extra/minesweeper/_resources/open7.gif
new file mode 100644 (file)
index 0000000..5618e64
Binary files /dev/null and b/extra/minesweeper/_resources/open7.gif differ
diff --git a/extra/minesweeper/_resources/open8.gif b/extra/minesweeper/_resources/open8.gif
new file mode 100644 (file)
index 0000000..59c777f
Binary files /dev/null and b/extra/minesweeper/_resources/open8.gif differ
diff --git a/extra/minesweeper/_resources/question.gif b/extra/minesweeper/_resources/question.gif
new file mode 100644 (file)
index 0000000..ccc79bb
Binary files /dev/null and b/extra/minesweeper/_resources/question.gif differ
diff --git a/extra/minesweeper/_resources/smiley.gif b/extra/minesweeper/_resources/smiley.gif
new file mode 100644 (file)
index 0000000..11b8045
Binary files /dev/null and b/extra/minesweeper/_resources/smiley.gif differ
diff --git a/extra/minesweeper/_resources/smileylost.gif b/extra/minesweeper/_resources/smileylost.gif
new file mode 100644 (file)
index 0000000..53ecfae
Binary files /dev/null and b/extra/minesweeper/_resources/smileylost.gif differ
diff --git a/extra/minesweeper/_resources/smileyuhoh.gif b/extra/minesweeper/_resources/smileyuhoh.gif
new file mode 100644 (file)
index 0000000..06ab226
Binary files /dev/null and b/extra/minesweeper/_resources/smileyuhoh.gif differ
diff --git a/extra/minesweeper/_resources/smileywon.gif b/extra/minesweeper/_resources/smileywon.gif
new file mode 100644 (file)
index 0000000..738575d
Binary files /dev/null and b/extra/minesweeper/_resources/smileywon.gif differ
diff --git a/extra/minesweeper/authors.txt b/extra/minesweeper/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/extra/minesweeper/minesweeper.factor b/extra/minesweeper/minesweeper.factor
new file mode 100644 (file)
index 0000000..c44df91
--- /dev/null
@@ -0,0 +1,299 @@
+! Copyright (C) 2017 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: accessors arrays assocs calendar colors.constants
+combinators combinators.short-circuit destructors formatting fry
+images.loader kernel locals math math.order math.parser
+namespaces opengl opengl.textures random sequences timers ui
+ui.commands ui.gadgets ui.gadgets.toolbar ui.gadgets.tracks
+ui.gadgets.worlds ui.gestures ui.pens.solid ui.render words ;
+
+IN: minesweeper
+
+CONSTANT: neighbors {
+    { -1 -1 } { -1  0 } { -1  1 }
+    {  0 -1 }           {  0  1 }
+    {  1 -1 } {  1  0 } {  1  1 }
+}
+
+SYMBOLS: +flagged+ +question+ +clicked+ ;
+
+TUPLE: cell #adjacent mined? state ;
+
+: make-cells ( rows cols -- cells )
+    '[ _ [ cell new ] replicate ] replicate ;
+
+:: cell-at ( cells row col -- cell/f )
+    row cells ?nth [ col swap ?nth ] [ f ] if* ;
+
+: cells-dim ( cells -- rows cols )
+    [ length ] [ first length ] bi ;
+
+: unmined-cell ( cells -- cell )
+    f [ dup mined?>> ] [ drop dup random random ] do while nip ;
+
+: #mines ( cells -- n )
+    [ [ mined?>> ] count ] map-sum ;
+
+: #flagged ( cells -- n )
+    [ [ state>> +flagged+ = ] count ] map-sum ;
+
+: #mines-remaining ( cells -- n )
+    [ #mines ] [ #flagged ] bi - ;
+
+: place-mines ( cells n -- cells )
+    [ dup unmined-cell t >>mined? drop ] times ;
+
+: adjacent-mines ( cells row col -- #mines )
+    neighbors [
+        first2 [ + ] bi-curry@ bi* cell-at
+        [ mined?>> ] [ f ] if*
+    ] with with with count ;
+
+:: each-cell ( ... cells quot: ( ... row col cell -- ... ) -- ... )
+    cells [| row |
+        [| cell col | row col cell quot call ] each-index
+    ] each-index ; inline
+
+:: update-counts ( cells -- cells )
+    cells [| row col cell |
+        cells row col adjacent-mines cell #adjacent<<
+    ] each-cell cells ;
+
+: reset-cells ( cells -- cells )
+    [ cells-dim make-cells ] [ #mines place-mines ] bi update-counts ;
+
+: won? ( cells -- ? )
+    [ [ { [ state>> +clicked+ = ] [ mined?>> ] } 1|| ] all? ] all? ;
+
+: lost? ( cells -- ? )
+    [ [ { [ state>> +clicked+ = ] [ mined?>> ] } 1&& ] any? ] any? ;
+
+: game-over? ( cells -- ? )
+    { [ lost? ] [ won? ] } 1|| ;
+
+: new-game? ( cells -- ? )
+    [ [ state>> +clicked+ = ] any? ] any? not ;
+
+DEFER: click-cell-at
+
+:: click-cells-around ( cells row col -- )
+    neighbors [
+        first2 [ row + ] [ col + ] bi* :> ( row' col' )
+        cells row' col' cell-at [
+            { [ mined?>> ] [ state>> +question+ = ] } 1|| [
+                cells row' col' click-cell-at drop
+            ] unless
+        ] when*
+    ] each ;
+
+:: click-cell-at ( cells row col -- ? )
+    cells row col cell-at [
+        cells new-game? [
+            ! first click shouldn't be a mine
+            dup mined?>> [
+                cells unmined-cell t >>mined? drop f >>mined?
+                cells update-counts drop
+            ] when
+        ] when
+        dup state>> { +clicked+ +flagged+ } member? [ drop f ] [
+            +clicked+ >>state
+            { [ mined?>> not ] [ #adjacent>> 0 = ] } 1&& [
+                cells row col click-cells-around
+            ] when t
+        ] if
+    ] [ f ] if* ;
+
+:: mark-cell-at ( cells row col -- ? )
+    cells row col cell-at [
+        dup state>> {
+            { +clicked+ [ +clicked+ ] }
+            { +flagged+ [ +question+ ] }
+            { +question+ [ f ] }
+            { f [ +flagged+ ] }
+        } case >>state drop t
+    ] [ f ] if* ;
+
+TUPLE: grid-gadget < gadget cells timer textures start end ;
+
+:: <grid-gadget> ( rows cols mines -- gadget )
+    grid-gadget new
+        rows cols make-cells
+        mines place-mines update-counts >>cells
+        H{ } clone >>textures
+        dup '[ _ relayout-1 ] f 1 seconds <timer> >>timer
+        COLOR: gray <solid> >>interior ;
+
+M: grid-gadget graft*
+    [ timer>> start-timer ] [ call-next-method ] bi ;
+
+M: grid-gadget ungraft*
+    [
+        dup find-gl-context
+        [ values dispose-each H{ } clone ] change-textures
+        timer>> stop-timer
+    ] [ call-next-method ] bi ;
+
+M: grid-gadget pref-dim*
+    cells>> cells-dim [ 32 * ] bi@ swap 58 + 2array ;
+
+:: cell-image-path ( cell game-over? -- image-path )
+    game-over? cell mined?>> and [
+        cell state>> +clicked+ = "mineclicked.gif" "mine.gif" ?
+    ] [
+        cell state>>
+        {
+            { +question+ [ "question.gif" ] }
+            { +flagged+ [ game-over? "misflagged.gif" "flagged.gif" ? ] }
+            { +clicked+ [
+                cell mined?>> [
+                    "mine.gif"
+                ] [
+                    cell #adjacent>> 0 or number>string
+                    "open" ".gif" surround
+                ] if ] }
+            { f [ "blank.gif" ] }
+        } case
+    ] if "vocab:minesweeper/_resources/" prepend ;
+
+: digit-image-path ( ch -- image-path )
+    "vocab:minesweeper/_resources/digit%c.gif" sprintf ;
+
+:: smiley-image-path ( won? lost? clicking? -- image-path )
+    {
+        { [ lost? ] [ "vocab:minesweeper/_resources/smileylost.gif" ] }
+        { [ won? ] [ "vocab:minesweeper/_resources/smileywon.gif" ] }
+        { [ clicking? ] [ "vocab:minesweeper/_resources/smileyuhoh.gif" ] }
+        [ "vocab:minesweeper/_resources/smiley.gif" ]
+    } cond ;
+
+: cached-texture ( path gadget -- texture )
+    textures>> [ load-image { 0 0 } <texture> ] cache ;
+
+:: draw-mines ( n gadget -- )
+    n "%03d" sprintf [
+        26 * 3 + 6 2array [
+            digit-image-path gadget cached-texture
+            { 26 46 } swap draw-scaled-texture
+        ] with-translation
+    ] each-index ;
+
+:: draw-smiley ( gadget -- )
+    gadget pref-dim first :> width
+    width 2/ 26 - 3 2array [
+        gadget cells>> won?
+        gadget cells>> lost?
+        hand-buttons get-global empty? not
+        gadget hand-click-rel second 58 >= and
+        smiley-image-path
+        gadget cached-texture { 52 52 } swap draw-scaled-texture
+    ] with-translation ;
+
+:: draw-timer ( n gadget -- )
+    gadget pref-dim first :> width
+    n "%03d" sprintf [
+        3 swap - 26 * width swap - 3 - 6 2array [
+            digit-image-path gadget cached-texture
+            { 26 46 } swap draw-scaled-texture
+        ] with-translation
+    ] each-index ;
+
+:: draw-cells ( gadget -- )
+    gadget cells>> game-over? :> game-over?
+    gadget cells>> [| row col cell |
+        col row [ 32 * ] bi@ 58 + 2array [
+            cell game-over? cell-image-path
+            gadget cached-texture
+            { 32 32 } swap draw-scaled-texture
+        ] with-translation
+    ] each-cell ;
+
+:: elapsed-time ( gadget -- n )
+    gadget start>> [
+        gadget end>> now or swap time- duration>seconds
+    ] [ 0 ] if* ;
+
+M: grid-gadget draw-gadget*
+    {
+        [ cells>> #mines-remaining ]
+        [ draw-mines ]
+        [ draw-smiley ]
+        [ elapsed-time ]
+        [ draw-timer ]
+        [ draw-cells ]
+    } cleave ;
+
+:: on-click ( gadget -- )
+    gadget hand-rel first2 :> ( w h )
+    h 58 < [
+        h 3 55 between?
+        gadget pref-dim first 2/ w - abs 26 < and [
+            gadget [ reset-cells ] change-cells
+            f >>start f >>end relayout-1
+        ] when
+    ] [
+        h 58 - w [ 32 /i ] bi@ :> ( row col )
+        gadget cells>> :> cells
+        cells game-over? [
+            cells row col click-cell-at [
+                gadget start>> [ now gadget start<< ] unless
+                cells game-over? [ now gadget end<< ] when
+                gadget relayout-1
+            ] when
+        ] unless
+    ] if ;
+
+:: on-mark ( gadget -- )
+    gadget hand-rel first2 :> ( w h )
+    h 58 >= [
+        h 58 - w [ 32 /i ] bi@ :> ( row col )
+        gadget cells>> :> cells
+        cells game-over? [
+            cells row col mark-cell-at [
+                gadget start>> [ now gadget start<< ] unless
+                cells game-over? [ now gadget end<< ] when
+                gadget relayout-1
+            ] when
+        ] unless
+    ] when ;
+
+: new-game ( gadget rows cols mines -- )
+    [ make-cells ] dip place-mines update-counts >>cells
+    f >>start f >>end relayout-window ;
+
+: com-easy ( gadget -- ) 7 7 10 new-game ;
+
+: com-medium ( gadget -- ) 15 15 40 new-game ;
+
+: com-hard ( gadget -- ) 15 30 99 new-game ;
+
+grid-gadget "toolbar" f {
+    { T{ key-down { sym "1" } } com-easy }
+    { T{ key-down { sym "2" } } com-medium }
+    { T{ key-down { sym "3" } } com-hard }
+} define-command-map
+
+grid-gadget "gestures" [
+    {
+        { T{ button-down { # 1 } } [ relayout-1 ] }
+        { T{ button-up { # 1 } } [ on-click ] }
+        { T{ button-up { # 3 } } [ on-mark ] }
+        { T{ key-down { sym " " } } [ on-mark ] }
+    } assoc-union
+] change-word-prop
+
+TUPLE: minesweeper-gadget < track ;
+
+: <minesweeper-gadget> ( -- gadget )
+    vertical minesweeper-gadget new-track
+    7 7 10 <grid-gadget>
+    [ <toolbar> format-toolbar f track-add ]
+    [ 1 track-add ] bi ;
+
+M: minesweeper-gadget focusable-child* children>> second ;
+
+MAIN-WINDOW: run-minesweeper {
+        { title "Minesweeper" }
+        { window-controls
+            { normal-title-bar close-button minimize-button } }
+    } <minesweeper-gadget> >>gadgets ;
diff --git a/extra/minesweeper/resources.txt b/extra/minesweeper/resources.txt
new file mode 100644 (file)
index 0000000..fcacd6e
--- /dev/null
@@ -0,0 +1 @@
+_resources
diff --git a/extra/minesweeper/summary.txt b/extra/minesweeper/summary.txt
new file mode 100644 (file)
index 0000000..a790673
--- /dev/null
@@ -0,0 +1 @@
+Minesweeper game
diff --git a/extra/minesweeper/tags.txt b/extra/minesweeper/tags.txt
new file mode 100644 (file)
index 0000000..cb5fc20
--- /dev/null
@@ -0,0 +1 @@
+demos