### oneOf.js Copyright (c) 2015 Bruno Dias Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ### ### Undularity Tools Those functions are not a core part of Undularity, but provide some general functionality that relates to adaptive text generation. This is provided partly as a helper to less technical users, and as a convenience for authors. ### # Monkey patching ### Shuffles an array. It can use Undum's random number generator implementation, so it expects a System.rnd object to be passed into it. If one isn't supplied, it will use Math.Random instead. This is an implementation of the Fischer-Yates (Knuth) shuffle. Returns the shuffled array. ### Array.prototype.shuffle = () -> # slice() clones the array. Object members are copied by reference, beware. newArr = this.slice() m = newArr.length while (m) i = Math.floor(salet.rnd.randf() * m--) t = newArr[m] newArr[m] = newArr[i] newArr[i] = t return newArr ### oneOf() Takes an array and returns an object with several methods. Each method returns an iterator which iterates over the array in a specific way: inOrder() Returns the array items in order. cycling() Returns the array items in order, cycling back to the first item when it runs out. stopping() Returns the array items in order, then repeats the last item when it runs out. randomly() Returns the array items at random. Takes a system object, for consistent randomness. Will never return the same item twice in a row. trulyAtRandom() Returns the array items purely at random. Takes a system object, for consistent randomness. inRandomOrder() Returns the array items in a random order. Takes a system object, for consistent randomness. ### ### Takes a function and gives it a toString() property that calls itself and returns its value, allowing for ambiguous use of the closure object as a text snippet. Returns the modified function. ### stringish = (callback) -> callback.toString = () -> return '' + this.call() return callback oneOf = (ary...) -> if ary.length == 0 throw new Error( "tried to create a oneOf iterator with a 0-length array"); return { inOrder: () -> i = 0 return stringish(() -> if i >= ary.length return null return ary[i++] ) cycling: () -> i = 0 return stringish(() -> if (i >= ary.length) i = 0 return ary[i++] ) stopping: () -> i = 0 return stringish(() -> if (i >= ary.length) i = ary.length - 1 return ary[i++] ) randomly: (system) -> last = null if (ary.length<2) throw new Error("attempted to make randomly() iterator with a 1-length array") return stringish( () -> i = null offset = null if not last? i = Math.floor(salet.rnd.randf() * ary.length) else ### Let offset be a random number between 1 and the length of the array, minus one. We jump offset items ahead on the array, wrapping around to the beginning. This gives us a random item other than the one we just chose. ### offset = Math.floor(salet.rnd.randf() * (ary.length -1) + 1) i = (last + offset) % ary.length last = i return ary[i] ) trulyAtRandom: (system) -> return stringish(() -> return ary[Math.floor(salet.rnd.randf() * ary.length)]; ) inRandomOrder: (system) -> shuffled = ary.shuffle(system) i = 0 return stringish(() -> if (i >= ary.length) i = 0 return shuffled[i++] ) } Array.prototype.oneOf = () -> oneOf.apply(null, this) String.prototype.oneOf = () -> return this