How to divide multiple shapes in Paper.js like in Illustrator with Pathfinder - paperjs

I have multiple overlapping squares in Paper.js, and I'd like to separate all the overlapping shapes into their own. You can do exactly this in Illustrator with the pathfinder divide. Before I attempt to just loop through all overlapping shapes and divide them with each other with what might have to be some nested loops I think, I'm wondering if there's a better way.
Example in Illustrator
I want to turn all these squares:
https://i.imgur.com/PPRi9M9.png
into pieces like this
https://i.imgur.com/xTFS8jP.png
(moved the pieces away from each other so you can see how they're separated)

I ended up going with my own solution which sounded more practical and simple than #arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.
Here's my actual code I'm using in my project with comments.
setupGrid() {
// Setup block row and column positions
for (let i = 0;i < this.total;i++) {
let x
let y
if (!odd(i)) {
x = firstColumnStartX + (this.size/2)
y = firstColumnStartY + ((i/2) * (this.size + this.gap)) + (this.size/2)
} else {
x = secondColumnStartX + (this.size/2)
y = secondColumnStartY + (Math.floor(i/2) * (this.size + this.gap)) + (this.size/2)
}
this.blocks.push(new paper.Path.Rectangle({
position: [x, y],
size: this.size,
strokeColor: '#ff000050'
}))
}
// Setup array to check what blocks are intersecting
const intersects = []
// Setup empty array with a nested array mapped to other blocks [5 x [5 x undefined]]
for (let i = 0;i < this.total;i++) {
intersects[i] = new Array(this.total).fill(undefined)
}
// Intersect checking
for (let i = 0;i < this.total;i++) {
const block = this.blocks[i]
for (let _i = 0;_i < this.total;_i++) {
const otherBlock = this.blocks[_i]
if (block !== otherBlock && intersects[i][_i] === undefined) {
intersects[_i][i] = intersects[i][_i] = block.intersects(otherBlock)
}
}
}
// First loop through all blocks
for (let i = 0;i < this.total;i++) {
let block = this.blocks[i]
// Then loop through other blocks only if they were intersected with the original block
for (let _i = 0;_i < this.total;_i++) {
const otherBlock = this.blocks[_i]
if (intersects[i][_i]) {
/* divide returns {
pieces: array of separated pieces that would be inside the original block's boundaries
leftoverBlock: what's leftover of the other block if the original block was subtracted from it
} */
const divide = this.divide(block, otherBlock)
block.remove()
otherBlock.remove()
// Override current block with the array of pieces
block = this.blocks[i] = divide.pieces
// Override other block with leftover
this.blocks[_i] = divide.leftoverBlock
// Don't let other block divide with original block since we already did it here
intersects[_i][i] = undefined
}
}
}
// Set random color for each piece to check if successful
for (let i = 0;i < this.blocks.length;i++) {
let block = this.blocks[i]
if (block instanceof Array) {
for (let _i = 0;_i < block.length;_i++) {
block[_i].fillColor = new paper.Color(Math.random(), Math.random(), Math.random(), 0.1)
}
} else {
block.fillColor = new paper.Color(Math.random(), Math.random(), Math.random(), 0.1)
}
}
}
// Divide blockA with blockB and expand
divideBlocks(blockA, blockB, pieces = []) {
const divideA = blockA.divide(blockB)
if (divideA instanceof paper.CompoundPath) {
for (let i = divideA.children.length;i--;) {
const child = divideA.children[i]
child.insertAbove(divideA)
pieces.push(child)
}
divideA.remove()
} else {
pieces.push(divideA)
}
return pieces
}
// Divide group (array of paths) with divider
divideGroup(children, divider, pieces = [], parent) {
for (let i = children.length;i--;) {
const child = children[i]
if (parent) {
child.insertAbove(parent)
}
if (child.intersects(divider)) {
this.divideBlocks(child, divider, pieces)
} else {
pieces.push(child)
}
}
}
// Subtract group (array of paths) from block
subtractGroupFromBlock(block, group) {
let oldBlock
let newBlock = block
for (let i = group.length;i--;) {
const child = group[i]
if (child.intersects(block)) {
newBlock = newBlock.subtract(child)
if (oldBlock) {
oldBlock.remove()
}
oldBlock = newBlock
}
}
return newBlock
}
// Check what kind of divide method to use
divide(blockA, blockB) {
const pieces = []
let leftoverBlock
if (blockA instanceof paper.Path) {
this.divideBlocks(blockA, blockB, pieces)
leftoverBlock = blockB.subtract(blockA)
} else if (blockA instanceof Array) {
this.divideGroup(blockA, blockB, pieces)
leftoverBlock = this.subtractGroupFromBlock(blockB, blockA)
}
return {
pieces,
leftoverBlock
}
}
My blocks set with random colors to differentiate each shape:
Overlapping blocks before:
https://i.imgur.com/j9ZSUC5.png
Overlapping blocks separated into pieces:
https://i.imgur.com/mc83IH6.png

Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.
Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.
Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.
You could also use Path.intersect(path[, options]) but I don't think it would help you.

Related

How to use minimax alalgorithm without recursion?

I'm developing a program that people can play "tic tac toe" with a computer.
I choose structured text as my develop language, but it doesn't have recursion, so I have to develop it without recursion.
As the result, I decide to use the stack to instead, but I don't know how to change recursion into the stack.
I try to use stack like BFS, and also I wanna that minimax can make the best move.
I don't know Structured Text, but maybe it helps to see a solution in another language.
You need a stack with moves, so that when backtracking, you know from where to start to search for a next, alternative move for it.
You also need a stack of scores, so you know the best score so far at every depth of the minimax search tree.
The two stacks could be combined into one stack when you can store the two data in one structure to be placed on the single stack. But in the below implementation in JavaScript I have tried to keep the data structures as simple as possible and used two stacks (fix-sized arrays with a separate size variable). All variables are declared at the top of the functions (as in Structured Text), and return statements are always at the end of the function bodies (since there is no return statement in Structured Text).
function gameWon(board) {
/* Looks at all possible lines of 3,
* to see if they are occupied by three of the same symbols
* board: is a 1D array with 9 integers:
* 1 = "X" (first player), 0 = free, 1 = "O"
* Returns boolean.
*/
let value;
let i;
// In Structured Text you'd not have gameWonReturn,
// as you would use `gameWon` instead for returning a value
let gameWonReturn = false;
for (i = 0; i < 3; i++) {
value = board[i*3];
if (value != 0 && value == board[i*3+1] && value == board[i*3+2]) {
gameWonReturn = true;
break;
}
value = board[i];
if (value != 0 && value == board[i+3] && value == board[i+6]) {
gameWonReturn = true;
break;
}
if (value != 0 && value == board[4] && value == board[8-i]) {
gameWonReturn = true;
break;
}
}
return gameWonReturn;
}
function play(board, moveStack, moveCount, move) {
let playReturn;
// Derive played symbol from number of moves played
board[move] = 1 - (moveCount % 2) * 2; // Use MOD operator. Result is 1 or -1
moveStack[moveCount] = move; // Log move in stack
playReturn = moveCount + 1;
return playReturn;
}
function minimax(board, moveStack, moveCount) {
const scoreStack = Array(10); // Array of signed integers
const originalMoveCount = moveCount;
let move; // -1..9
let score; // -10..10
let player; // -1 or 1
let minimaxReturn = -1; // -1..9
while (true) {
// Current player can be derived from the number of moves that were played
player = 1 - (moveCount % 2) * 2; // 1 = First, maximizing player. -1 = Second, minimizing player
// Check for game-over
if (gameWon(board)) { // Preceding move resulted in win for previous player
scoreStack[moveCount] = -(10 - moveCount) * player; // Earlier wins get greater score
} else if (moveCount == 9) { // It's a draw
scoreStack[moveCount] = 0;
} else {
moveStack[moveCount] = -1; // Prepare for iterating moves for current player
scoreStack[moveCount] = -player * 10; // Initialize with worst possible score for current player
moveCount++;
}
do { // Repeat:
moveCount--;
if (moveCount < originalMoveCount) { // All done
break; // Exit point
}
// Look for a next, valid move
move = moveStack[moveCount];
if (move >= 0) { // Was a valid move: derive score from deeper results
score = scoreStack[moveCount + 1]; // Best score opponent can get
if ((board[move] == 1) == (score > scoreStack[moveCount])) { // Improvement
scoreStack[moveCount] = score;
if (moveCount == originalMoveCount) {
minimaxReturn = move; // For now this is a best move...
}
}
// Take back move
board[move] = 0;
}
// Look for next valid move
do {
move++;
} while (move < 9 && board[move] != 0) // Occupied
} while (move == 9); // Backtrack (i.e. repeat loop) when all moves were tried
if (moveCount < originalMoveCount) { // All done
break; // Exit point
}
// Play move
moveCount = play(board, moveStack, moveCount, move);
}
return minimaxReturn;
}
function main() {
const board = Array(9).fill(0); // An empty 3x3 board as 1 dimensional array
const moveStack = Array(10); // History of played moves (indices in board)
let moveCount = 0; // Number of moves played
let bestMove;
/* Demo:
* Play moves to arrive at this board:
*
* X | O |
* ---+---+---
* O | |
* ---+---+---
* X | |
*/
moveCount = play(board, moveStack, moveCount, 0); // Play X in top-left
moveCount = play(board, moveStack, moveCount, 1); // Play O next to it
moveCount = play(board, moveStack, moveCount, 6); // Play X in bottom-left
moveCount = play(board, moveStack, moveCount, 3); // Play O in middle row
// Run minimax for suggesting where to play an "X":
bestMove = minimax(board, moveStack, moveCount);
console.log(bestMove); // 4 (center of the board)
}
main();

How to properly backtrack in Depth First Search Algorithm?

I am trying to solve a problem which is: Find all ancestors of a particular node in a binary tree.
Input: root, targetNode
Output: An array/list containing the ancestors
Suppose, we have the above binary tree as an example. We want to find the ancestors of the node 4. The output should be [3, 5, 2, 4]. If the node is 8, the output is [3, 1, 8]
To solve this, I have written a function which implements DFS.
var ancestor = function(root, target) {
var isFound = false;
const dfs = (node, curr) => {
if (node === null) {
return curr;
}
if (node.val === target.val) {
curr.push(node.val);
isFound = true;
return curr;
}
curr.push(node.val);
const left = dfs(node.left, curr);
if (!isFound) {
const right = dfs(node.right, curr);
curr.pop();
return right;
} else {
curr.pop();
return left;
}
}
console.log(dfs(root, []));
};
But it is not returning the correct ouput. For example, if the targetNode is 7, the output is [3], if the targetNode is 8, the output is also [3]. If I remove the line curr.pop() the output is also invalid. for targetNode 7 it is [3 , 5, 6, 2, 7]. I think I found the issue where I am making mistake. While backtracking, I am doing something wrong with the remove of the node that was pushed in the curr array. If I pass a string instead of the array, it prints the output correctly.
var ancestor = function(root, target) {
var isFound = false;
const dfs = (node, curr) => {
if (node === null) {
return curr;
}
if (node.val === target.val) {
curr += node.val;
isFound = true;
return curr;
}
const left = dfs(node.left, curr + node.val + '->);
if (!isFound) {
const right = dfs(node.right, curr + node.val + '->);
return right;
} else {
return left;
}
}
console.log(dfs(root, ''));
The above code with string instead of array prints the output correctly, If I pass targetNode 7, output is 3->5->2->7
My question is, how to properly unchoose/backtrack here? Or is there anything else that I am doing incorrectly? Thanks in advance.
recursion in its natural setting
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding imperative things such as mutations like push and cur += node.val, variable reassignments like isFound = true, and other side effects. We can write ancestor as a simple generator-based function that prepends each node to the output of recursive sub-problem -
const empty =
Symbol("tree.empty")
function node(val, left = empty, right = empty) {
return { val, left, right }
}
function* ancestor(t, q) {
if (t == empty) return
if (t.val == q) yield [t.val]
for (const l of ancestor(t.left, q)) yield [t.val, ...l]
for (const r of ancestor(t.right, q)) yield [t.val, ...r]
}
const mytree =
node(3, node(5, node(6), node(2, node(7), node(4))), node(1, node(0), node(8)))
for (const path of ancestor(mytree, 7))
console.log(path.join("->"))
3->5->2->7
use modules
To finish, I would recommend a module-based approach for this code -
// tree.js
const empty =
Symbol("tree.empty")
function node(val, left = empty, right = empty) {
return { val, left, right }
}
function* ancestor(t, q) {
if (t == empty) return
if (t.val == q) yield [t.val]
for (const l of ancestor(t.left, q)) yield [t.val, ...l]
for (const r of ancestor(t.right, q)) yield [t.val, ...r]
}
function insert(t, val) {
// ...
}
function remove(t, val) {
// ...
}
function fromArray(a) {
// ...
}
// other tree functions...
export { empty, node, ancestor, insert, remove, fromArray }
// main.js
import { node, ancestor } from "./tree.js"
const mytree =
node(3, node(5, node(6), node(2, node(7), node(4))), node(1, node(0), node(8)))
for (const path of ancestor(mytree, 7))
console.log(path.join("->"))
3->5->2->7
private generator
In the previous implementation, our module exposes a generator for ancestor's public interface. Another option is to return undefined when a node cannot be found and has no ancestry. Consider this alternate implementation which hides the generator and requires the caller to null-check the result instead -
const empty =
Symbol("tree.empty")
function node(val, left = empty, right = empty) {
return { val, left, right }
}
function ancestor(t, q) {
function* dfs(t) {
if (t == empty) return
if (t.val == q) yield [t.val]
for (const l of dfs(t.left)) yield [t.val, ...l]
for (const r of dfs(t.right)) yield [t.val, ...r]
}
return Array.from(dfs(t))[0]
}
const mytree =
node(3, node(5, node(6), node(2, node(7), node(4))), node(1, node(0), node(8)))
const result =
ancestor(mytree, 7)
if (result)
console.log(result.join("->"))
else
console.log("no result")
3->5->2->7
You need to check whether the DFS of the right child has found the node.
fix:
const left = dfs(node.left, curr);
if (!isFound) {
const right = dfs(node.right, curr);
if(isFound) {
return right;
}
curr.pop();
return; // return nothing, backtracking
}
return left;
In the array example, your loop iterates through the nodes in a DFS manner, so each of those nodes are connected in that manner. If we count the tree nodes in DFS algorithm, [3 , 5, 6, 2, 7] are actually in order 1, 2, 3, 4 and 5. In this manner, your whole tree in an array should be looking like this; [3 , 5, 6, 2, 7, 4, 1, 0, 8].
So when you find the target value, you pop from the current node and trace it all back up to the head node in DFS algorithm.
I'd either suggest finding a way to get around that, or you could save each of these node's parents. Meaning you could use tuples instead of int arrays (if that's acceptable). An index could look like this = (node value, parent value)
[(3,NULL),(5,3),(6,5),(2,5)...]
And then traceback accordingly...

Sensible way to encode user defined sort-order in back end database?

I have a series of "rows" in a collection which are persisted to a nosql database (in this case Firestore). Each one of my rows has a sort order which is established when the user adds, inserts, copies or moves rows with the collection. The insertion point into which a user may insert new records is arbitrary. The sort order is persisted to the backend, and can be retrieved ordered by the sort order field. There may be a large number of rows in the collection, on the order 50K.
The question what is the sort order encoding format that would permit repeated insertion of new records between existing records, without having to occasionally rewrite the sort index of the entire collection to provide "space" in the sort order between adjacent records.
I'm guessing there may some standard way to achieve this, but not sure what it is.
Assume the alphabet is "abc". Then:
b, c, cb...
is a lexicographically sorted list that allows you to insert items anywhere:
ab, b, bb, c, cab, cb, cbb...
And the result is still a list that allows you to insert items anywhere:
aab, ab, ac, b, bab, bb, bc, c, caab, cab, cac, cb, cbab, cbb, cbbb...
The trick is to avoid having "a" as the last character of an item, so that you can always put items behind others.
Do this with 64 ASCII characters instead of 3.
I've been thinking about this for quite a few months. This is my progress so far in implementing it. It still has some flaws and it's a little bit of a mess, but I guess I'll clean it and upload it at npm when I find more time.
// Originally written in TypeScript, then removed the types for SO.
const alphabet = 'abc';
function getHigherAsciiChar(char) {
const index = alphabet.indexOf(char);
if (index === alphabet.length - 1) {
return ''; // sorry, there's no higher character
}
const nextIndex = Math.ceil((index + alphabet.length - 1) / 2);
return alphabet.charAt(nextIndex);
}
function getCharBetween(minChar, maxChar) {
if (minChar > maxChar) {
throw new Error('minChar > maxChar, ' + minChar + ' > ' + maxChar);
}
const minIndex = alphabet.indexOf(minChar);
const maxIndex = alphabet.indexOf(maxChar);
const nextIndex = Math.floor((minIndex + maxIndex) / 2);
if (nextIndex === minIndex) {
return ''; // there is no character between these two
}
return alphabet.charAt(nextIndex);
}
function getPaddedString(finalLength, string) {
let result = string;
while (result.length < finalLength) {
result += alphabet.charAt(0);
}
return result;
}
function getOrderString(bounds) {
const console = { log: () => {} }; // uncomment this to log debug stuff
if (!bounds.previous && !bounds.next) {
return getHigherAsciiChar(alphabet[0]);
}
const previousString = bounds.previous || '';
if (!bounds.next) {
const firstPreviousChars = previousString.substr(0, previousString.length - 1);
const lastPreviousChar = previousString.charAt(previousString.length - 1);
return firstPreviousChars + (
getHigherAsciiChar(lastPreviousChar) || (
lastPreviousChar + getHigherAsciiChar(alphabet.charAt(0))
)
);
}
const nextString = bounds.next;
console.log(`Searching between '${previousString}' and '${nextString}'...`);
const bigStringLength = Math.max(previousString.length, nextString.length);
const previous = getPaddedString(bigStringLength, previousString);
const next = getPaddedString(bigStringLength, nextString);
console.log(previous, next);
let result = '';
let i;
for (i = 0; i < bigStringLength; i++) {
const previousChar = previous.charAt(i);
const nextChar = next.charAt(i);
// keep adding common characters
if (previousChar === nextChar) {
result += previousChar;
console.log(result, 'common character');
continue;
}
// when different characters are reached, try to add a character between these two
const charBetween = getCharBetween(previousChar, nextChar);
if (charBetween) {
result += charBetween;
console.log(result, 'character in-between. RETURNING');
// and you're done
return result;
}
// if there was no character between these two (their distance was exactly 1),
// repeat the low character, forget about the upper bound and just try to get bigger than lower bound
result += previousChar;
console.log(result, 'the lower character so we can forget about high bound');
i++;
break;
}
for (; previousString >= result; i++) {
const previousChar = previous.charAt(i);
const higherChar = getHigherAsciiChar(previousChar);
if (higherChar) {
// you found a digit that makes your result greater than the lower bound. You're done.
result += higherChar;
console.log(result, 'a higher character. RETURING');
return result;
}
// the digits are still very close, can't find a digit in-between (yet)
result += previousChar;
console.log(result, 'moving on to next digit');
}
// so you end up depleting all the character slots from the lower bound. Meh, just add any character.
result += getHigherAsciiChar(alphabet.charAt(0));
console.log(result, 'meh, just add any character. RETURNING');
return result;
}
function interleaveTest(order) {
const newOrder = [];
newOrder.push(getOrderString({ next: order[0] }));
for (let i = 0; i < order.length - 1; i++) {
newOrder.push(order[i]);
newOrder.push(getOrderString({ previous: order[i], next: order[i + 1] }));
}
newOrder.push(order[order.length - 1]);
newOrder.push(getOrderString({ previous: order[order.length - 1] }));
return newOrder;
}
let order = ['c'];
console.log('\n' + order.join(', ') + '\n');
order = interleaveTest(order);
console.log('\n' + order.join(', ') + '\n');
order = interleaveTest(order);
console.log('\n' + order.join(', ') + '\n');
order = interleaveTest(order);
console.log('\n' + order.join(', ') + '\n');
let atEnd = ['b'];
for (let i = 0; i < 10; i++) {
atEnd.push(getOrderString({ previous: atEnd[atEnd.length - 1] }));
}
console.log('\nat end: ' + atEnd.join(', ') + '\n');

Select symbol definition path

I need to view the segments and handles of the path that defines a SymbolItem. It is a related issue to this one but in reverse (I want the behavior displayed on that jsfiddle).
As per the following example, I can view the bounding box of the SymbolItem, but I cannot select the path itself in order to view its segments/handles. What am I missing?
function onMouseDown(event) {
project.activeLayer.selected = false;
// Check whether there is something on that position already. If there isn't:
// Add a circle centered around the position of the mouse:
if (event.item === null) {
var circle = new Path.Circle(new Point(0, 0), 10);
circle.fillColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
var circleSymbol = new SymbolDefinition(circle);
multiply(circleSymbol, event.point);
}
// If there is an item at that position, select the item.
else {
event.item.selected = true;
}
}
function multiply(item, location) {
for (var i = 0; i < 10; i++) {
var next = item.place(location);
next.position.x = next.position.x + 20 * i;
}
}
Using SymbolDefinition/SymbolItem prevent you from changing properties of each symbol items.
The only thing you can do in this case is select all symbols which share a common definition.
To achieve what you want, you have to use Path directly.
Here is a sketch showing the solution.
function onMouseDown(event) {
project.activeLayer.selected = false;
if (event.item === null) {
var circle = new Path.Circle(new Point(0, 0), 10);
circle.fillColor = Color.random();
// just pass the circle instead of making a symbol definition
multiply(circle, event.point);
}
else {
event.item.selected = true;
}
}
function multiply(item, location) {
for (var i = 0; i < 10; i++) {
// use passed item for first iteration, then use a clone
var next = i === 0 ? item : item.clone();
next.position = location + [20 * i, 0];
}
}

how to make href random button go to ID tag [duplicate]

This question already has answers here:
Getting a random value from a JavaScript array
(28 answers)
Closed 7 years ago.
var items = Array(523, 3452, 334, 31, ..., 5346);
How do I get random item from items?
var item = items[Math.floor(Math.random()*items.length)];
1. solution: define Array prototype
Array.prototype.random = function () {
return this[Math.floor((Math.random()*this.length))];
}
that will work on inline arrays
[2,3,5].random()
and of course predefined arrays
var list = [2,3,5]
list.random()
2. solution: define custom function that accepts list and returns element
function get_random (list) {
return list[Math.floor((Math.random()*list.length))];
}
get_random([2,3,5])
Use underscore (or loDash :)):
var randomArray = [
'#cc0000','#00cc00', '#0000cc'
];
// use _.sample
var randomElement = _.sample(randomArray);
// manually use _.random
var randomElement = randomArray[_.random(randomArray.length-1)];
Or to shuffle an entire array:
// use underscore's shuffle function
var firstRandomElement = _.shuffle(randomArray)[0];
If you really must use jQuery to solve this problem (NB: you shouldn't):
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
var items = [523, 3452, 334, 31, ..., 5346];
var item = jQuery.rand(items);
This plugin will return a random element if given an array, or a value from [0 .. n) given a number, or given anything else, a guaranteed random value!
For extra fun, the array return is generated by calling the function recursively based on the array's length :)
Working demo at http://jsfiddle.net/2eyQX/
Here's yet another way:
function rand(items) {
// "~~" for a closest "int"
return items[~~(items.length * Math.random())];
}
Or as recommended below by #1248177:
function rand(items) {
// "|" for a kinda "int div"
return items[items.length * Math.random() | 0];
}
var random = items[Math.floor(Math.random()*items.length)]
jQuery is JavaScript! It's just a JavaScript framework. So to find a random item, just use plain old JavaScript, for example,
var randomItem = items[Math.floor(Math.random()*items.length)]
// 1. Random shuffle items
items.sort(function() {return 0.5 - Math.random()})
// 2. Get first item
var item = items[0]
Shorter:
var item = items.sort(function() {return 0.5 - Math.random()})[0];
Even shoter (by José dB.):
let item = items.sort(() => 0.5 - Math.random())[0];
var rndval=items[Math.floor(Math.random()*items.length)];
var items = Array(523,3452,334,31,...5346);
function rand(min, max) {
var offset = min;
var range = (max - min) + 1;
var randomNumber = Math.floor( Math.random() * range) + offset;
return randomNumber;
}
randomNumber = rand(0, items.length - 1);
randomItem = items[randomNumber];
credit:
Javascript Function: Random Number Generator
If you are using node.js, you can use unique-random-array. It simply picks something random from an array.
An alternate way would be to add a method to the Array prototype:
Array.prototype.random = function (length) {
return this[Math.floor((Math.random()*length))];
}
var teams = ['patriots', 'colts', 'jets', 'texans', 'ravens', 'broncos']
var chosen_team = teams.random(teams.length)
alert(chosen_team)
const ArrayRandomModule = {
// get random item from array
random: function (array) {
return array[Math.random() * array.length | 0];
},
// [mutate]: extract from given array a random item
pick: function (array, i) {
return array.splice(i >= 0 ? i : Math.random() * array.length | 0, 1)[0];
},
// [mutate]: shuffle the given array
shuffle: function (array) {
for (var i = array.length; i > 0; --i)
array.push(array.splice(Math.random() * i | 0, 1)[0]);
return array;
}
}

Resources