File: citygrid.tcl

package info (click to toggle)
tklib 0.6%2B20190108-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 15,008 kB
  • sloc: tcl: 75,757; sh: 5,789; ansic: 792; pascal: 359; makefile: 70; sed: 53; exp: 21
file content (220 lines) | stat: -rw-r--r-- 6,315 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# -*- tcl -*-

package require Tk
package require cache::async
package require struct::set

namespace eval ::city {

    proc block {n} { variable part ; return [expr {$n * $part}] }

    variable tessel 64
    variable part   [expr {$tessel/8}]
    variable cstart [block 2]
    variable cend   [block 6]
    variable rstart [block 3]
    variable rend   [block 5]

    variable parcel [image create photo -height $part -width $part]
    $parcel put black -to 0 0 $part $part

    variable tilecache [cache::async tc ::city::Gen]

    variable lego  {}
    variable neigh ; array set neigh {} ; # name,dir -> list(name)
    variable map   ; array set map   {} ; # name -> (type flags)
    variable grid  ; array set grid  {} ; # at -> name
}

proc ::city::tile {} {
    variable tessel
    return  $tessel
}

proc ::city::grid {__ at donecmd} {
    Tile get [Randomize $at] [list ::city::ToGrid $at $donecmd --]
    return
}
proc ::city::ToGrid {at donecmd -- what key args} {
    # Route the cache result retrieved by name to the grid cell the
    # original request came from.
    #puts "\tToGrid ($at) '$donecmd' $what ($key) <$args>"
    if {[catch {
	uplevel #0 [eval [linsert $args 0 linsert $donecmd end $what $at]]
    }]} { puts $::errorInfo }
}

proc ::city::Randomize {at} {
    variable grid
    set p [Possibilities $at]
    if {[llength $p] == 1} {
	set res [lindex $p 0]
    } else {
	set res [lindex $p [Rand [llength $p]]]
    }
    #puts "($at) = $p"
    set grid($at) $res
    return $res
}

proc ::city::Rand {n} {
    # 0...n-1
    # (0,1) -> (0,n)
    expr {int(rand()*$n)}
}

proc ::city::Possibilities {at} {
    variable lego
    variable grid
    foreach {y x} $at break

    set l [list [expr {$x - 1}] $y]
    set r [list [expr {$x + 1}] $y]
    set u [list $x [expr {$y - 1}]]
    set d [list $x [expr {$y - 1}]]

    set allowed $lego
    Cut $l r allowed
    Cut $r l allowed
    Cut $u d allowed
    Cut $d u allowed

    return $allowed
}

proc ::city::Cut {at dir v} {
    variable grid
    variable neigh
    upvar 1 $v allowed
    foreach {y x} $at break
    if {![info exists grid($at)]} return
    set allowed [struct::set intersect $allowed $neigh($grid($at),$dir)]
    return
}

proc ::city::Tile {__ name donecmd} {
    variable tilecache
    #puts "__ $name ($donecmd)"
    $tilecache get $name $donecmd
    return
}

