############################################################################ # # File: carplay.icn # # Subject: Program to create "carpets" # # Author: Ralph E. Griswold # # Date: January 11, 1998 # ############################################################################ # # This is an experimental program under development to produce carpets # as specificed in the include file, carpincl.icn, which is produced by # carport.icn. # ############################################################################ # # Requires: Version 9 graphics and large integers # ############################################################################ # # Links: carputil, lists, matrix, mirror, options, wopen # # Note: The include file may contain link declarations. # ############################################################################ link carputil link lists link matrix link mirror link options link wopen $include "carpincl.icn" $ifdef Randomize link random $endif $ifdef Scramble link random $endif $ifdef Background $undef Hidden $undef Save_carpet $undef Dialogs $undef Save_mirror $define Hidden $define Save_carpet $endif $ifdef Dialogs link interact $undef Save_carpet $undef Save_mirror $endif global array global cmod global colors global height global modulus global width procedure main() local mcarpet $ifdef Randomize randomize() $endif # The carpet-generation process is now done by two procedures, the first to # initialize the edges and the second to actually create the carpet. This # has been done to allow possible extensions. init() weave() $ifdef Mirror mcarpet := mirror(&window) # produced mirrored image $endif $ifndef Hidden $ifdef Mirror WAttrib(mcarpet, "canvas=normal") # make the mirrored image visible Raise() $endif $endif $ifdef Dialogs Bg("light gray") # reset colors for dialogs Fg("black") repeat { # provide user dialog case TextDialog("Save images?", , , , ["Quit", "Save Image", "Save Mirrored"]) of { "Quit" : exit() "Save Image" : snapshot() "Save Mirrored" : snapshot() } } $else $ifdef Save_carpet WriteImage(Name || ".gif") $ifdef Save_mirror WriteImage(Name || "_m.gif") $endif $endif $ifndef Hidden repeat case Event() of { # process low-level user events "q" : exit() "s" : WriteImage(Name || ".gif") "m" : WriteImage(Name || "_m.gif") } $endif $endif end # Initialize the carpet procedure init() local m, n, v, canvas colors := carpcolr(Colors) | { $ifdef Dialogs Notice("Unrecognized color specification.", "Palette c2 substituted.") #else write(&errout, "Unrecognized color specification.", "\n", "Palette c2 substituted.") $endif colors := colrplte("c2") } cmod := *colors # The definitions in the following expressions may not be constants. # Assignments are made to avoid expressions being evaluated multiple # times. This not only prevents unnecessary evaluation later, but it # also prevents values from changing while the carpet is being # generated. modulus := Modulus width := Width height := Height array := create_matrix(height, width, 0) $ifdef Hidden canvas := "canvas=hidden" $else canvas := "canvas=normal" $endif WOpen(canvas, "size=" || width || "," || height) | { $ifdef Dialogs ExitNotice("Cannot open window for carpet.") $else stop("Cannot open window for carpet.") $endif } # Initialize the edges. m := 0 every v := (Left \ height) do { array[m +:= 1, 1] := v % modulus } n := 0 every v := (Top \ width) do { array[1, n +:= 1] := v % modulus } return end $ifndef Twopass # do modulus reduction on the fly. # Create the carpet. procedure weave() local m, n every m := 1 to height do { if *Pending() > 0 then { if Event() === "q" then exit() } every n := 1 to width do { $ifdef Wrap array[m, n] := neighbor( array[(m - 1) | -1, (n - 1) | -1], array[(m - 1) | -1, n], array[m, (n - 1) | -1] ) % modulus $else array[m, n] := neighbor( array[m, n - 1], array[m - 1, n - 1], array[m - 1, n], ) % modulus $endif Fg(colors[(abs(integer(array[m, n])) % cmod) + 1]) DrawPoint(n - 1, m - 1) } } return end $else # do modulus reduction on a second pass # In this version, the computations are made in plain arithmethic and # then modulo-reduced in a second pass. The results are the same as # long as all operations have satisfy the relationship (i op j) % n = # (i % n) op (j % n). This is true for addition, subtraction, and # multiplication. procedure weave() local m, n every m := 1 to height do { if *Pending() > 0 then { if Event() === "q" then exit() } } every n := 1 to width do { $ifdef Wrap array[m, n] := neighbor( array[(m - 1) | -1, (n - 1) | -1], array[(m - 1) | -1, n], array[m, (n - 1) | -1] ) } } $else array[m, n] := neighbor( array[m, n - 1], array[m - 1, n - 1], array[m - 1, n], ) } } $endif every m := 1 to height do { if *Pending() > 0 then { if Event() === "q" then exit() } } every n := 1 to width do { Fg(colors[(abs(integer(array[m, n] % modulus)) % cmod) + 1]) DrawPoint(n - 1, m - 1) } } return end $endif procedure neighbor(n, nw, w) return Neighbors end