xxxxxxxxxx
64
// Background:
// https://en.wikipedia.org/wiki/Tower_of_Hanoi
/*
Syntax:
towerMoves(n)
towerMoves(n, s, t)
Parameters:
// n: number of rings (1, 2, 3, ...)
// s: source peg (1, 2, or 3), defaulting to 1
// t: target peg (1, 2, or 3), defaulting to 3
Return value:
Optimal sequence of moves to solve Tower of Hanoi puzzle (Array)
Example:
The sequence [[1, 2], [1, 3], [2, 3]] means
"move ring at top of peg 1 to peg 2," then
"move ring at top of peg 1 to peg 3," then
"move ring at top of peg 2 to peg 3."
*/
function towerMoves(n, s = 1, t = 3) {
const pegs = [1, 2, 3];
// intermediate peg (not source or target)
const i = pegs.find(peg => (peg !== s) && (peg !== t));
return n === 1 ?
[[s, t]] :
towerMoves(n - 1, s, i).concat([[s, t]], towerMoves(n - 1, i, t));
}
/*
* Alternative:
* altTowerMoves(n)
* altTowerMoves(n, s, t, i)
*
* The difference is that, if non-default pegs are used,
* then all three pegs need to be specified.
*
* For example, altTowerMoves(2, 1, 2, 3) returns the same value as
* towerMoves(2, 1, 2). In each case, two rings are moved from source
* peg 1 to target peg 2, using peg 3 as an intermediate peg.
*
* A cost of the alternative implementation is that the user
* needs to pass in data that could be determined automatically.
* A benefit is that the implementation is simpler.
*
* Also, the alternative implementation uses n = 0 as a base case
* instead of n = 1, to show that this is possible.
*/
function altTowerMoves(n, s = 1, t = 3, i = 2) {
return n === 0 ?
[] :
towerMoves(n - 1, s, i, t).concat([[s, t]],towerMoves(n - 1, i, t, s));
}
// tests
console.log(towerMoves(3));
console.log(altTowerMoves(3));
console.log(towerMoves(2, 1, 2));
console.log(altTowerMoves(2, 1, 2, 3));