Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Question and comment about randomizing a block of values

 [1/28] from: jos::trapeze::com at: 18-Jun-2001 16:45


-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hey all! I'm working on a set of generic class's to be used to create card based games. (current framework included below) My question centers on 'shuffling' the deck. I know there are _many_ methods of shuffling, with various degrees of randomness. I'd like to know what you all think about the following 'shuffle' function (this function is in a class. the list-of-cards var is a class variable): shuffle-deck: func [ "Randomizes the list-of-cards" number-of-passes [number!] ] [ for a-pass 1 number-of-passes 1 [ sort/compare list-of-cards func [a b /local c] [ c: random 2 if c = 1 [return true] if c = 2 [return false] ] ] ] Using the sort/compare works really fast, but i'm not sure that this is the way its meant to be used ;), but it seems to work quite well, especially with multiple passes. If anyone has any suggestions, please let me know! thanks jos ps. here is the framework so far... REBOL [ Title: "Generic Card Object Framework" Version: 0.0.1 Author: {Jos "Hyakugei" Yule} Date: 20-June-2001 ] card: make object! [ ;place holder to be extended ; depending on what kind of cards you want to use ] collection-of-cards: make object! [ list-of-cards: [] ; should be a 'block' of object cards. get-top-card: func [ "Returns (and removes) the top card in the list-of-cards vars" ] [ top-card: first list-of-cards remove list-of-cards return top-card ] ; built in assumption - a card is added to the bottom of the 'pile' add-card: func [ "Adds (appends} a card to the list" the-card [object!] ] [ list-of-cards: append list-of-cards the-card ] shuffle-deck: func [ "Randomizes the list-of-cards" number-of-passes [number!] ] [ for a-pass 1 number-of-passes 1 [ sort/compare list-of-cards func [a b /local c] [ c: random 2 if c = 1 [return true] if c = 2 [return false] ] ] ] create-deck: func [ "Create a deck of cards" ] [] ; just a 'virtual' function (is that the right term?) ; this is pretty dependant on the kind of cards you are implementing ; 'regular' cards, Tarot, Magic:the gathering, etc. new: func ["Creates a new collection of cards"] [ make self [] ] ] -----BEGIN PGP SIGNATURE----- Version: PGP 6.5.8 iQA/AwUBOy5ohN4WdA43RP/AEQLSKACgjMxXksroSB84bYfmaN3Q6B/SQh8AoIIr vZYu8mQ7pkt4J/kZnKuFEAX7 =zOvW -----END PGP SIGNATURE-----

 [2/28] from: joel:neely:fedex at: 18-Jun-2001 17:18


