21 counting game (like nim game) - javascript

I'd like to develop a bot that is able to win the 21 - counting game/NIM - game every time.
Rules: Here are the rules for the game:
In a game players take it in turns to say up to 3 numbers (starting at 1 and working their way up).
Who every say's the number 21 is eliminated.
Strategie: Winning the game ever time is possible if you know the right strategy How to win?
Continuing on, if you say 12 you win
if you say 9, you win,
if you say 6, you win,
if you say 3, you win
So, if you go second, you can guarantee that you will say 3, and win every time.
My question: I'd like to create a bot using javascript that is able to beat the user.
let _ = function(call, int) {
setTimeout(call, int)
}
class game {
constructor() {
this.number = 1;
}
user(val) {
console.log(`Userinput: +${val}`)
for (let i=0; i<val; i++)
console.log(`number: ${this.number++}`)
this.checkWin("bot")
console.log("\n\n\n")
this.bot()
}
bot() {
let val = (this.number === 3) ? 3 : parseInt(Math.random()*2)+1
console.log(`Botinput: +${val}`)
for (let i=0; i<val; i++)
console.log(`number: ${this.number++}`)
this.checkWin("user")
console.log("\n\n\n")
}
checkWin(looser) {
if (this.number >= 21) {
console.log(`${looser} lost the game.`);
}
}
}
let instance = new game()
_(function() {
instance.user(3)
},0)
_(function() {
instance.user(2)
},100)
_(function() {
instance.user(3)
},200)
_(function() {
instance.user(3)
},300)
_(function() {
instance.user(1)
},400)
Note: I did not finished the development but obviously there are some issues. I would really appreciate if somebody is able to help me finding/fixing them.

To solve a nim game we calculate the nimbers:
the losing state has nimber 0
the rest of the nimbers is calculated by looking at all the reachable states and taking the mex (minimal exclusive) which is the smallest missing number in the sequence of 0, 1, 2, 3, ...
nimber(21) = 0
nimber(20) = 1, only 0 can be reached, so 1 is the mex
nimber(19) = 2, 0 and 1 can be reached within one move, so mex is 2
nimber(18) = 3
nimber(17) = 0, because we can reach 1 to 3, so 0 is the smallest missing number
and so on...
It is easy to see, that it is repeating. So we can calculate the nimber like this (n is the current state): 3 - (n + 2) % 4. Or generalized if we can count up to x numbers and the losing number is y: we want to add z to y, so that (y + z) % (x + 1) = x and then the formula is x - (n + z) % (x + 1). We could also say that y % (x + 1) + z = x (to find the smallest non-negative z, the other formula has an infinite amount of solutions for z), so z = x - y % (x + 1).
So if the nimber of a state is not 0, the winning move is the one going to the next losing state with nimber 0. As it turns out the winning move (how many numbers to count) is exactly equal to the nimber.
It is important to note, that 21 denotes the state when 20 was said, 21 itself wasn't said yet.
It gets interesting when we play with several instances, like having cards numbered from 1 to 21 in several stacks where you can draw 1 to 3 of the lowest cards in a stack. The one taking the very last card loses. Here we can just xor the nimbers of all stacks, if it is 0 we are in a losing state, otherwise there is a winning move.

Related

What is wrong in this knapsack problem solution?

