drawing names, take 2
It turns out, the consummate dunce who originally posted the Perl code mentioned in my previous post (and whose code I used as a model to write mine) was thoughtful enough to include the possibility of infinite recursion in some cases.
Suppose you have drawn n - 2 names, and Ann and Bill still need gift-recipients; Curtis The Dunce and Bill are the names in the hat. So, Ann reaches in and gets Curtis. (Of course, he is a bad little boy who won’t get any presents. But that’s another story.) Then Bill chooses… well, duh. Problem. This is the bug in Perl-boy’s code.
As a public service, I have updated my code to eliminate this possibility. Enjoy your bug-free gift-name-drawing.
(* Draw randomly-selected names for each person in `nameList'. *)structure DrawNames = structlocaltype match = {name: string, match: string}
(* Set of strings. *)structure S = BinarySetFn(type ord_key = string val compare = String.compare)
(* List of all names. *)val nameList = ["Denis", "Lisa", "Dave", "Beth", "Tim", "Emma"]val names = S.addList (S.empty, nameList)
(* For the random-number generator seed. This seed is only sufficient. *)fun getpid () = SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ()))fun now () = let val time = Time.toMilliseconds (Time.now ()) val time' = case Int.maxInt of NONE => time | SOME x => LargeInt.mod (time, Int.toLarge x) in Int.fromLarge time' end
in
(* Match up all the names. *)fun match () = let val seed = Random.rand (now (), getpid ()) fun randomElt l = List.nth (l, (Random.randRange (0, (length l) - 1) seed)) fun getName set = randomElt (S.listItems set) fun getNameExcluding (excl, set) = randomElt (S.listItems (S.difference (set, S.singleton excl)))
(* Find a match for the given `name'. *) fun findMatch (mapFrom, mapTo, matches) = if S.isEmpty mapFrom then matches else let val name = getName mapFrom val match = getNameExcluding (name, mapTo) val mapFrom' = S.delete (mapFrom, name) val mapTo' = S.delete (mapTo, match) (* If the only choice is to map to oneself, we made the * wrong choice: try again. *) in if S.numItems mapFrom' = 1 andalso S.equal (mapFrom', mapTo') then findMatch (mapFrom, mapTo, matches) else findMatch (mapFrom', mapTo', {from=name, to=match} :: matches) end fun printMatch {from, to} = print (from ^ " -> " ^ to ^ "\n")
val matches = findMatch (names, names, []) in app printMatch matches end
end (* local *)end (* struct *)
7 Comments »
Leave a comment
-
Archives
- November 2009 (1)
- July 2009 (1)
- March 2009 (2)
- July 2008 (1)
- May 2008 (1)
- April 2008 (1)
- March 2008 (1)
- February 2008 (1)
- October 2007 (1)
- August 2007 (1)
- July 2007 (2)
- April 2007 (4)
-
Categories
-
RSS
Entries RSS
Comments RSS
I see a lot of words … but does it mean anything?
Oh, btw, go back to my Perl post … read the comments.
Oh, fraptuous day! My gift-drawing script will work now!
Callooh! Callay!
And, though it’s nonsense-speak, and thus probably doesn’t matter: it’s “frabjous”.
Curtis,
Pretty nifty about Randal Schwartz reading your code. I noticed that the version that you wrote looks *nothing like* what he came up with. I guess that tells you something.
Yeah … I even gave him credit though. splice() is pretty neat … with it’s 3-argument version. However, he didn’t solve the infinite recursion problem … which, of course, was about a 20 second ordeal. I could have made it look more like my first version with approximately the same number of lines of code, but, I did like his ideas better. Besides, he bloody wrote the Perl book. Who in his right mind would pass up advice on that level?
Actually, fraptuous was the verification word that I had to enter to comment. Or not. I was subconsciously mixing rapturous and frabjous, I’m sure.
That being the case, I just want to say, lmamenz!