Hi, Jos, Minor tweaks and a major suggestion... Jos Yule wrote:
> My question centers on 'shuffling' the deck. I know there are _many_ > methods of shuffling, with various degrees of randomness. I'd like to
<<quoted lines omitted: 15>>
> especially with multiple passes. If anyone has any suggestions, > please let me know!
Your existing design above can be simplified and sped up by the following changes: 1) Since you're not using A-PASS within each pass, you can dispense with it (and the overhead of a FOR loop) entirely: shuffle-deck: func [ "Randomizes the list-of-cards" number-of-passes [number!] ] [ loop number-of-passes 1 [ ;... ] ] 2) We can evolve the comparison function to a much simpler state: 2.1) Since RANDOM 2 must always return 1 or 2, we don't need two IF tests. This first step gives us: func [a b /local c] [ either 1 = c: random 2 [return true] [return false] ] 2.2) Now C is unnecessary, so eliminate it: func [a b] [ either 1 = random 2 [return true] [return false] ] 2.3) Now we have a tautology; we're returning the same LOGIC! value that EITHER is testing, so there's no point in restating it: func [a b] [ return [1 = random 2] ] 2.4) A function returns the last expression evaluated, so we don't need to say RETURN anymore: func [a b] [1 = random 2] I've incorporated both of these into the generic block-shuffling function which follows (after a little block constructor): iota: func [n [integer!] /local c r] [ r: make block! n c: 0 loop n [append r c: c + 1] ]
>> iota 10
== [1 2 3 4 5 6 7 8 9 10]
>> iota 2
== [1 2] shuffle-block: func [b [block!] n [integer!]] [ loop n [sort/compare b func [a b] [1 = random 2]] ]
>> shuffle-block iota 20 10
== [15 4 13 19 9 16 6 10 12 18 5 20 3 17 14 7 2 1 8 11] Now for a suggested change to your design... I can think of two problems with using RANDOM inside the comparison function: 1) It adds cycles in the inner-most loop. The cost of calling a user-written comparison function, plus the cost of whatever that function does, can really add up for large blocks. (I'm assuming that the time complexity of SORT is O(n log n) , which is canonical.) 2) Since successive calls on RANDOM make the comparison unstable that can inflate the time complexity of the sort (depending on what sort algorithm is used internally). We can solve both of those by making this observation. You can shuffle a block by copying elements from the block using a set of index values that have been shuffled (as long as each index value occurs exactly once). Consider this little modification on IOTA from above: random-iota: func [n [integer!] /local m f c r] [ f: n + 1 m: f * f c: 0 r: make block! n loop n [append r (f * random m) + c: c + 1] ] This creates a block of (weird-looking ;-) numbers like this:
>> foo: random-iota 10
== [859 794 850 1115 1193 963 689 536 1219 714] But there's method in my wierdness! Those number actually have the property that their remainders (mod N + 1) are the set of numbers 1 thru N, and their "high-order" bits are random! That means that we can sort them and use their remainders to get a shuffled set of indexes, as follows:
>> sort foo
== [536 689 714 794 850 859 963 1115 1193 1219]
>> foreach n foo [prin [n // 11 " "]] print ""
8 7 10 2 3 1 6 4 5 9 Based on that, we can create a shuffling function that generates a block of random indexes and then builds a new block by copying the indexed elements from the original block. shuffled: func [b [block!] /local m n i r] [ r: make block! n: length? b i: sort random-iota n m: n + 1 foreach n i [append r pick b n // m] ] which behaves as follows:
>> test-data: iota 20
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
>> new-data: shuffled test-data
== [6 10 9 12 20 19 15 13 7 11 2 5 18 8 16 14 3 1 17 4] This version sorts a block of weird-looking integers which can then have unique index values remaindered out to build the result from the input block. I believe it to be a significant speed improvement (although I haven't had the time to benchmark it ;-) because: 1) It sorts a block of INTEGER! values. I suspect this is the fastest thing we can sort (but I'm sure Holger will let us know if I'm wrong on this detail). 2) It eliminates the need for the "call-back" to a user-written comparison function. 3) It will call RANDOM (within RANDOM-IOTA) exactly once for each element in the original block. Hope this helps! -jn- ___ ___ ___ \/ 2 + \/ 2 = 4 (for sufficiently large approximations of \/ 2 ) joel'dot'neely'at'fedex'dot'com

 [3/28] from: agem:crosswinds at: 19-Jun-2001 0:47


RE: [REBOL] Question and comment about randomizing a block of values [jos--trapeze--com] wrote:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1
<<quoted lines omitted: 20>>
> especially with multiple passes. If anyone has any suggestions, > please let me know!
:) :) :) funny way usualy i shuffle like this: [rebol [] n-cards: 20 deck: copy [] repeat i n-cards [append deck i] probe deck random/seed now shuffled-deck: copy [] loop n-cards [ card-no: random length? deck append shuffled-deck pick deck card-no remove at deck card-no ] probe shuffled-deck ] also Allan Kamp has some nice card-games. on http://www.rebolforces.com/index.r , reb-sites/R-forces . maybe he should start some article about it? BTW Allan, where are the RebNotes gone?! -Volker

 [4/28] from: joel:neely:fedex at: 18-Jun-2001 17:44


Hi, Jos (and all), Sorry to be replying to my own post, but another bit of explanation might be in order... Joel Neely wrote:
> random-iota: func [n [integer!] /local m f c r] [ > f: n + 1
<<quoted lines omitted: 3>>
> loop n [append r (f * random m) + c: c + 1] > ]
The reason why F needs to be N + 1 is that REBOL uses 1-origin indexing instead of 0-origin indexing. Since our weird numbers have to have remainders in the range 1..N we have to multiply the high-order randomness by N + 1 to protect all of the indexes. The reason why M is F * F is simply to give RANDOM more of a chance to "spread" the high-order randomness out, reducing the probability that we'll get duplicates in the H-O R. HOWEVER... Upon further reflection, I've decided that the coupling between RANDOM-IOTA and SHUFFLED is just too ugly for words. Therefore, I propose to atone for that ugliness that by offering the slightly-less-ugly: shuffled-iota: func [n [integer!] /local m f c r] [ m: n * n c: -1 r: make block! n loop n [append r (n * random m) + c: c + 1] sort r forall r [change r r/1 // n + 1] head r ] shuffled-block: func [b [block!] /local n i r] [ r: make block! n: length? b i: shuffled-iota n foreach n i [append r pick b n] ] which push all the arithmetic nastiness into SHUFFLED-IOTA, and still behave as follows:
>> test-data: iota 20
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
>> new-data: shuffled-block test-data
== [16 8 11 20 5 2 19 10 18 1 17 15 7 4 13 12 9 3 14 6]
>> sort copy new-data
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20] Cleaner is better! -jn- ___ ___ ___ \/ 2 + \/ 2 = 4 (for sufficiently large approximations of \/ 2 ) joel'dot'neely'at'fedex'dot'com

 [5/28] from: joel:neely:fedex at: 18-Jun-2001 18:22


Hi, Volker, [agem--crosswinds--net] wrote:
> usualy i shuffle like this: > [rebol []
<<quoted lines omitted: 11>>
> probe shuffled-deck > ]
It probably doesn't matter for small blocks, but I suspect the overhead of plucking a value out of the middle of a block (presuming that the following elements are scooted over to fill the gap) might add up for larger blocks. That's one of the reasons I proposed building a result without modifying the original. Some benchmarking is probably in order to see whether my suspicions are valid or total nonsense (both have been known to happen ;-). -jn- ___ ___ ___ \/ 2 + \/ 2 = 4 (for sufficiently large approximations of \/ 2 ) joel'dot'neely'at'fedex'dot'com

 [6/28] from: agem:crosswinds at: 19-Jun-2001 1:53


RE: [REBOL] Re: Question and comment about randomizing a block of values [joel--neely--fedex--com] wrote:
> Hi, Jos (and all), > Sorry to be replying to my own post, but another bit of explanation
<<quoted lines omitted: 30>>
> head r > ]
;Aargh! whats this? you are going to beat Ladislav in puzzling! ;specially tricky the hidden assignment of 'c ! :) ; after puzzling a while i think you do this? : [rebol [] ???: func ["set-word!-?? , dump-tool" 'word value] [ print [mold :word " : " mold :value] word :value] shuffled-iota: func [n [integer!] /local f r r1 i] [ f: 2 ** 30 ;make a block of pairs [57 1 82 2 16 3 ..] r1: make block! n * 2 repeat i n [append r1 reduce [random f i]] ;flat block! sort/skip ?? r1 2 ;shuffle-map ready ? r1 ;now keep only the indices, kill randoms r: make block! n forskip r1 2 [append r second r1] r ] shuffled-block: func [b [block!] /local n i r] [ r: make block! n: length? b i: shuffled-iota n foreach n i [append r pick b n] ] ;and test random/seed now ??? test-data: repeat i 20 [append [] i] ;never in function! ??? new-data: shuffled-block test-data ??? all-numbers-there?: sort copy new-data ;-) Volker ]

 [7/28] from: joel:neely:fedex at: 18-Jun-2001 15:48