proc ::city::Gen {__ name donecmd} {
    variable tessel
    variable cstart
    variable cend
    variable rstart
    variable rend
    variable parcel
    variable map

    #puts "\tGENERATE $name ($donecmd)"

    foreach {olx orx oux odx ilx irx iux idx cx} $map($name) break
    set tile [image create photo -height $tessel -width $tessel]
    $tile put white -to 0 0 $tessel $tessel
    #puts ([join $map($name) {)(}])|$olx|$orx|$oux|$odx|$ilx|$irx|$iux|$idx|$cx|
    if {$cx}  { $tile copy $parcel -to $rstart $rstart $rend   $rend   } ; # center

    if {$olx} { $tile copy $parcel -to 0       $rstart $cstart $rend   } ; # ou left
    if {$orx} { $tile copy $parcel -to $cend   $rstart $tessel $rend   } ; # ou right
    if {$oux} { $tile copy $parcel -to $rstart 0       $rend   $cstart } ; # ou up
    if {$odx} { $tile copy $parcel -to $rstart $cend   $rend   $tessel } ; # ou down

    if {$ilx} { $tile copy $parcel -to $cstart $rstart $rstart $rend   } ; # in left
    if {$irx} { $tile copy $parcel -to $rend   $rstart $cend   $rend   } ; # in right
    if {$iux} { $tile copy $parcel -to $rstart $cstart $rend   $rstart } ; # in up
    if {$idx} { $tile copy $parcel -to $rstart $cend   $rend   $cend   } ; # in down

    if 0 {
	set label $olx$orx$oux$odx/$ilx$irx$iux$idx/$cx
	#set label [string range $name 0 3]/[string range $name 4 7]/[string index $name 8]
	label .l$name -image $tile -bd 2 -relief sunken
	pack .l$name -side left
	tooltip::tooltip .l$name $label
    }

    #puts "run ([linsert $donecmd end set $name $tile])"
    uplevel #0 [linsert $donecmd end set $name $tile]
    return
}

proc ::city::Name {olx orx oux odx ilx irx iux idx cx} {
    #set name "$olx$orx$oux$odx$ilx$irx$iux$idx$cx"
    set name ""
    if {$cx}  { append name c } ; # center
    if {$olx} { append name l } ; # left
    if {$ilx} { append name - } ; # left
    if {$orx} { append name r } ; # right
    if {$irx} { append name _ } ; # right
    if {$oux} { append name u } ; # up
    if {$iux} { append name = } ; # up
    if {$odx} { append name d } ; # down
    if {$idx} { append name % } ; # down
    if {$name eq ""} { set name empty }
    #puts $name\ ...
    return $name
}

proc ::city::Init {} {
    variable lego
    variable neigh
    variable map

    foreach olx {0 1} {
	foreach orx {0 1} {
	    foreach oux {0 1} {
		foreach odx {0 1} {
		    foreach ilx {0 1} {
			foreach irx {0 1} {
			    foreach iux {0 1} {
				foreach idx {0 1} {
				    foreach cx {0 1} {
					# inner not allowed without center
					if {!$cx && $ilx} continue
					if {!$cx && $irx} continue
					if {!$cx && $iux} continue
					if {!$cx && $idx} continue

					#if {!$olx && $ilx} continue
					#if {!$orx && $irx} continue
					#if {!$oux && $iux} continue
					#if {!$odx && $idx} continue

					set n [Name $olx $orx $oux $odx $ilx $irx $iux $idx $cx]
					set map($n) [list $olx $orx $oux $odx $ilx $irx $iux $idx $cx]
					lappend bins(l$olx) $n
					lappend bins(r$orx) $n
					lappend bins(u$oux) $n
					lappend bins(d$odx) $n
					lappend lego $n
				    }
				}
			    }
			}
		    }
		}
	    }
	}
    }

    #puts /[llength $lego]
    
    # Now compute which tiles can be neighbours of what others, for
    # all four sides.

    foreach t $bins(d0) { foreach n $bins(u0) { lappend neigh($t,d) $n } }
    foreach t $bins(d1) { foreach n $bins(u1) { lappend neigh($t,d) $n } }
    foreach t $bins(l0) { foreach n $bins(r0) { lappend neigh($t,l) $n } }
    foreach t $bins(l1) { foreach n $bins(r1) { lappend neigh($t,l) $n } }
    foreach t $bins(u0) { foreach n $bins(d0) { lappend neigh($t,u) $n } }
    foreach t $bins(u1) { foreach n $bins(d1) { lappend neigh($t,u) $n } }
    foreach t $bins(r0) { foreach n $bins(l0) { lappend neigh($t,r) $n } }
    foreach t $bins(r1) { foreach n $bins(l1) { lappend neigh($t,r) $n } }

    foreach k [array names neigh] { set neigh($k) [lsort -unique $neigh($k)] }
    return
}

::city::Init
#exit