about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame
diff options
context:
space:
mode:
Diffstat (limited to 'js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame')
-rw-r--r--js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame268
1 files changed, 268 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame b/js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame
new file mode 100644
index 0000000..f68d3fb
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/downloads/csls-programs/dotgame
@@ -0,0 +1,268 @@
+;;; Connect-the-dots game
+
+to dotgame :size
+; Connect-the-dots game.  Input is the number of dots on each side.
+if :LogoPlatform = "Windows [maximize.window "true]
+ht cs
+setpc 7
+setpensize [6 6]
+localmake "offset (:size-1)*20
+pu setpos list -:offset -:offset
+board :size
+localmake "lines ~
+   se (crossmap [list (list ?1 ?2) (list ?1 1+?2)]
+                (iseq 0 :size-1) (iseq 0 :size-2)) ~
+      (crossmap [list (list ?1 ?2) (list 1+?1 ?2)]
+                (iseq 0 :size-2) (iseq 0 :size-1))
+localmake "computer 0
+localmake "person 0
+localmake "numboxes (:size-1)*(:size-1)
+localmake "boxlists (array 5 0)
+localmake "oldmove []
+for [i 1 4] [setitem :i :boxlists []]
+setitem 0 :boxlists ~
+        (crossmap [list ?1 ?2] (iseq 0 :size-2) (iseq 0 :size-2))
+localmake "boxes (array :size-1 0)
+for [i 0 :size-2] [setitem :i :boxes (array :size-1 0)]
+
+CATCH "WIN [FOREVER [PERSONMOVE COMMOVE]]	; play the game!
+
+if not emptyp :oldmove [	; make the last move white
+  setpc 7
+  pu
+  setpos map [40*? - :offset] first :oldmove
+  pd
+  setpos map [40*? - :offset] last :oldmove
+]
+if computer > :person ~
+   [print (se [you lost] :computer "to :person)]
+if :computer < :person ~
+   [print (se [you won] :person "to :computer)]
+if :computer = :person [print (se [tie game])]
+setpensize [1 1]
+end
+
+; --------------- Initial board display -------------------------
+
+to board :num
+repeat :num [dots :num]
+end
+
+to dots :num
+pd
+repeat :num [fd 0 pu rt 90 fd 40 lt 90 pd]
+pu lt 90 fd 40 * :num rt 90 fd 40
+end
+
+; -------------- Human player's move ---------------------
+
+to personmove
+; Read a mouse click, turn it into a move if legal.
+localmake "move gmove
+if not legal? :move [print [Not a legal move!  Try again.]
+                     personmove stop]
+drawline :move 6
+localmake "direction reverse (map "difference (last :move) (first :move))
+localmake "found "false
+fillboxes 6 "person
+if :found [personmove]
+end
+
+to gmove
+while [not buttonp] []
+while [buttonp] []
+output findline (map [? + :offset] mousepos)
+end
+
+to findline :pos
+; Find the nearest vertical or horizontal line to the mouse click.
+localmake "xrem remainder (first :pos)+10 40
+localmake "yrem remainder (last :pos)+10 40
+localmake "xpos (first :pos)+10-:xrem
+localmake "ypos (last :pos)+10-:yrem
+if :xrem > :yrem ~
+   [output list (list :xpos/40 :ypos/40) (list :xpos/40+1 :ypos/40)]
+output list (list :xpos/40 :ypos/40) (list :xpos/40 :ypos/40+1)
+end
+
+to legal? :move
+; Output true if this is an undrawn line segment connecting two dots.
+output memberp :move :lines
+end
+
+; ----------------- Computer's move ----------------------
+
+to commove
+; The computer chooses a move, does the housekeeping for it.
+; Strategy: complete boxes if possible, otherwise pick a move that doesn't
+; let the opponent complete a box.
+ifelse not emptyp (item 3 :boxlists) [
+  localmake "move lastline first (item 3 :boxlists)
+] [
+  localmake "goodlines filter "lineokay? :lines
+  ifelse not emptyp :goodlines [
+    localmake "move pick :goodlines
+  ] [
+    localmake "cohorts []
+    makecohorts :lines
+    localmake "move lastline first smallest :cohorts
+  ]
+]
+drawline :move 4
+localmake "direction reverse (map "difference (last :move) (first :move))
+localmake "found "false
+fillboxes 4 "computer
+if :found [commove]
+end
+
+to lineokay? :move
+; Output true if this move won't let the opponent complete a box.
+localmake "direction reverse (map "difference (last :move) (first :move))
+output and (boxokay? first :move) ~
+           (boxokay? (map "difference (first :move) :direction))
+end
+
+to boxokay? :box
+; Output true if this box has fewer than 2 edges already drawn.
+if or ((first :box) < 0) ((last :box) < 0) [output "true]
+if or ((first :box) > (:size-2)) ((last :box) > (:size-2)) [output "true]
+localmake "count item (last :box) item (first :box) :boxes
+if emptyp :count [make "count 0]
+output :count<2
+end
+
+to lastline :box
+; Box has three lines drawn; find the missing one for us to draw.
+if memberp (list :box (map "sum :box [0 1])) :lines [
+  output (list :box (map "sum :box [0 1]))]
+if memberp (list :box (map "sum :box [1 0])) :lines [
+  output (list :box (map "sum :box [1 0]))]
+if memberp (list (map "sum :box [0 1]) (map "sum :box [1 1])) :lines [
+  output (list (map "sum :box [0 1]) (map "sum :box [1 1]))]
+if memberp (list (map "sum :box [1 0]) (map "sum :box [1 1])) :lines [
+  output (list (map "sum :box [1 0]) (map "sum :box [1 1]))]
+output []	; box was full already (from makecohort)
+end
+
+to makecohorts :lines
+; Partition the available boxes into chains, to look for the smallest.
+; Note, the partition is not necessarily optimal -- this algorithm needs work.
+; It's important that LINES be a local variable here, so that we can "draw"
+; lines hypothetically that we're not really going to draw on the board.
+while [not emptyp :lines] [
+  localmake "cohort []
+  makecohort first :lines
+  push "cohorts :cohort
+]
+end
+
+to makecohort :line
+; Group all the boxes in a chain that starts with this line.
+; Mark the line as drawn (locally to caller), then look in both directions
+; for completable boxes.
+make "lines remove :line :lines
+localmake "direction reverse (map "difference (last :line) (first :line))
+makecohort1 (map "difference (first :line) :direction)
+makecohort1 first :line
+end
+
+to makecohort1 :box
+; Examine one of the boxes adjoining the line just hypothetically drawn.
+; It has 0, 1, or 2 undrawn sides.  (If 3 or 4, wouldn't have gotten here.)
+; 0 sides -> count the box if not already, but no further lines in the chain.
+; 1 side -> count the box, continue the chain with its last side.
+; 2 sides -> the box isn't ready to complete, so it's not in this chain.
+if or ((first :box) < 0) ((last :box) < 0) [stop]
+if or ((first :box) > (:size-2)) ((last :box) > (:size-2)) [stop]
+localmake "togo filter [memberp (list (map "sum :box first ?)
+				      (map "sum :box last ?))
+				:lines] ~
+		       [[[0 0] [0 1]] [[0 0] [1 0]]
+		        [[1 0] [1 1]] [[0 1] [1 1]]]
+if (count :togo)=2 [stop]
+if not memberp :box :cohort [push "cohort :box]
+if emptyp :togo [stop]
+localmake "line (list (map "sum :box first first :togo)
+                      (map "sum :box last first :togo))
+makecohort :line
+end
+
+to smallest :cohorts [:sofar []] [:minsize :numboxes+1]
+if emptyp :cohorts [output :sofar]
+if (count first :cohorts) < :minsize ~
+   [output (smallest bf :cohorts first :cohorts count first :cohorts)]
+output (smallest bf :cohorts :sofar :minsize)
+end
+
+; ----------- Common procedures for person and computer moves --------
+
+to drawline :move :color
+; Actually draw the selected move on the screen.
+if not emptyp :oldmove [
+  setpc 7
+  pu
+  setpos map [40*? - :offset] first :oldmove
+  pd
+  setpos map [40*? - :offset] last :oldmove
+]
+setpc :color
+pu
+setpos map [40*? - :offset] first :move
+pd
+setpos map [40*? - :offset] last :move
+make "oldmove :move
+end
+
+to fillboxes :color :owner
+; Implicit inputs (inherited from caller):
+;   :move is the move someone just made.
+;   :direction is [1 0] for vertical move, [0 1] for horizontal.
+; Note that the line is drawn, check the two boxes (maybe) on either side,
+; color them and count them for the appropriate player, see if game over.
+make "lines remove :move :lines
+if boxbefore? :move [fillbox (map "difference (first :move) :direction)]
+if boxafter? :move [fillbox first :move]
+testwin
+end
+
+to boxafter? :move
+; Output true if the box above or to the right of the move is now complete.
+output (increment first :move)=4
+end
+
+to boxbefore? :move
+; Output true if the box below or to the left of the move is now complete.
+localmake "p3 (map "difference (first :move) :direction)
+output (increment :p3)=4
+end
+
+to increment :box
+; If this isn't a box at all (might be if the move was on a border),
+; just output [].  Otherwise, increment the number in the :boxes array,
+; and move this box from one of the :boxlists to the next higher one.
+; Output the new count of number of lines drawn in this box.
+if or ((first :box) < 0) ((last :box) < 0) [output []]
+if or ((first :box) > (:size-2)) ((last :box) > (:size-2)) [output []]
+localmake "count item (last :box) item (first :box) :boxes
+if emptyp :count [make "count 0]
+setitem (last :box) item (first :box) :boxes :count+1
+setitem :count :boxlists (remove :box item :count :boxlists)
+setitem :count+1 :boxlists (fput :box item :count+1 :boxlists)
+output :count+1
+end
+
+to fillbox :box
+; Color in a completed box, increase the box count of its owner, and
+; flag that a box was completed.
+pu
+setpos (map [40*? - :offset] :box)
+filled :color [repeat 4 [fd 40 rt 90]]
+make :owner (thing :owner)+1
+make "found "true
+end
+
+; ------------------- Endgame processing --------------------
+
+to testwin
+if :computer+:person = :numboxes [throw "win]
+end