Hi, again, Volker! [agem--crosswinds--net] wrote:
> [joel--neely--fedex--com] wrote: > >
<<quoted lines omitted: 10>>
> ;Aargh! whats this? you are going to beat Ladislav in > puzzling!
Who should be more offended, Ladislav or me? ;-)
> ;specially tricky the hidden assignment of 'c ! :) >
It's not hidden; it's right there in plain sight! Actually, one of the aspects of Jeff's post on "REBOL Zen" was the fact that many REBOL expressions have both a result value and an effect (not to say "side-"effect), and that tense, well-bummed code makes use of both.
> ; after puzzling a while i think you do this? : >
You certainly got the essence of SHUFFLED-IOTA , but ...
> ???: func ["set-word!-?? , dump-tool" 'word value] [ > print [mold :word " : " mold :value] word :value]
<<quoted lines omitted: 10>>
> r > ]
... I used arithmetic instead of a pair-block because I wanted to squeeze all of the performance I could out of SHUFFLED-IOTA. You've inspired me to run some benchmarks on how much difference it makes, however.
> ??? test-data: repeat i 20 [append [] i] ;never in function! >
And *you* accused *me* of being tricky??? I'm going to have to remember *that* tasty little trick, I assure you! -jn- ------------------------------------------------------------ Programming languages: compact, powerful, simple ... Pick any two! joel'dot'neely'at'fedex'dot'com

 [8/28] from: agem:crosswinds at: 19-Jun-2001 4:51


RE: [REBOL] Re: Question and comment about randomizing a block of values [joel--neely--fedex--com] wrote:
> Hi, Volker, > [agem--crosswinds--net] wrote:
<<quoted lines omitted: 25>>
> my suspicions are valid or total nonsense (both have been known > to happen ;-).
its in my trick-bag now. :) but card-games, ~50? performance-hint for great blocks: don't use remove. poke deck card-no (last deck) clear back tail deck random is random i hope? ;-) ;clear can be ommitted with downcounting loop.. -Volker

 [9/28] from: joel:neely:fedex at: 18-Jun-2001 18:54


[agem--crosswinds--net] wrote:
> its in my trick-bag now. :) but card-games, ~50? >
Clearly there's a trade-off between speed and readability. At ~50 there's not much speed gain to worry about, but for larger numbers there's an advantage to be had. OBTW, I did the benchmarking with a slightly (again!) modified version of my SHUFFLED-IOTA, given below. Using the square of N for the high-order part limits the maximum block size to ~1K. Inspired by your larger random range, I tricked M to use most of the remaining bits for high- order randomization. Hence: shuffled-iota1: func [n [integer!] /local m f c r] [ m: to-integer (2 ** 30) / n c: -1 r: make block! n loop n [append r (n * random m) + c: c + 1] sort r forall r [change r r/1 // n + 1] head r ] A quick bit of benchmarking with the above vs. your version with SORT/SKIP (generating 1000 blocks with 2000 entries each) showed times of 5:12 vs. 6:38, about 27% longer for SORT/SKIP.
> performance-hint for great blocks: don't use remove. > poke deck card-no (last deck) clear back tail deck >
I guess I'm being dense tonight, but I don't see how that last line above shuffles the block.
>> tester: iota 10
== [1 2 3 4 5 6 7 8 9 10]
>> poke tester (random 10) (last tester)
== [1 2 3 4 5 6 7 8 9 10]
>> poke tester (random 10) (last tester)
== [1 2 10 4 5 6 7 8 9 10]
>> poke tester (random 10) (last tester)
== [1 10 10 4 5 6 7 8 9 10]
>> poke tester (random 10) (last tester)
== [1 10 10 4 5 6 7 8 9 10]
>> poke tester (random 10) (last tester)
== [1 10 10 4 5 6 10 8 9 10] It would "overstrike" a random element with the last element of the block, losing the one POKEd on top of. OTOH, using ...
>> tester: iota 10
== [1 2 3 4 5 6 7 8 9 10]
>> insert at tester (random 10) last tester
clear back tail tester == []
>> insert at tester (random 10) last tester
clear back tail tester == []
>> insert at tester (random 10) last tester
clear back tail tester == []
>> insert at tester (random 10) last tester
clear back tail tester == []
>> insert at tester (random 10) last tester
clear back tail tester == []
>> tester
== [6 1 9 8 10 2 3 4 5 7] ... does get the shuffling done, but now the INSERT is the culprit for having to scoot the block elements around. Have I misunderstood something?
> random is random i hope? ;-) >
Perhaps RANDOM/SECURE is more random than RANDOM ... ;-) -jn- ------------------------------------------------------------ Programming languages: compact, powerful, simple ... Pick any two! joel'dot'neely'at'fedex'dot'com

 [10/28] from: hyakugei:theorganization at: 18-Jun-2001 22:26