I understand that this is more of a problem solving than a coding question as such, so my apologies if this post breaks any rules here, but does anyone have any idea how best to go about this?
I am trying to solve the problem, but there is a logical error in my code, or rather I have not considered all the conditions, tell me how to find it.
The problem: An adventurer found himself in a dungeon full of treasures. However, before entering he activated a trap, which in t minutes will flood the entire room.
You are given an array of chests, where chests[i] is the number of treasures in the chest. The explorer can either pick up treasure i, taking one minute, or move to the next chest (i+1), which also takes one minute. He starts at position zero, it is not necessary to reach the end of the array.
Determine the maximum amount of treasure the hero can collect. by writing function getResult(chests,t):Integer
Input:
chests - number of treasures in chests, 2<length(chests)<20, 0<chests[i]<100
t - number of minutes to flood, 0<t<20
Output:
Integer - maximum number of treasures collected
Example 1:
chests = [1, 4, 2] t = 3
getResult(chests, t) = 5 // In the first minute the hero collected treasure from the first chest,
in the second minute, he moved to the next chest, in the third minute, he gets the treasure from it
Example 2:
chests = [7, 8, 9] t = 2
getResult(chests, t) = 8 // In the first minute, the hero goes to the second chest and gets the treasure from it,
than taking the treasure in the first chest
below are my reasons, and code.
the horizontal side of the matrix is moves and captures. They don't differ, because it takes the same amount of time to move or capture an item.
1 unit per move or capture. The chests are arranged vertically, in order of increasing number of moves to the chest, so we can say
If n (number of chests)=4, the values in the chests are in order of distance of moves with the contents of 1, 4, 3, 5
It is possible to take any[j,i] chest in i moves. In 10 moves it is possible to take all items, the point is that the number of moves n for taking
chest is a triangular number, i.e. the sum of the first n natural numbers. The formula for calculating a triangular number is: 1/2 * n * (n+1)
We build a matrix, put the inputs [1, 4, 3, 5] there, and place all the sums of those there, too, as chests.
If one cell of the matrix contains more than 1 chest, we choose maximum.
all combinations without regard to direction, (i.e. 2+3=3+2 without regard to such permutations)
summary matrix: chests and their combinations and steps to get
1__2__3__4__5__6__7__8__9_10
first chest 1, | | | | | | | | |
second chest 0, 4, 5 | | | | | | |
third chest 0, 0, 3, 4, 7, 8, | | | |
fourth chest 0, 0, 0, 5, 6, 9,10, 9 12 13
there are combinations not included in the matrix,
i.e. 4c+1c,2c>4c+3 (throw out the equal in moves option 4+3 chest, this is not the maximum)
So, form a one-dimensional array to select the best (maximal) combinations for each move
maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13]
count sum of elements up to t-1
compare with the element with the number t
ANSWER: sumofchests(0,t-1)>maxs_in_onerow(t) ? return sumofchests(0,t-1) : maxs_in_onerow(t)
// fill in the backpack, output the result
function getResult(chests, t) {
function transpose(a) { //helper func
// Calculate the width and height of the Array
let w = a.length || 0;
let h = a[0] instanceof Array ? a[0].length : 0;
// In case it is a zero matrix, no transpose routine needed.
if(h === 0 || w === 0) { return []; }
let i, j, t = [];
// Loop through every item in the outer array (height)
for(i=0; i<h; i++) {
// Insert a new row (array)
t[i] = [];
// Loop through every item per item in outer array (width)
for(j=0; j<w; j++) {
// Save transposed data.
t[i][j] = a[j][i];
}
}
return t;
}
function sumofsteps(c = chests) {
if (!Array.isArray(c)) c=Array.from({length:c})
return (c.length * (c.length + 1)) / 2;
}
function sumofchests(c = chests) {
return c.reduce((partialSum, a) => partialSum + a, 0);
}
const J = sumofsteps(chests);
const I = (chests.length);
// console.log(`${chests.length}, ${J}, ${I}`);
//create a matrix with the size of the number of chests
//for as many moves as it takes to get all the chests=J
let matrix = Array.from({ length: I }, () => new Array(J).fill(0));
let maxs_in_onerow = [];
// fill with values
let prevstepI = 0;
chests.forEach((element,index) => {
let cchests=chests.slice(0,index)
//the side of the matrix, the moves for moving and taking chests, grows like half a square
for (let i = prevstepI; i <=cchests.length; i++) {
// matrix side, chests,
// nothing before the diagonal, skip
if (i<index) continue
if (i===index) { //diagonal, minimum moves to take
prevstepI=i
matrix[index][i]=element
}
let _x=0
while (_x<i) {
matrix[_x].forEach((el , ind ) => { /* ... */
if (el > 0) {matrix[index][i+ind+1]=element + el}
})
//create combinations of chests
_x+=1
if (_x===i) break
}
}
});
// form maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13]
let jmartix=[]
jmartix=transpose(matrix)
for (let j = 0; j < J; j++) {
let cur=Math.max.apply(null, jmartix[j])
maxs_in_onerow.push(cur);
}
// fill in the backpack, output the result
let res;
if (t === 1) res = chests[0];
if (t >= J) res = sumofchests(chests);
if (t<J) {
let res1=Math.max.apply(null,maxs_in_onerow.slice(0,t))
let res2=sumofchests(maxs_in_onerow.slice(0,t-1))
res = res1>res2 ? res1 : res2
}
// console.log( `${matrix}, ${totalsteps()}, t: ${t}, maxs: ${maxs_in_onerow}, res: ${res} ` );
return res;
}
console.log(` input: [1, 4, 2], 3 \n response: ${getResult([1, 4, 2], 3)}`);
console.log(` input: [7, 8, 9], 2 \n response: ${getResult([7, 8, 9], 2)}`);
My sleep-deprived brain is not up trying to interpret your code or your reasoning. Instead, here's a simple recursive solution:
const maxTreasure = ([c, ...cs], t) =>
t <= 0 || c == undefined
? 0
: c == 0
? maxTreasure (cs, t - 1)
: Math. max (c + maxTreasure ([0, ...cs], t - 1), maxTreasure (cs, t - 1) )
console .log (`maxTreasure ([1, 4, 2], 3) //=> ${maxTreasure ([1, 4, 2], 3)}`);
console .log (`maxTreasure ([7, 8, 9], 2) //=> ${maxTreasure ([7, 8, 9], 2)}`);
We check whether the time has run out or if there are no more chests found, and if so, simply return 0. If the first chest is empty, we have no reasonable alternative than to move on to the next one, so we reduce the time by one and recur with the remaining chests. Otherwise we have to choose the better of two possibilities: taking the current chests' treasures or moving on to the next one. We use Math .max to select one of these, and calculate them by recursion. In one case, we include the current chest (c) and recur with a list of chests that replaces the current chest's value with zero. In the other, we move on to the remaining chests. In either case, we reduce the time by one.
So we have base cases, and three potential recursive calls. In each of those calls, we're reducing the time by 1, so we will eventually reach the case t <= 0.
That same foggy brains isn't going to do the analysis of time complexity here. I wouldn't be surprised if this is horribly inefficient; it's likely of exponential complexity in the number of chests. But it's simple and a good start at thinking of the problem logically. If it turns out too inefficient for real world use (ha!) we can come back at a solution using bottom-up dynamic programming... and that may be what you're attempting.
But I would always start simply, and often recursion is simplest.

