Perplexityy
Perplexityy

Reputation: 569

Array of JavaScript arrow functions

I'm implementing the card game Hearts in JavaScript, and one of the core elements of the game is that you can pass your cards to other players. My game has strictly 4 players, no more, no less.

The passing order goes left, right, straight ahead, then no passing. Therefore, P1 would pass to P2, P4, P3, and then pass to nobody. The cycle loops until the game is over.

I am trying to implement this logic via arrow functions, however, it is not working. What I am trying to do is print out the player, and the player that they should pass to, based on a given index.

Here is my code, I hope it is clear what I am trying to do.

const players = [1, 2, 3, 4];
const passingOrder = 2;
const passCards = [
  i => (i + 1) % 4, //pass left
  i => (i - 1 + 4) % 4, //pass right
  i => (i + 2) % 4, //pass straight
  i => i //pass to ones self
];

players.forEach((player, index) => {
  console.log(player + "passes to " + passCards[passingOrder](index))
})

Upvotes: 0

Views: 121

Answers (5)

nonopolarity
nonopolarity

Reputation: 151036

1, 2, 3, 4 are not good numbers to work with when you have to do MOD, which produces something from 0 and up, and you use it to indicate which user.

Use 0, 1, 2, 3 instead:

const players = [0, 1, 2, 3];
const passingOrder = 2;
const passCards = [
  i => (i + 1) % 4, //pass left
  i => (i - 1 + 4) % 4, //pass right
  i => (i + 2) % 4, //pass straight
  i => i //pass to ones self
];

players.forEach((player, index) => {
  console.log(player + "passes to " + passCards[passingOrder](index))
})

Or if you want to keep it 1, 2, 3, 4, or even use names, you need to use the index generated to find the player using players[generatedIndex], where generatedIndex is passCards[passingOrder](index):

const players = [1, 2, 3, 4];
const passingOrder = 2;
const passCards = [
  i => (i + 1) % 4, //pass left
  i => (i - 1 + 4) % 4, //pass right
  i => (i + 2) % 4, //pass straight
  i => i //pass to ones self
];

players.forEach((player, index) => {
  console.log(player + "passes to " + players[passCards[passingOrder](index)])
})

And you can use names if you want:

const players = ["Peter", "Paul", "Mary", "Susan"];
const passingOrder = 2;
const passCards = [
  i => (i + 1) % 4, //pass left
  i => (i - 1 + 4) % 4, //pass right
  i => (i + 2) % 4, //pass straight
  i => i //pass to ones self
];

players.forEach((player, index) => {
  console.log(player + " passes to " + players[passCards[passingOrder](index)])
})

And all passing methods:

const players = ["Peter", "Paul", "Mary", "Susan"];
const passCards = [
  i => (i + 1) % 4, //pass left
  i => (i - 1 + 4) % 4, //pass right
  i => (i + 2) % 4, //pass straight
  i => i //pass to ones self
];

passCards.forEach((passMethod, iPassMethod) => {
  console.log(`Game ${iPassMethod + 1}`);
  players.forEach((player, index) => {
    console.log(player + " passes to " + players[passMethod(index)])
  })
  console.log("\n");
})

Upvotes: 1

grodzi
grodzi

Reputation: 5703

In your case, you have passCards which takes an index and return an index. You can also consider passTo (just named differently) which takes a player and returns a player.

Below an example in which passTo defines the possible actions

const players = [1, 2, 3, 4];
const passingOrder = 2;
const passTo = (players => {
  const inIndexSpace = cb => {
    return player => {
      const i = players.indexOf(player)
      return players[cb(i)]
    }
  }
  return {
    left: inIndexSpace(i => (i + 1) % 4),
    right: inIndexSpace(i => (i - 1 + 4) % 4),
    straight: inIndexSpace(i => (i + 2) % 4),
    self: inIndexSpace(i => i)
  }
})(players)

players.forEach((player, index) => {
  console.log(player + "passes to " + passTo.straight(player))
})

which in "minimal" form (which you should avoid since dupplicate code) would be

const players = [1, 2, 3, 4];
const passingOrder = 2;
const passTo = [
  player => { const i = players.indexOf(player); return players[(i + 1) % 4]},
  player => { const i = players.indexOf(player); return players[(i - 1 + 4) % 4]},
  player => { const i = players.indexOf(player); return players[(i + 2) % 4]},
  player => { const i = players.indexOf(player); return players[i]}
];

players.forEach((player, index) => {
  console.log(player + "passes to " + passTo[passingOrder](player))
})

Upvotes: 0

sfy
sfy

Reputation: 3238

I would go a simple solution, each player should remember his passing order, if he can't, he should not join the game.

class Player {
  constructor(id, passOrder, name = 'Anounymous') {
    this.id = id
    this.name = name
    this.passOrder = passOrder
  }
}


let players = [
  new Player(1, [2, 4, 3], 'Alex'),
  new Player(2, [3, 1, 4], 'Billy'),
  new Player(3, [4, 2, 1]),
  new Player(4, [1, 3, 2], 'Tom')
]

players.forEach((p, i) => {
  console.log(`#${i+1} Player ${p.name} pass to `)
  p.passOrder.forEach(np => {
    console.log(`    #${np} player ${players[np-1].name},`)
  })
  console.log('-------------------')
})

Upvotes: 0

Lewis
Lewis

Reputation: 4595

We're going to cheat. Rather than waste time trying to solve this in an overly creative way, we're going to make an object that lays out the association between players and their passing direction. Let's skip the modulus for this one.

Doing things this way also happens to keep our code readable, and is more intuitive at first glance. Notice how we could easily extend this to three dimensions by just adding up and down keys to passingOrder and directions.

Sometimes it pays off to be lazy!

var players = [1, 2, 3, 4];
var passingOrder = ["left", "right", "center"];
var directions = {
  1: {
    left: 2,
    center: 3,
    right: 4
  },
  2: {
    left: 3,
    center: 4,
    right: 1
  },
  3: {
    left: 4,
    center: 1,
    right: 2
  },
  4: {
    left: 1,
    center: 2,
    right: 3
  }
};

players.forEach(
  player => passingOrder.forEach(
    pass => console.log(player, "passes to", directions[player][pass])
  )
);

Upvotes: 0

Jacob
Jacob

Reputation: 926

Your players a 1 based while the index is 0 based.

Try

console.log(player + "passes to " + (passCards[passingOrder](index) + 1))

Or make your players const players = [0, 1, 2, 3];.

Upvotes: 1

Related Questions