-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 - ----- Original Message ----- From: "Joel Neely" <[joel--neely--fedex--com]> To: <[rebol-list--rebol--com]> Sent: Monday, June 18, 2001 6:44 PM Subject: [REBOL] Re: Question and comment about randomizing a block of values
<snip> > shuffled-iota: func [n [integer!] /local m f c r] [
<<quoted lines omitted: 11>>
> foreach n i [append r pick b n] > ]
</snip> Wow. Thanks for 2 very interesting emails/articles on code refactoring! These are very clever methods, i'm going to have to go over them tonight, to try to figure out what is going on! (not that your explanation is not clear, i just need to 'actually do it' in rebol for it to sink in) <grin> I will do some speed comparisons too, tho the deck i will be using is pretty small (81 cards), so i might devise a larger 'test' deck to get better results... Thanks again for the well thought out code! jos "hyakugei" yule -----BEGIN PGP SIGNATURE----- Version: PGP 6.5.8 iQA/AwUBOy64Ud4WdA43RP/AEQKLNwCfRGU/K1ttz/GNnABN2Hq20O6ISyAAnROg C75Hg56PwDkZjHDgpcS19FDr =+QvR -----END PGP SIGNATURE-----

 [11/28] from: jeff:rebol at: 19-Jun-2001 7:07


Sorry to ask a stupid question, but what's wrong with: random/seed now/time c: 0 x: random reduce head insert/dup copy [] [c: c + 1] 52 ; -- produces a block of 1 - 52 randomly ordered

 [12/28] from: joel:neely:fedex at: 19-Jun-2001 10:05


Hi, Jeff, Thanks for the hint! Not a stupid question at all ... Jeff Kreis wrote:
> Sorry to ask a stupid question, but what's wrong with: > random/seed now/time
<<quoted lines omitted: 3>>
> > > shuffled-iota1: func [n [integer!] /local m f c r] [ > . . .
... but I guess I'm the stupid one.
>> ? random
USAGE: RANDOM value /seed /secure /only DESCRIPTION: Returns a random value of the same datatype. RANDOM is an action value. ARGUMENTS: value -- Maximum value of result (Type: any) REFINEMENTS: /seed -- Restart or randomize /secure -- Returns a cryptographically secure random number. /only -- Return single value from series.
>>
Having seen your example (I like the INSERT/DUP trick, BTW) I can now be reminded of it by the hints in HELP output, but I think it would have taken me a VERRRRY long time to make the leap in the other direction and think of trying that from the way that RANDOM is described. Ah, well... That's how we learn! -jn- ___ ___ ___ \/ 2 + \/ 2 = 4 (for sufficiently large approximations of \/ 2 ) joel'dot'neely'at'fedex'dot'com

 [13/28] from: gjones05:mail:orion at: 19-Jun-2001 11:23


From: "Jeff Kreis"
> random/seed now/time > c: 0 > x: random reduce head insert/dup copy [] [c: c + 1] 52 > > ; -- produces a block of 1 - 52 randomly ordered
I've been thinking about this on and off for two hours, and I still do not understand how this statement works. Can someone state what is going on in other words? Thanks! --Scott Jones

 [14/28] from: agem:crosswinds at: 19-Jun-2001 18:44


RE: [REBOL] Re: Question and comment about randomizing a block of values joelfehlf (15) ! [rebol [title: "shortest rebol-toy?"] view layout [ f1: field "anagram" a1: h1 f1/size button "anagram" [a1/text: random f1/text show a1] ] ] nice to know that :) -Volker [jeff--rebol--net] wrote:

 [15/28] from: jeff:rebol at: 19-Jun-2001 9:47


