<commit_before>library freecell.view.solutionplayer;

import "dart:async";

import "../deck/deck.dart";
import "../tableau/tableau.dart";
import "../solver/solution.dart";

import "card-coordinator.dart";

class Transfer {
  final Pile source;
  final Pile destination;

  Transfer(this.source, this.destination);
}

class CompoundMovePlanner {
  Tableau tableau;
  List<Pile> freeCells;
  List<Pile> freeColumns;

  CompoundMovePlanner(this.tableau) {
    freeCells = _findFree(tableau.cells);
    freeColumns = _findFree(tableau.columns);
  }

  static List<Pile> concat(List<Pile> a, List<Pile> b) {
    List<Pile> result = new List.from(a);
    result.addAll(b);
    return result;
  }

  List<Pile> _findFree(List<Pile> piles) {
    List<Pile> result = new List<Pile>();
    for (Pile pile in piles) {
      if (pile.isEmpty)
        result.add(pile);
    }
    return result;
  }

  List<Transfer> plan(Transfer transfer, int count) {
    List<Pile> availableColumns = new List.from(freeColumns);
    availableColumns.remove(transfer.destination);
    return _createRecursivePlan(transfer, count, availableColumns);
  }

  List<Transfer> _createRecursivePlan(Transfer transfer, int count, List<Pile> availableColumns) {
    if (count <= freeCells.length + availableColumns.length + 1)
      return _createSimplePlan(transfer, count, concat(freeCells, availableColumns));

    List<Pile> childAvailableColumns = new List.from(availableColumns);
    Pile pivot = childAvailableColumns.removeLast();

    Transfer pivotTransfer = new Transfer(transfer.source, pivot);
    Transfer unpivotTransfer = new Transfer(pivot, transfer.destination);

    int pivotCount = freeCells.length + childAvailableColumns.length + 1;
    List<Pile> pivotTemporaries = concat(freeCells, childAvailableColumns);

    List<Transfer> plan = _createSimplePlan(pivotTransfer, pivotCount, pivotTemporaries);
    plan.addAll(_createSimplePlan(transfer, count - pivotCount, pivotTemporaries));
    plan.addAll(_createSimplePlan(unpivotTransfer, pivotCount, pivotTemporaries));
    return plan;
  }

  List<Transfer> _createSimplePlan(Transfer transfer, int count, List<Pile> temporaries) {
    assert(!temporaries.contains(transfer.source));
    assert(!temporaries.contains(transfer.destination));

    List<Transfer> plan = new List<Transfer>();

    int nextTemporary = 0;
    for (int i = 0; i < count - 1; ++i)
      plan.add(new Transfer(transfer.source, temporaries[nextTemporary++]));

    plan.add(transfer);

    while (nextTemporary > 0)
      plan.add(new Transfer(temporaries[--nextTemporary], transfer.destination));

    return plan;
  }
}

class SolutionPlayer {
  static final _moveDelay = new Duration(milliseconds: 100);<commit_msg>Support fancier compound plans<commit_after>library freecell.view.solutionplayer;

import "dart:async";

import "../deck/deck.dart";
import "../tableau/tableau.dart";
import "../solver/solution.dart";

import "card-coordinator.dart";

class Transfer {
  final Pile source;
  final Pile destination;

  Transfer(this.source, this.destination);
}

class CompoundMovePlanner {
  Tableau tableau;
  List<Pile> freeCells;
  List<Pile> freeColumns;

  CompoundMovePlanner(this.tableau) {
    freeCells = _findFree(tableau.cells);
    freeColumns = _findFree(tableau.columns);
  }

  static List<Pile> concat(List<Pile> a, List<Pile> b) {
    List<Pile> result = new List.from(a);
    result.addAll(b);
    return result;
  }

  List<Pile> _findFree(List<Pile> piles) {
    List<Pile> result = new List<Pile>();
    for (Pile pile in piles) {
      if (pile.isEmpty)
        result.add(pile);
    }
    return result;
  }

  List<Transfer> plan(Transfer transfer, int count) {
    List<Pile> availableColumns = new List.from(freeColumns);
    availableColumns.remove(transfer.destination);
    return _createRecursivePlan(transfer, count, availableColumns);
  }

  List<Transfer> _createRecursivePlan(Transfer transfer, int count, List<Pile> availableColumns) {
    if (count <= freeCells.length + availableColumns.length + 1)
      return _createSimplePlan(transfer, count, concat(freeCells, availableColumns));

    List<Pile> childAvailableColumns = new List.from(availableColumns);
    Pile pivot = childAvailableColumns.removeLast();

    Transfer pivotTransfer = new Transfer(transfer.source, pivot);
    Transfer unpivotTransfer = new Transfer(pivot, transfer.destination);

    int pivotCount = freeCells.length + childAvailableColumns.length + 1;
    List<Pile> pivotTemporaries = concat(freeCells, childAvailableColumns);

    List<Transfer> plan = _createSimplePlan(pivotTransfer, pivotCount, pivotTemporaries);
    plan.addAll(_createRecursivePlan(transfer, count - pivotCount, childAvailableColumns));
    plan.addAll(_createSimplePlan(unpivotTransfer, pivotCount, pivotTemporaries));
    return plan;
  }

  List<Transfer> _createSimplePlan(Transfer transfer, int count, List<Pile> temporaries) {
    assert(!temporaries.contains(transfer.source));
    assert(!temporaries.contains(transfer.destination));

    List<Transfer> plan = new List<Transfer>();

    int nextTemporary = 0;
    for (int i = 0; i < count - 1; ++i)
      plan.add(new Transfer(transfer.source, temporaries[nextTemporary++]));

    plan.add(transfer);

    while (nextTemporary > 0)
      plan.add(new Transfer(temporaries[--nextTemporary], transfer.destination));

    return plan;
  }
}

class SolutionPlayer {
  static final _moveDelay = new Duration(milliseconds: 100);
{'fraction_non_alphanumeric': 0.11676701331873746, 'fraction_numerical': 0.003284072249589491, 'mean_word_length': 4.537373737373738, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '218855', 'n_tokens_mistral': 1748, 'n_tokens_neox': 1645, 'n_words': 362}