How would I fix my approach to this Manhattan Skyline/Stone Wall and where did I go wrong? Javascript

I just came across this problem and thought I would give it a try, but now I'm stuck and need help if possible.
The problem I keep facing is my return is usually off by 1 or 2 but I can't figure out why not. I have traced my code back but still can't figure it out
The problem :
You are to write a program to assist an architect in drawing the skyline of a city. Building are rectangular in shape, the height of each building is represented by an element in a given array.
The above skyline above is represented like
[1,3,2,1,2,1,5,3,3,4,2]
SO FAR HERE IS WHAT I AM WORKING WITH:
const skyline =(H)=> {
let stack = [];
let count = 0;
let height = 0;
const addBlock = (value) => {
if (value > height) {
stack.push(value - height);
height = value;
count += 1;
}
}
const pop = (value) => {
while (value < height) {
height -= stack.pop();
}
if (value > height) {
addBlock(value)
}
}
for (let i = 0; i < H.length; i += 1) {
let value = H[i];
if (value < height) {
pop(value)
} else if (value > height) {
addBlock(value)
}
}
return count
}
skyline([1,3,2,1,2,1,5,3,3,4,2]) //Expect 9
// Test CASES:
let strokes = [1,3,2,1,2,1,5,3,3,4,2] // Expect 9
// let strokes = [5,8] // Expect 8
// let strokes = [1,1,1,1] // Expect 1
skyline(strokes)
Is this the basic algorithm?
* Big eats small (and equal-sized)
* Small reduces big to small
adding the difference
* Count last one standing
Examples:
[5,8]
-> 8 eats 5, count 8
[1,1,1,1]
-> 1 eats 1 eats 1 eats 1
-> count 1
[1,3,2,1,2,1,5,3,3,4,2]
-> 3 eats 1
-> 2 reduces 3 to 2 and adds 3-2
-> 1 reduces 2 to 1 and adds 2-1
-> 2 eats 1
-> 1 reduces 2 to 1 and adds 2-1
-> 5 eats 1
-> 3 reduces 5 to 3 and adds 5-3
-> 3 eats 3
-> 4 eats 3
-> 2 reduces 4 to 2 and adds 4-2
-> count 2
Total: 1 + 1 + 1 + 2 + 2 + 2 = 9
JavaScript code:
function f(A){
let result = 0;
for (let i=1; i<A.length; i++)
result += Math.max(0, A[i-1] - A[i]);
return result + A[A.length-1];
}
console.log(f([1,3,2,1,2,1,5,3,3,4,2]));
console.log(f([5,8]));
console.log(f([1,1,1,1]));
One liner :)
function f(A){
return [0].concat(A).reduce((a,b,i,A) => a + Math.max(0, A[i-1] - b)) + A[A.length-1];
}
the current answer seems to solve the problem presented, additionally I would like to point that a way to tackle this kind of problems is to solve it by hand and take notes on which steps you took to solve it.
In this case, they ask you to draw horizontal lines without picking up the pencil and one way to do that by hand is to do all the posible strokes on the same row before passing on to the next, until there are no rows left to check.
On every row, you will surely check if the current spot (array element) is greater than 0, which means that it is part of the stroke.
Now in more concise words:
While there are rowsLeft I will traverse the array. on every
traversal I will:
check if the current position is greater than 0 which means there is a
newStroke, it also means there are rowsLeft and since you want to keep
moving forward you would like to decrease the current element by one.
then, if there is a newStroke and the current element is 0 (end of the
stroke) or if it is the end of the array, I would add 1 to my numOfStrokes
count and also state that since I have just finished the stroke then there is
no newStroke at the moment.
Well that's what I did to solve the case you posted, I believe you can code it from there and I hope it helps you, then again, bruce's answer seems to be right, I just wanted to add how you could came up with the solution, there are surely many ways f doing it.
function minimalNumberOfSkylinesIn(array) {
if(array.length == 0)
return 0;
let result = array[0];
for(let i=1; i<array.length; ++i) {
let differnce = array[i] - array[i-1];
result += difference > 0 ? difference : 0;
}
return result;
}