Howdy, Joel:
> >> ? random > USAGE: > RANDOM value /seed /secure /only
[...]
> Having seen your example (I like the INSERT/DUP trick, BTW) > I can now be reminded of it by the hints in HELP output, > but I think it would have taken me a VERRRRY long time to > make the leap in the other direction and think of trying > that from the way that RANDOM is described.
RANDOM on a block is a relatively recent addition to REBOL (like core 2.3 and higher I think). RANDOM/only [block] returns a random element from the block. RANDOM [block] returns a randomized version of that block. I think it's a handy shorthand. Also works on other series: rand-alpha: random alpha: "abcdefghijklmnopqrstuvwxyz" ;-- (Creates a copy) The commonly found construct: 'PICK block RANDOM LENGTH? block' can be replaced with 'RANDOM/only block'. And as you've discovered, 'RANDOM block' can replace a considerable variety of code that does the same. :-) This returns us to a unifying concept in REBOL: series as values vs. series as sequential values. RANDOM and RANDOM/only on a block extends the two ways we can think of blocks. We can treat a block as a value itself, or as a sequence of separate values. MOLD/only, RANDOM/only, CHANGE/only, INSERT/only, FIND/only. ONLY allows us to switch our approach to that of "singular" values, we are interested in a single thing. Otherwise we are treating the series as a sequence of things. #1 find [1 2 3 [1 2 3]] [1 2 3] #2 find/only [1 2 3 [1 2 3]] [1 2 3] When I look at the above, in the first one, I mentally strip the outer brackets of the [1 2 3] that we're looking for, and I imagine a full expression that looks like: #1 find [1 2 3 [1 2 3] 1.. 2.. 3.. I want to find the sequence 1 followed by 2 followed by 3. In the second case, I mentally reinforce the surounding brackets of [1 2 3] that's being sought, and I see an expression like: #2 find [1 2 3 [1 2 3]] _[_ 1 2 3 _]_ I want to find THE single block value whose contents are 1 2 3. So the same deal with RANDOM: #1 random [1 2 3] #2 random/only [1 2 3] I mentally convert to: #1 random 1.. 2.. 3.. #2 random _[_ 1 2 3 _]_ #1 I want the random sequence of numbers made from the sequence of numbers 1 followed by 2 followed by 3. #2 I want a single random value from this block of values. Don't mean to lecture (-:, just think this is an important and powerful concept found in series that sometimes gets overlooked. Recognizing this dual nature of REBOL series is very helpful in so many different problem domains. This just seemed an appropriate spot in the thread to rant about the series duality for the benefit of any who may not already have the concept solid in their REBOL mental model. :-) Party on-- -jeff

 [16/28] from: joel:neely:fedex at: 19-Jun-2001 12:07


Hey, Scott, Which part? See below GS Jones wrote:
> From: "Jeff Kreis" > > random/seed now/time
<<quoted lines omitted: 5>>
> still do not understand how this statement works. Can someone > state what is going on in other words?
The deep magic (the part I didn't know about ;-) is that RANDOM will take a block and return a "randomized" copy of the block:
>> a: [1 2 3 4] == [1 2 3 4] >> random a == [3 2 4 1] >> random a == [3 2 1 4] >> random a == [4 3 2 1] >> random a == [3 1 2 4]
in contrast to RANDOM/ONLY which returns a random selection from the block
>> random/only a == 3 >> random/only a == 1 >> random/only a == 4 >> random/only a == 3
The cool trick on the right-hand side is to use an anonymous block that is extended with instructions to count up, and then is reduced. Note the addition of PROBEs... c: 0 x: probe random probe reduce probe head insert/dup copy [] [c: c + 1] 8 which yields [ c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1] A block containing 8 copies of C: C + 1 will reduce to [1 2 3 4 5 6 7 8] (if C is initialized to zero, of course). This randomizes to [7 6 4 3 5 2 1 8] Cool, huh? Thanks again, Jeff! -jn- ___ ___ ___ \/ 2 + \/ 2 = 4 (for sufficiently large approximations of \/ 2 ) joel'dot'neely'at'fedex'dot'com

 [17/28] from: petr:krenzelok:trz:cz at: 19-Jun-2001 19:35


----- Original Message ----- From: "GS Jones" <[gjones05--mail--orion--org]> To: <[rebol-list--rebol--com]> Sent: Tuesday, June 19, 2001 6:23 PM Subject: [REBOL] Re: Question and comment about randomizing a block of values
> From: "Jeff Kreis" > > random/seed now/time
<<quoted lines omitted: 4>>
> I've been thinking about this on and off for two hours, and I still do not > understand how this statement works. Can someone state what is going on
in
> other words?
->> x: insert/dup copy [] [c: c + 1] 52 == [] ->> head x == [c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c: c + 1 c... ->> c: 0 == 0 ->> reduce head x == [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 4... I hope it is self explanatory now (in fact - it is crazy! :-) "Insanely great" :-) -pekr-

 [18/28] from: gjones05:mail:orion at: 19-Jun-2001 13:11


From: "Joel Neely"
> Hey, Scott, > > Which part? See below
Oh, the "usual" part, you know, the one that becomes obvious once someone points it out in a different way!!
> > From: "Jeff Kreis" > > > random/seed now/time
<<quoted lines omitted: 8>>
> > state what is going on in other words? > >
JN> The deep magic (the part I didn't know about ;-) is that RANDOM JN> will take a block and return a "randomized" copy of the block: This was ultimately the stumper portion. I thought I understood 'random, so I was looking for the magic elsewhere. Since I was not really familiar with insert/dup, I figured that I must be misunderstanding something inherent in the construct. Just like the append "problem" (problem for me only!!) from last week, cognitively, I keep falling for the red herring. What annoys me once again, is that I should know better, and should have been using your reductionist approach. Obviously I didn't learn the real lesson last time, and I'll just have to wait and see if I have learned it this time. Thanks for the full explanation! <major snip> JN> Cool, huh? Thanks again, Jeff! This is the sort of abstraction and encapsulation of functionality that just blows me away in regards to REBOL. Good job RT! --Scott Jones

 [19/28] from: gjones05:mail:orion at: 19-Jun-2001 13:15


From: "Petr Krenzelok" ...
> I hope it is self explanatory now (in fact - it is crazy! :-) "Insanely > great" :-)
Yes, thank you, and insanely great is exactly the way to describe it! --Scott Jones

 [20/28] from: gjones05:mail:orion at: 19-Jun-2001 12:48


> From: "Jeff Kreis" > random/seed now/time > c: 0 > x: random reduce head insert/dup copy [] [c: c + 1] 52 > > ; -- produces a block of 1 - 52 randomly ordered
From: "Volker Nitsch"
> joelfehlf (15) ! > [rebol [title: "shortest rebol-toy?"]
<<quoted lines omitted: 5>>
> ] > nice to know that :)
Awesome!!! Now, I get it! --Scott Jones

 [21/28] from: gjones05:mail:orion at: 19-Jun-2001 13:34


From: "Jeff Kreis" ...
> This just seemed an appropriate spot in the thread to rant about the > series duality for the benefit of any who may not already have the > concept solid in their REBOL mental model. :-) Party on--
Hi, Jeff, Feel free to rant on all you want!!! I would suggest including this discussion in an upcoming REBOL/Zine, so that we have a great reference to which to point people in the future. You folks at RT have put a lot of thought into enhancing the language in ways that save sometimes a dozen lines of programming here and there. It all adds up. Many of the languages I've used may extend functionality through libraries, but what I really appreciate about REBOL and RT is the way that you thoughtly encapsulate the most important functionality using no new function names! Keep up the great work! --Scott Jones

 [22/28] from: agem:crosswinds at: 19-Jun-2001 13:54


