TL;DR
If an object X has an object Y as its field instance, is there a way for Y to call upon or retrieve X without assigning X to also be a field instance of Y?
I am writing a JavaScript program which implements Farkle, a die-based game. To run a game of Farkle, I instantiate one instance of the FarkleGame class. This involves two instantiations of the FarklePlayer class and an instantiation of the FarkleDie class. The two FarklePlayer instances (representing the two humans playing Farkle) and the one FarkleDie instance (representing the one die used in Farkle) are assigned as field instances within the FarkleGame class and are initialized within the FarkleGame constructor. However, the two FarklePlayer instances need to be able to access data present within the FarkleGame class definition but outside their own FarklePlayer class definition.
For Example: A human has to roll a die in Farkle, and may receive a score depending on the roll’s value. I’d like for a FarklePlayer instance to initiate a die roll by accessing the die field attribute of the higher-level FarkleGame instance as well as the score_die() method.
Here is a sample control flow:
FarkleGame instance asks FarklePlayer instance whether she wants to pass her turn or roll
FarklePlayer instance chooses to roll, and invokes her class method roll()
But the FarklePlayer class method roll() actually retrieves the FarkleDie instance belonging to the higher level FarkleGame instance, and tells the FarkleDie instance to invoke rolled(), as well as retrieves the higher-level FarkleGame instance and tells it to invoke score_die().
class FarkleGame { player_one; player_two; die; constructor(name_of_player_one, name_of_player_two) { this.player_one = new FarklePlayer(name_of_player_one); this.player_two = new FarklePlayer(name_of_player_two); this.die = new FarkleDie(); } get_player_one() { return this.player_one; } get_player_two() { return this.player_two; } get_die() { return this.die; } score_die() { let die_value = this.get_die().get_value(); let score = ((die_value * die_value) * 10) - 1); } } class FarklePlayer { name; constructor(name_of_player) { this.name = name_of_player; } roll() { // FarklePlayer instance wants to roll and needs to access the // die field attribute and score_die() method of the // higher-level FarkleGame instance of which it is a part of. higher_level_FarkleGame_instance.get_die().rolled(); higher_level_FarkleGame_instance.score_die(); } } class FarkleDie { value; constructor() { this.value = null; } rolled() { let value_after_rolled = (Math.floor(Math.random() * 6) + 1); this.value = value_after_rolled; } }
It’s important to note I don’t want to pass the FarkleDie instance as a parameter for some FarklePlayer roll() method. I want the FarklePlayer roll() method to access higher-level data (namely a field instance of the FarkleGame instance) and even instruct its higher-level instance to do something (by calling a method define din the FarkleGame class).
How do lower-level instances call upon fields & methods of higher-level instances to which they belong to?
Thank you in advance.
Advertisement
Answer
The OP …
It’s important to note I don’t want to pass the
FarkleDie
instance as a parameter for someFarklePlayer
‘sroll
method.
I want the
FarklePlayer
‘sroll
method to access higher-level data (namely a field attribute of theFarkleGame
instance)
From the above comment …
“Since a player acts or has to act within the context of a game why does the OP not pass the very game (instance) to the player’s constructor function at each player’s instantiation time?”
Why not doing the obvious then. A game instance holds all the references which are needed. Thus a player
does access the die
via its game
reference.
class FarkleGame { constructor(firstPlayerName, secondPlayerName) { this.playerOne = new FarklePlayer(firstPlayerName, this); this.playerTwo = new FarklePlayer(secondPlayerName, this); this.die = new FarkleDie(); }/* Why prototypal getters, since all the properties are public anyhow? getPlayerOne() { return this.playerOne; } getPlayerTwo() { return this.playerTwo; } getDie() { return this.die; }*/ } class FarklePlayer { constructor(name, game) { this.name = name; this.game = game; } roll() { this.game.die.rolled(); } } class FarkleDie { constructor() { this.value = null; } rolled() { this.value = (Math.floor(Math.random() * 6) + 1); } } const game = new FarkleGame('Jill', 'Jack'); console.log( 'game.die.value:', game.die.value ); console.log( '... game.playerOne.roll() ...', ); game.playerOne.roll(); console.log( 'game.die.value:', game.die.value ); console.log( '... game.playerTwo.roll() ...', ); game.playerTwo.roll(); console.log( 'game.die.value:', game.die.value );
.as-console-wrapper { min-height: 100%!important; top: 0; }