constructor(game, config) {
    assertPositiveInteger(config.epsilonDecayFrames);

    this.game = game;

    this.epsilonInit = config.epsilonInit;
    this.epsilonFinal = config.epsilonFinal;
    this.epsilonDecayFrames = config.epsilonDecayFrames;
    this.epsilonIncrement_ = (this.epsilonFinal - this.epsilonInit) /
        this.epsilonDecayFrames;

    this.onlineNetwork =
        createDeepQNetwork(game.height,  game.width, NUM_ACTIONS);
    this.targetNetwork =
        createDeepQNetwork(game.height,  game.width, NUM_ACTIONS);
    // Freeze taget network: it's weights are updated only through copying from
    // the online network.
    this.targetNetwork.trainable = false;

    this.optimizer = tf.train.adam(config.learningRate);

    this.replayBufferSize = config.replayBufferSize;
    this.replayMemory = new ReplayMemory(config.replayBufferSize);
    this.frameCount = 0;
    this.reset();
  }
Constructor of SnakeGameAgent.

@param {SnakeGame} game A game object.
@param {object} config The configuration object with the following keys:
  - `replayBufferSize` {number} Size of the replay memory. Must be a
    positive integer.
  - `epsilonInit` {number} Initial value of epsilon (for the epsilon-
    greedy algorithm). Must be >= 0 and <= 1.
  - `epsilonFinal` {number} The final value of epsilon. Must be >= 0 and
    <= 1.
  - `epsilonDecayFrames` {number} The # of frames over which the value of
    `epsilon` decreases from `episloInit` to `epsilonFinal`, via a linear
    schedule.
  - `learningRate` {number} The learning rate to use during training.