RE: [REBOL] Re: Question and comment about randomizing a block of values Hi Joel [joel--neely--fedex--com] wrote:
> [agem--crosswinds--net] wrote: > >
<<quoted lines omitted: 21>>
> with SORT/SKIP (generating 1000 blocks with 2000 entries each) > showed times of 5:12 vs. 6:38, about 27% longer for SORT/SKIP.
Wow. thats close. 27% for being more readable. IMHO of course ;-) if, it may serve as doc for your version, then presenting the modulo trick to pack two numbers in one? i think your main advantage about my first version is, it depends linear on n instead of this n*n with the remove-move. this advantage should be kept with the sort/skip? of course programming c 27% would be horrible, there i'm happy place optimized code everywhere :) if i could only motivate me to write some.. a, bitmap/graphics! oh no, 3d now. matrices. hey, lots of zeros! could unroll this loops a bit, some lines rebol.. AARGH! how to put the c in blocks? well, hoping the compiler will do it.. what do you say, recursive templates? hey, works! cool! needs only some years to get the right grip.. OK, going OT, but c, old friend.. ;-)
> > > > performance-hint for great blocks: don't use remove.
<<quoted lines omitted: 14>>
> >> poke tester (random 10) (last tester) > == [1 10 10 4 5 6 10 8 9 10]
thank you for the "late" answer. was night here to. so my undrstanding of your understanding.. ;) meant it this way: instead of filling the gap by remove and moving the whole rest of the block, i fill it with the last element and let the rest in place, then shrink the block moves 1 element/loop instead of n/2. you can ignore the shrink-part if you calculate card-no based on index, like repeat i n-cards: (random length? deck) - i + 1 .. ;+/-1 , my preferred bug [rebol [] n-cards: 20 deck: copy [] repeat i n-cards [append deck i] probe deck random/seed now shuffled-deck: copy [] loop n-cards [ card-no: random length? deck append shuffled-deck pick deck card-no ; remove at deck card-no ;replaced with poke deck card-no (last deck) clear back tail deck ] probe shuffled-deck probe sort shuffled-deck ]
> It would "overstrike" a random element with the last element > of the block, losing the one POKEd on top of.
<<quoted lines omitted: 25>>
> > > Perhaps RANDOM/SECURE is more random than RANDOM ... ;-)
:-) Carl? -Volker

 [23/28] from: joel:neely:fedex at: 19-Jun-2001 18:24


