makePgn method

String makePgn()

Make a PGN String from PgnGame.

Implementation

String makePgn() {
  final builder = StringBuffer();
  final token = StringBuffer();

  if (headers.isNotEmpty) {
    headers.forEach((key, value) {
      builder.writeln('[$key "${_escapeHeader(value)}"]');
    });
    builder.write('\n');
  }

  for (final comment in comments) {
    builder.writeln('{ ${_safeComment(comment)} }');
  }

  final fen = headers['FEN'];
  final initialPly = fen != null ? _getPlyFromSetup(fen) : 0;

  final List<_PgnFrame> stack = [];

  if (moves.children.isNotEmpty) {
    final variations = moves.children.iterator;
    variations.moveNext();
    stack.add(_PgnFrame(
        state: _PgnState.pre,
        ply: initialPly,
        node: variations.current,
        sidelines: variations,
        startsVariation: false,
        inVariation: false));
  }

  bool forceMoveNumber = true;
  while (stack.isNotEmpty) {
    final frame = stack[stack.length - 1];

    if (frame.inVariation) {
      token.write(') ');
      frame.inVariation = false;
      forceMoveNumber = true;
    }

    switch (frame.state) {
      case _PgnState.pre:
        {
          if (frame.node.data.startingComments != null) {
            for (final comment in frame.node.data.startingComments!) {
              token.write('{ ${_safeComment(comment)} } ');
            }
            forceMoveNumber = true;
          }
          if (forceMoveNumber || frame.ply.isEven) {
            token.write(
                '${(frame.ply / 2).floor() + 1}${frame.ply.isOdd ? "..." : "."} ');
            forceMoveNumber = false;
          }
          token.write('${frame.node.data.san} ');
          if (frame.node.data.nags != null) {
            for (final nag in frame.node.data.nags!) {
              token.write('\$$nag ');
            }
            forceMoveNumber = true;
          }
          if (frame.node.data.comments != null) {
            for (final comment in frame.node.data.comments!) {
              token.write('{ ${_safeComment(comment)} } ');
            }
          }
          frame.state = _PgnState.sidelines;
          continue;
        }

      case _PgnState.sidelines:
        {
          final child = frame.sidelines.moveNext();
          if (child) {
            token.write('( ');
            forceMoveNumber = true;
            stack.add(_PgnFrame(
                state: _PgnState.pre,
                ply: frame.ply,
                node: frame.sidelines.current,
                sidelines:
                    <PgnChildNode<PgnNodeData>>[].iterator, // empty iterator
                startsVariation: true,
                inVariation: false));
            frame.inVariation = true;
          } else {
            if (frame.node.children.isNotEmpty) {
              final variations = frame.node.children.iterator;
              variations.moveNext();
              stack.add(_PgnFrame(
                  state: _PgnState.pre,
                  ply: frame.ply + 1,
                  node: variations.current,
                  sidelines: variations,
                  startsVariation: false,
                  inVariation: false));
            }
            frame.state = _PgnState.end;
          }
          break;
        }

      case _PgnState.end:
        {
          stack.removeLast();
        }
    }
  }
  token.write(Outcome.toPgnString(Outcome.fromPgn(headers['Result'])));
  builder.writeln(token.toString());
  return builder.toString();
}