How to generate a random number between two values with preference for numbers closer to the limits

I am implementing an AI system that basically plays the Battle Ships game.
A part of this AI consists in placing the Ships on the board. This should be a random process but however statistics says that you are more likely to win the game if you place your ships near to the edge of the board.
Something like this:
So, saying the ship can be at any position X (between 0 and 9) and Y (between 0 and 9) I would like to implement an algorithm that can generate a random integer between 0 and 9 with more probability of returning numbers closer to 0 or closer to 9 (being 4 and 5 the numbers less likely to be returned). This would be a javascript algorithm but any intuition using pseudo-code is appreciated.
Any suggestions?
Thanks!
So let's say you have some samples and a fair sampling function
// an equal distribution
const equalDistribution =
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// fair sampling function
sample (equalDistribution) // equal probability of 0 - 9
Simply adjust the samples to include more numbers that you want to appear more frequently - below, 0 and 9 have an increased probability (3/14) compared to before (1/10)
// 0 and 9 are more likely
const inequalDistribution =
[ 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9 ]
// same fair sampling function
sample (inequalDistribution) // = 0 and 9 more likely
This gives you full control over which distribution of outcomes you'd like. Of course your job now is to make a function which takes equalDistribution and creates inequalDistribution based on some input. This is where you write a program, and if you get stuck, share it and ask for help.
Basically all you do is sum up the probabilities of all the cells, then pick a random number & multiply by this sum.
Now loop your probability matrix and subtract from the random number total until less than equal to 0. This then will be the one you want.
Below is a simple example, it's a 3 x 3 matrix, with cell 4 (middle one) with a probability half of the rest, so cell 4 should get selected half as many times as the rest.
ps. Cell 4 as in 0-8,.. Not 1-9, as arrays are zero based.
const squaresProb = [
2, 2, 2,
2, 1, 2,
2, 2, 2
];
const maxProb = squaresProb.reduce((a, v) => a +v);
function pickRandomCell() {
let r = Math.random() * maxProb;
for (let c = 0; c < squaresProb.length; c ++) {
r -= squaresProb[c];
if (r <= 0) return c;
}
return squaresProb.length -1;
}
const cellCounts = [0,0,0, 0,0,0, 0,0,0];
//test.. Pick 100,000 cells,
//Cell 4 should be the smallest.
for (let l = 0; l < 100000; l ++) {
cellCounts[pickRandomCell()] ++;
}
console.log(cellCounts);

Looping over numbers

So this is the question that is given.
You are in a room with a circle of 100 chairs. The chairs are numbered sequentially from 1 to 100.
At some point in time, the person in chair #1 will be asked to leave. The person in chair #2 will be skipped, and the person in chair #3 will be asked to leave. This pattern of skipping one person and asking the next to leave will keep going around the circle until there is one person left, the survivor.
And this is the answer I came up with. I believe this is the right answer, I've done it on paper about 10 times as well and came up with 74 every time.
Is this a trick question or something? Because I'm not sure what to do from here.
Here is the jsfiddle http://jsfiddle.net/cQUaH/
var console = {
log : function(s) {
document.body.innerHTML += s + "<br>";
}
};
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 2;
while(chairArr.length > 1) {
console.log('removing ' + chairArr[j]);
chairArr.splice(j, 1);
j++;
if(j >= chairArr.length) {
console.log('--- Finished pass');
console.log('--- Array state:');
console.log(chairArr);
j = (j == chairArr.length) ? 0 : 1;
}
}
console.log('--- Final result: ' + chairArr);
//result 74
With a minor change in indices, you have the Josephus problem. In the traditional formulation, person 1 kills person 2, 3 kills 4, etc. To convert to that form, kill off person 1, as your problem states, and then renumber people 2-100 by subtracting 1, giving people 1-99.
A good treatment of the Josephus problem, including an account of its origin in the Jewish Revolt of 70-73 CE, is in Concrete Mathematics, 2nd edition, by Graham, Knuth, and Patashnik, Section 1.3. Both Wikipedia and Wolfram MathWorld have articles on the problem, Wikipedia even includes the original description by Josephus in The Jewish War.
The book gives a mildly complicated recursion for the solution, and a simpler algorithm. If the number of people is n, and n = 2^l + m where l is as large as possible, then the answer is 2m+1. So, since 99 = 2^6 + 35, the solution is 2*35 + 1 = 71. But you need to reverse the renumbering, so the real answer is 72.
As far as your programming problem, however, why don't you take as your basic operation Remove the first person in the circle and move the second person to the end. So, with 5 people, [1,2,3,4,5], you remove the first getting [2,3,4,5]and moving the new first element to the end getting [3,4,5,2].
var killAndRotate = function(array) { // say [1,2,3,4,5]
var dead = array.shift(), // dead = 1, array = [2,3,4,5]
skipped = array.shift(); // skipped = 2, array = [3,4,5]
array.push(skipped); // array = [3,4,5,2]
}
And then the main loop becomes:
while (chairArray.length > 1) {
killAndRotate(chairArray);
}
alert(chairArray[0]); // or console.log, or return.
// In turn, array is:
// [1,2,3,4,5]
// [3,4,5,2]
// [5,2,4]
// [4,2]
// [2] and we alert, log, or return 2.
Added
The easy way to find that result for the original Josephus problem is to see that:
If there are 2^l people, then in the first pass all the even-numbered people are killed, so the first person remains alive.
1 2 3 4 5 6 7 8
X X X X
Now there are 2^(l - 1) people. Again, the first person survives:
1 2 3 4 5 6 7 8
X X X X
X X
Repeat the process; the first person survives each pass, and so is the last survivor.
Now, suppose there are m extra people with m < 2^l. Here, l = 3 and m = 5. Kill the first m people to die.
1 2 3 4 5 6 7 8 9 10 11 12 13
X X X X X Y
Now, there are 2^l people left, and person 2 m + 1 = 11 is the first in line. So he survives.
One should also point out that adding a new index variable and splicing can lead to programmer error. Since you only need to remove from the front and add to the back, use the basic methods of arrays.
It seems to me the answer is 72. When you realize that rather than removing numbers you can skip them, the code becomes very short and straight-forward.
var chairArr = [];
for (var i = 1; i <= 100; i++)
chairArr.push(i);
for (i = 1; i < chairArr.length-2; i = i + 2)
chairArr.push(chairArr[i]);
console.log('--- Final result: ' + chairArr[i]);
What have you described here is the Josephus problem, and can be solved using dynamic programming:
function josephus(n, k)
{
if (n == 1) {
return 1;
} else {
return ((josephus(n-1, k) + k - 1) % n) + 1;
}
}
alert(josephus(100, 2));
Source: Wikipedia
The n denotes the number of chairs and k indicates every kth person leaving.
The result here is 73.
Update
Unfortunately, I didn't read the problem properly. The above code solves a slightly different problem; instead of killing off the first person in round one, the second person is killed instead. Being a survivor hinges on details :)
Solving your code problem is rather simple, start with the first person instead of the third in the first round.
var chairArr = [];
for (var i = 1; i <= 100; i++){
chairArr.push(i);
}
var j = 0;
while (chairArr.length > 1) {
chairArr.splice(j, 1);
j = (j + 1) % n;
}
You don't need an iteration to find the result, there is a formula that can be use to obtain the final chair:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 || (input === 1 ? 0 : input)
}
And for the original Josephus problem, which you kill the even numbers instead, the formula can be simplified:
function findChair (input) {
return (input - Math.pow(2, Math.floor(Math.log2(input)))) * 2 + 1
}
The cool thing about the original problem, is that you can work with binary. For example:
100 = 1100100
Take the first '1' and place it to the last:
1001001 = 73

