@Override
 public void advance() {
   if (end) return;
   super.advance();
   switch (animDirection) {
     case ShowHint:
       if (hintAnimCount < HINT_ANIM_MAX) ++hintAnimCount;
       break;
     case HideHint:
       if (hintAnimCount > 0) --hintAnimCount;
       else {
         resetMask.setVisible(false);
         resetMask.setEnabled(false);
         animDirection = Stay;
       }
       break;
   }
   int[] currentColorIndexes = Ball.ballsToInts(balls);
   boolean finished = true;
   for (int i = 0; i < currentColorIndexes.length; ++i) {
     if (currentColorIndexes[i] != record.targetColorIndexes[i]) {
       finished = false;
       break;
     }
   }
   if (finished) {
     end = true;
     PuzzleInfo.testMinSteps(
         record.type, record.stage, record.advanced, currentMoveItem.getNumber());
     PuzzleNextStageWidget widget =
         new PuzzleNextStageWidget(record.type, record.stage, record.advanced);
     mainWidget.changeControl(widget, true);
   }
 }
  public PuzzleGameWidget(int type, int stage, boolean advanced) {
    this.gesture = AbstractStandardGameWidget.StandardGesture.Rotate;

    record = new PuzzleGameRecord();
    record.load(type, stage, advanced);

    balls = Ball.intsToBalls(record.originalColorIndexes);

    standardInit();

    gameBoard = new SixtyOneGameBoard();

    rule = new StandardGameRule();
    gameEffectAdapter = new GameEffectAdapter(new EffectPainter());
    coreController = new CoreController(this, rule, balls);
    ballFiller = null;

    connectionCalculator = null;
    gestureController = new RotateGestureController(this, rule);

    rule.setBallFiller(ballFiller);
    rule.setConnectionCalculator(connectionCalculator);
    rule.setCoreController(coreController);
    rule.setEffectPainter(gameEffectAdapter);
    rule.setGameBoard(gameBoard);
    rule.setGestureController(gestureController);
    rule.setSomeBooleans(true, false, false);

    puzzleHintButton = new RectButtonItem();
    puzzleHintButton.setWidth((int) (width() * HINT_BASE_RATE));
    puzzleHintButton.setHeight((int) (height() * HINT_BASE_RATE));
    puzzleHintButton.setLogicalPosition(
        new MyPoint((int) (width() * HINT_BASE_RATE / 2), (int) (height() * HINT_BASE_RATE / 2)));
    addItem(puzzleHintButton, AbstractSimpleWidget.ItemType.ButtonItem);

    currentMoveItem = new IntegerItem(280);
    currentMoveItem.setDescription("Current moved steps:");
    currentMoveItem.setNumber(0);
    currentMoveItem.setLogicalPosition(
        new MyPoint((int) (width() * 0.15), (int) (height() * 0.45)));
    addItem(currentMoveItem, AbstractSimpleWidget.ItemType.SimpleItem);

    leastMoveItem = new IntegerItem(280);
    leastMoveItem.setDescription(" Least moved steps: ");
    leastMoveItem.setNumber(record.minSteps);
    leastMoveItem.setLogicalPosition(new MyPoint((int) (width() * 0.15), (int) (height() * 0.6)));
    addItem(leastMoveItem, AbstractSimpleWidget.ItemType.SimpleItem);

    resetButton.setLogicalPosition(new MyPoint((int) (width() * 0.15), (int) (height() * 0.8)));
    exitButton.setLogicalPosition(new MyPoint((int) (width() * 0.15), (int) (height() * 0.9)));
  }
 /*
  * (non-Javadoc)
  *
  * @see VAST.HexGame.GameWidget.AbstractStandardGameWidget#reset()
  */
 @Override
 public void reset() {
   for (int i = 0; i < balls.length; ++i)
     balls[i] = Ball.intToBall(record.originalColorIndexes[i]);
   currentMoveItem.setNumber(0);
 }
 @Override
 public void goodMove() {
   super.goodMove();
   currentMoveItem.setNumber(currentMoveItem.getNumber() + 1);
 }