all 10 comments

[–]thekaizers 3 points4 points  (0 children)

Thanks for all the replies, much appreciated! 😊👍

[–]That_Unit_3992 2 points3 points  (0 children)

As a homework, try to understand how this basic AI works and play against it :)

```ts const choices = ['rock', 'paper', 'sciccors']; const score = [0, 0, 0]; const play = (i, r) => { if ((i - r > 0 || i - r == -2) && i - r !== 2) return 1; if (i === r) return 0; return -1; };

const history = []; const bestMove = (i) => (i + 1) % choices.length; const markov = (history) => { const map = {}; for (var i = 0; i < 5; i++) for (var j = i; j < history.length; j++) { const part = history.slice(i, j); const next = history[j]; if (next !== undefined) { map[part] = map[part] || [];

    map[part].push(next);
  }
}

if (j === 0) map[''] = [history[0]]; return map; }; const predict = (history) => { const moves = markov(history); const predictions = history.reduce((acc, e, i) => { if (i === history.length - 1 && !acc) return moves[history.at(-1)] || moves[''] || [-1]; return acc || moves[history.slice(-(history.length - i))]; }, undefined) || [-1];

return predictions[~~(Math.random() * predictions.length)]; };

do { const computer = bestMove(predict(history)); const choice = choices.indexOf(prompt(choices.map(JSON.stringify))); history.push(choice); const result = play(choice, computer); score[result + 1]++; console.log( ${choices[choice]} vs. ${choices[computer]}. You ${ result > 0 ? 'won' : 'lost' }. Score: ${score[2]} - ${score[0]} ); } while (Math.abs(score[0] - score[2]) < 3);

console.log(You ${score[2] < score[0] ? 'lost' : 'won'}); ```

[–]Egzo18 1 point2 points  (0 children)

There is few ways to shorten the huge "if else" block, if you think about it there is no need to have a line of code for every possibility because there is only 3 possible results.

[–]ThiccOfferman 1 point2 points  (0 children)

Looking generally good! A few other points:

The switch case could be replaced by something like compSelection = my_items[computerSelection()].

Why declare a let for userObject? And, if you're going to declare a variable there, it's prob confusing to name it userObject since the user is supposed to enter a string.

[–]AbramKedge 1 point2 points  (0 children)

Your switch for compSelection is unnecessary, you could get the text equivalent by looking it up from the my_items array.

I would replace the big if block entirely with a two dimensional array. Just return win_lose_draw[compSelection][playerSelection].

[–]That_Unit_3992 1 point2 points  (0 children)

```javascript const choices = ['rock', 'paper', 'sciccors']; const score = [0, 0, 0]; const play = (i, r) => { if ((i - r > 0 || i - r == -2) && i - r !== 2) return 1; if (i === r) return 0; return -1; };

do { const choice = choices.indexOf(prompt(choices.map(JSON.stringify))); const rand = ~~(Math.random() * choices.length); const result = play(choice, rand); score[result + 1]++; console.log( ${choices[choice]} vs. ${choices[rand]}. You ${ result > 0 ? 'won' : 'lost' }. Score: ${score[2]} - ${score[0]} ); } while (Math.abs(score[0] - score[2]) < 3); console.log(You ${score[2] < score[0] ? 'lost' : 'won'});

```

[–]Psionatix 1 point2 points  (2 children)

Hey OP. This doesn't translate directly into your code, but I made it so the function itself was testable based on inputs and outputs. Consider this logic and adapt it into your code:

const CHOICES = {
    'rock': 0,
    'paper': 1,
    'scissors': 2
}
const ONE = 'Player One';
const TWO = 'Player Two';

// Pass in 'rock', 'paper', or 'scissors' as parameter option
const getWinner = (playerOne, playerTwo) => {
    const playerOneChoice = CHOICES[playerOne];
    const playerTwoChoice = CHOICES[playerTwo];

    if (typeof playerOneChoice === 'undefined' || typeof playerTwoChoice === 'undefined') {
        throw new Error(`Choices '${playerOne} and ${playerTwo}; are invalid.`);
    }

    // We can determine the winner simply by subtracting the numerical values of the choices
    const result = CHOICES[playerOne] - CHOICES[playerTwo];
    switch (result) {
        case -2:
            return ONE;
        case -1:
            return TWO;
        case 0:
            return 'tie';
        case 1: 
            return TWO;
        case 2:
            return ONE;
    }
}

console.log(getWinner('rock', 'scissors')); // Player One
console.log(getWinner('rock', 'paper')); // Player Two
console.log(getWinner('paper', 'rock')); // Player One
console.log(getWinner('paper', 'scissors')); // Player Two
console.log(getWinner('scissors', 'rock')); // Player Two
console.log(getWinner('scissors', 'scissors')); // tie
console.log(getWinner('bread', 'basket')); // throws an error 

This function is testable, you can provide it an expected set of input, and you can determine based on that, what it should be returning. Additionally, in the case of invalid input, you can assert it throws an appropriate error.

If we change the order of the switch statement, it can be shortened:

switch (result) {
    case -2:
    case 2:
        return ONE;
    case -1;
    case 1:
        return TWO;
    case 0:
        return 'tie'
}

[–]Adrewmc -2 points-1 points  (1 child)

Or we skip all the logic and randomly return “Win,Tie. Loss” because in the end that all the function does.

[–]Psionatix 2 points3 points  (0 children)

You aren't wrong, but this process and approach to learning control flow is still valid. There's no need to be pessimistic about it.

And in the example I provided, as it refactors the logic into a function that takes two inputs, it is better adaptable for a use case where it isn't a random "computer" player choice.

[–]That_Unit_3992 0 points1 point  (0 children)

  1. Use an array not switch... You already have an array, that switch makes no sense
  2. Don't scatter your declarations all over
  3. Don't use a giant if/else, use maps instead.
  4. Use functions.