Why isn't my attempted solution working?

When I run the code in the console, the browser just stops working (am assuming stack overflow).
I've come up with several different algorithms for solving this problem, but I thought this one would not cause any SOs.
The problem:
The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1 3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.
What is the value of the first triangle number to have over five hundred divisors?
Failing solution:
function divisors(n){
var counter = 0;
var triangle = 3;
var triangle_add = 2;
while (counter < n){
for (var i = 1; i = triangle; i++){
if (triangle % i === 0){
counter++;
}
};
if (counter < n){
triangle_add++;
triangle = triangle + triangle_add;
counter = 0;
};
};
return triangle;
};
console.log(divisors(501));
Your solution is not working because, most probably, it is very slow. This problem can be solved much faster by the following method:
Find all the prime numbers smaller than some N (put, for example, N=100'000) using Sieve of Eratosthenes. It is quite fast.
As we know from elementary math each number can be written in the form X=p1^i1*p2^i2*...*pn^in where pj is prime number and ij is the power of corresponding prime number. The number of divisors of X is equal to (i1+1)*(i2+1)*...*(in+1) since that many different ways we can form a number which will be divisor of X. Having an array of prime numbers the number of divisors for X can be calculated quite fast (the code still has place to be optimized):
int divisorCount(long long X)
{
int c = 1;
for (int i = 0; PRIMES[i] <= X; ++i)
{
int pr = PRIMES[i];
if (X % pr == 0)
{
int p = 1;
long long r = X;
while (r % pr == 0)
{
r = r / pr;
++p;
}
c *= p;
}
}
return c;
}
Iterate through all triangle numbers and count divisor numbers for them using the above function. The i-th triangle number is i * (i + 1) / 2, so no need to keep a variable, increment it and add it each time.

Categories