Hey, Jeff, Since we started off apologizing for "stupid" questions, I'll feel entitled to ask a few of my own. (Not complaining, just clarifying... ;-) Jeff Kreis wrote:
> Sorry to ask a stupid question, but what's wrong with: > > random/seed now/time > c: 0 > x: random reduce head insert/dup copy [] [c: c + 1] 52 >
Nothing's wrong with it but... Stupid Question #1: How were we supposed to know about it? I went back and checked the 2.3 and 2.5 release docs at www.rebol.com and found no mention of this capability. I *did* find a mention of applying RANDOM to TUPLE! values, but I'll discuss that later on.
> RANDOM on a block is a relatively recent addition to REBOL > (like core 2.3 and higher I think). > > RANDOM/only [block] ... random element from the block. > RANDOM [block] ... randomized version of that block. > > I think it's a handy shorthand... >
So do I. I wish I had known about it. :-/
> This returns us to a unifying concept in REBOL: series as > values vs. series as sequential values. >
Well, it returns *me* to another concept: the dangers of using conversational language as our only (or, in this case, /ONLY ;-) specification.
> Don't mean to lecture (-:, just think this is an important > and powerful concept found in series that sometimes gets > overlooked. Recognizing this dual nature of REBOL series is > very helpful in so many different problem domains. >
WADR, understanding the difference between series-as-value and series-as-container-of-values is fairly well-established for many of us. However (speaking for myself), I'm still not very good at "mind-reading" to figure out how some parts of REBOL work. Stupid Question #2: How are we to figure out the sense of potentially ambiguous refinements (or short verbal descriptions) without resorting to trial and error? Let's examine the appeal to precedent by looking at APPEND. From the examples such as:
>> append [1 2 3] 4 == [1 2 3 4] >> append/only [1 2 3] [4 5 6] == [1 2 3 [4 5 6]] >> append [1 2 3] [4 5 6] == [1 2 3 4 5 6]
we might infer that /ONLY causes a function to create a singular result from the series, while omitting the /ONLY causes a series to be "distributed" across all of the individual elements within the series. In other words, append block0 block1 appears to be an abbreviation of foreach item1 block1 [append block0 item1] or the slightly more baroque do head foreach item1 block1 [ insert append [block0] item1 [append] ] In addition, if we were lucky enough to notice the cryptic "now operates on negative values and tuples" in the Core 2.3 release notes for RANDOM, we might have tried some experiments (since there's no description that I could find for what it means for RANDOM to operate on tuples) and observed:
>> loop 6 [print random 4.16.64]
0.1.35 2.6.62 2.1.29 3.14.22 3.4.43 2.2.46 which seem to indicate that a whole tuple is returned, but that each component of the tuple is randomly selected within a range determined by the corresponding component of the original argument. In other words, given foo: 4.16.64 we see that random foo appears to be an abbreviation of
>> to-tuple reduce [random foo/1 random foo/2 random foo/3]
== 3.3.51 or the slightly more baroque
>> to-tuple repeat i length? foo [append [] random foo/:i]
== 1.7.61 and "tuple-hood" is passed from the argument to the result. So, observing from
>> loop 6 [print random/only [11 22 33 44 55 66]]
22 44 22 22 33 33 that RANDOM/ONLY treats the entire block as a set of legal values and returns a single randomly selected member, we might be led to infer that random blockval is an abbreviation of foreach item blockval [append [] random item] which "distributes" RANDOM across the elements of the block and produces a block of results (by direct analogy with the result for tuple values) where each element is chosen at random within a range set by the corresponding element of the original block. I'll stop belaboring the point, except to mention that if someone had suggested that there was a way to get RANDOM to shuffle the elements of a block, it might have been natural to assume that it would be random/all blockval by analogy with the /ALL refinement for PARSE, which says to treat all of the content values in a uniform fashion. Stupid Question #3: Is there any more effective way to find out what's going on with REBOL (and especially with new releases) other than trial and error? Every now and then, I get this nagging feeling that I'm stumbling around blindfolded in a dark room full of neat goodies, which I'll only find if I happen to stumble over each of them by accident. Or by asking stupid questions. -jn- ------------------------------------------------------------ Programming languages: compact, powerful, simple ... Pick any two! joel'dot'neely'at'fedex'dot'com

 [24/28] from: joel:neely:fedex at: 20-Jun-2001 15:28


Hi, nop, Hmmm... The REBOL equivalent of "Where's Waldo?" could be until [ find "jeff" foreach x head insert/dup "" "nop" 4 [ append "" to-char 32 + random x - 32 ] ] nop wrote:
> Huh, I could have sworn one of the changes docs listed at least > RANDOM/only... > I just didn't realize people didn't know about it. :-) >
Seriously, thanks for bringing it up. My apologies for sounding grumpy! I really would like to figure out some way to increase the bandwidth (and I don't mean to sound like I'm beating up on RT for not doing more!) For example... In REBOL/Zine/1 Carl referred to running regression tests after doing a new build. I assume that means there's a test suite evaluates a largish pile of expressions and verifies that each yields the expected value. Assuming that's true... If RT could make those tests available in some fashion, they would make a wonderful addition to the "use the source, Luke" story! If one wanted to know how a function was supposed to behave, the effect of a refinement, etc. one could look at (or run) the appropriate tests for a real-life "here's what we intended" sample. I'd be very happy to try to take some of the less obvious ones and write descriptions for what's going on and why, and I'm sure I'm not alone in that. The quid pro quo is that RT gives us (the community) a little more (existing) information, and we add value to it for RT and the community. I'd also be very happy to write additional tests, both for reference and regression purposes. I'm open to any other ideas that involve shared effort for common benefit (as long as I don't have to write anything in The Language That Must Not Be Named! ;-) -- It's turtles all the way down! joel'dot'neely'at'fedex'dot'com

 [25/28] from: whip:cs:unm at: 20-Jun-2001 9:22


Howdy, Joel:
> Stupid Question #1: > > How were we supposed to know about it?
Huh, I could have sworn one of the changes docs listed at least RANDOM/only. I know that I also posted that to the list because we were originally spurred on to add RANDOM/only when Andrew Martin sent in some block randomizing mezzanines. So I asked my "stupid question" because I was barging into a long thread, and I hadn't looked real closely to see if there was some reason why RANDOM block wasn't used. I just didn't realize people didn't know about it. :-)
> > Don't mean to lecture (-:, just think this is an important and > > powerful concept found in series that sometimes gets
<<quoted lines omitted: 4>>
> series-as-container-of-values is fairly well-established for many of > us.
Sure, Joel, I was putting my remarks about that for others. I'm sure you've got all that. :-)
> Stupid Question #2: > > How are we to figure out the sense of potentially ambiguous > refinements (or short verbal descriptions) without resorting to > trial and error?
I'm not sure. What would you suggest? Extending built-in help? Hopefully, the list of refinements you don't have direct experience with should be getting shorter every day. Perhaps make a script to spit out all functions with refinements, see which one's you haven't played with, post to the list weird ones, email feedback, get the president on the line. :-)
> random blockval > is an abbreviation of
<<quoted lines omitted: 3>>
> tuple values) where each element is chosen at random within a range > set by the corresponding element of the original block.
No, because the above isn't guaranteed to be equally distributed across the blocks contents. You could have duplicates.
> Stupid Question #3: > > Is there any more effective way to find out what's going on with > REBOL (and especially with new releases) other than trial and error?
See stupid answer to stupid question #2. :-) Hopefully RT will do a better job of keeping people informed of new stuff.
> Every now and then, I get this nagging feeling that I'm stumbling > around blindfolded in a dark room full of neat goodies, which I'll > only find if I happen to stumble over each of them by accident. Or > by asking stupid questions.
:-) The only stupid question is the one never asked. Sorry for any confusion or feelings of annoyance. (-: RANDOM [have a good day] -jeff

 [26/28] from: joel:neely:fedex at: 22-Jun-2001 15:02


Hi, Jeff/nop Just a minor clarification... nop wrote:
> > random blockval > >
<<quoted lines omitted: 9>>
> No, because the above isn't guaranteed to be equally distributed > across the blocks contents. You could have duplicates.
I wasn't saying that the above *is* the way RANDOM BLOCKVAL works, but rather that the above is the way one might have *expected* it to work, based on the facts that 1) The absence of /ONLY on APPEND etc. causes the APPENDing action to "distribute" across a second-argument block, and 2) The way RANDOM TUPLEVALUE works also "distributes" the RANDOM across individual elements (which does often create dups),
>> random 2.4.6.8 == 1.3.5.2 >> random 2.4.6.8 == 0.0.1.6 >> random 2.4.6.8 == 1.2.1.4 >> random 2.4.6.8 == 0.1.0.1
which I see as directly analogous to
>> map :random [2 4 6 8] == [1 2 5 1] >> map :random [2 4 6 8] == [2 3 2 7] >> map :random [2 4 6 8] == [1 4 5 6] >> map :random [2 4 6 8] == [2 2 6 4]
3) The fact that RANDOM TUPLEVALUE doesn't randomly reorder the elements of a tuple would have suggested that RANDOM BLOCKVALUE wouldn't randomly reorder the elements of a block (the other side of the coin from the previous point). I'm not trying to argue which specification for RANDOM BLOCKVALUE is correct (since the implementation is already done), but just to point out that there are *MANY* more options than two, therefore it takes more explanation than series as value vs. series as collection of values to clarify which of the possible options is implied by the presence or absence of /ONLY. It wasn't that I had never seen /ONLY before, but that all of my experience with it had led me to a different set of expectations. -jn- It's turtles all the way down! joel'dot'neely'at'fedex'dot'com

 [27/28] from: jeff:rebol at: 22-Jun-2001 13:37


Yes, REBOL breaks with consistency sometimes when not being consistent, for some reason, seems to make more sense, is more intuiative in the situation, or provides more utility, etc. I think these inconsistencies are not very abundant, though, but I see how that complicates the attempt to create a formal model. Very rigidly defined languages (like ML, eg.) have never really been my cup of tea. (-: -jeff

 [28/28] from: jeff:rebol at: 22-Jun-2001 7:49


Howdy, Joel:
> If RT could make those tests available in some fashion, > they would make a wonderful addition to the "use the > source, Luke" story! If one wanted to know how a function > was supposed to behave, the effect of a refinement, etc. > one could look at (or run) the appropriate tests for a > real-life "here's what we intended" sample.
Hmm.. publish the test suite? I think your reasoning and objectives are great, but my views wrt the current REBOL test suite are a bit conflicted. The suite is.. um.. how can I say it.. perhaps not an adequate reference for describing REBOL -- maybe some parts of it are... hmm.. lemme do some poking around and return to this topic soon. -jeff

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted