// This is complex as it tries to do as little as possible when // the move list hasn't changed and is sorted the same way, // so simulations can go as fast as possible. // Nevertheless, TODO clean this up void MoveBox::setMoves(const Quackle::MoveList &moves, const Quackle::Move &selectedMove) { bool resorted = false; if (m_previousMoves.size() == moves.size()) { Quackle::MoveList::const_iterator prevIt = m_previousMoves.begin(); const Quackle::MoveList::const_iterator end = moves.end(); for (Quackle::MoveList::const_iterator it = moves.begin(); it != end; ++it, ++prevIt) { if (!(*prevIt == *it)) { resorted = true; break; } } } else { resorted = true; } bool hasNewItems = false; Quackle::MoveList::const_iterator end(moves.end()); for (Quackle::MoveList::const_iterator it = moves.begin(); it != end; ++it) { QMap<Quackle::Move, QTreeWidgetItem *>::const_iterator mapEnd(m_moveMap.end()); for (QMap<Quackle::Move, QTreeWidgetItem *>::const_iterator mapIt = m_moveMap.begin(); mapIt != mapEnd; ++mapIt) { if (mapIt.key() == *it) { mapIt.value()->setText(WinPercentageColumn, formatWinPercentage((*it).win)); mapIt.value()->setText(EquityColumn, formatValuation((*it).equity)); if (resorted) { m_treeWidget->addTopLevelItem(m_treeWidget->takeTopLevelItem(m_treeWidget->indexOfTopLevelItem(mapIt.value()))); } goto foundFirstPass; } } hasNewItems = true; m_moveMap.insert(*it, createItem(*it)); foundFirstPass: continue; } if (resorted) { for (QMutableMapIterator<Quackle::Move, QTreeWidgetItem *> mapIt(m_moveMap); mapIt.hasNext(); ) { mapIt.next(); for (Quackle::MoveList::const_iterator it = moves.begin(); it != end; ++it) if (mapIt.key() == *it) goto found; delete mapIt.value(); mapIt.remove(); found: continue; } } if (moves.contains(selectedMove) && m_moveMap.contains(selectedMove)) { m_treeWidget->setCurrentItem(m_moveMap.value(selectedMove)); } selectionChanged(); if (hasNewItems) QTimer::singleShot(0, this, SLOT(checkGeometry())); m_previousMoves = moves; m_previousSelection = selectedMove; }
void GraphicalReporter::reportPosition(const Quackle::GamePosition &position, Quackle::ComputerPlayer *computerPlayer) { openIndex(); const QSize pictureSize(500, 500); Quackle::GamePosition positionCopy = position; { QString title; if (!position.gameOver()) { title = GraphicalBoard::tr("<h2>%1: Turn %2</h2>").arg(QuackleIO::Util::uvStringToQString(position.currentPlayer().name())).arg(position.turnNumber()); } else { title = GraphicalBoard::tr("<h2>Game over.</h2>"); } if (m_generateImages) { QPixmap pixmap; positionCopy.resetMoveMade(); GraphicalBoardFrame::staticDrawPosition(positionCopy, pictureSize, &pixmap); QImage image = pixmap.toImage(); const QString filebasename = QString("%1-%2-position.png").arg(position.turnNumber()).arg(QuackleIO::Util::uvStringToQString(position.currentPlayer().name())); const QString filename = makeFilename(filebasename); if (image.save(filename, "PNG")) { m_indexStream << QString("<a href=\"%1\">%2</a>").arg(filebasename).arg(title) << endl; } else { QMessageBox::critical(0, GraphicalBoard::tr("Error Writing File - Quacker"), GraphicalBoard::tr("Could not write image %1.").arg(filename)); } m_indexStream << "<p><img src=\"" << filebasename << "\"></p>" << endl; } else { m_indexStream << title; const int boardTileSize = position.gameOver()? 45 : 25; m_indexStream << QuackleIO::Util::sanitizeUserVisibleLetterString(QuackleIO::Util::uvStringToQString(position.board().htmlBoard(boardTileSize))) << endl; } } const Quackle::PlayerList players(position.endgameAdjustedScores()); m_indexStream << "<table cellspacing=6>" << endl; for (Quackle::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it) { m_indexStream << "<tr>"; m_indexStream << "<td>"; if ((*it) == position.currentPlayer()) m_indexStream << "→"; else m_indexStream << " "; m_indexStream << "</td>"; m_indexStream << "<td>" << QuackleIO::Util::uvStringToQString((*it).name()) << "</td>" << "<td>" << QuackleIO::Util::sanitizeUserVisibleLetterString(QuackleIO::Util::uvStringToQString((*it).rack().toString())) << "</td>" << "<td>" << (*it).score() << "</td>" << "</tr>" << endl; } m_indexStream << "</table>" << endl; if (computerPlayer && !position.gameOver()) { computerPlayer->setPosition(position); if (position.committedMove().isAMove()) computerPlayer->considerMove(position.committedMove()); const unsigned int movesToShow = 5; Quackle::MoveList moves = computerPlayer->moves(movesToShow); if (!moves.contains(position.committedMove())) { if (moves.size() == movesToShow) moves.pop_back(); moves.push_back(position.committedMove()); } m_indexStream << "<ol>" << endl; for (Quackle::MoveList::const_iterator it = moves.begin(); it != moves.end(); ++it) { QString item; switch ((*it).action) { case Quackle::Move::Place: case Quackle::Move::PlaceError: { if (m_generateImages) { QPixmap pixmap; positionCopy.setMoveMade(*it); GraphicalBoardFrame::staticDrawPosition(positionCopy, pictureSize, &pixmap); QImage image = pixmap.toImage(); const QString filebasename = QString("%1-%2-%3-%4.png").arg(position.turnNumber()).arg(QuackleIO::Util::uvStringToQString(position.currentPlayer().name())).arg(QuackleIO::Util::letterStringToQString((*it).prettyTiles())).arg(QuackleIO::Util::uvStringToQString((*it).positionString())); const QString filename = makeFilename(filebasename); if (image.save(filename, "PNG")) { item = QString("<a href=\"%1\">%2</a> %3").arg(filebasename); } else { QMessageBox::critical(0, GraphicalBoard::tr("Error Writing File - Quacker"), GraphicalBoard::tr("Could not write image %1.").arg(filename)); } } else { item = "%1 %2"; } item = item.arg(QuackleIO::Util::sanitizeUserVisibleLetterString(QuackleIO::Util::moveToDetailedString(*it))).arg((*it).score); break; } case Quackle::Move::Exchange: case Quackle::Move::BlindExchange: default: item = QuackleIO::Util::moveToDetailedString(*it); break; } if (*it == position.committedMove()) item += QString(" ←"); if (!item.isEmpty()) m_indexStream << "<li>" << item << "</li>" << endl; } m_indexStream << "</ol>" << endl; } m_indexStream << "\n\n"; }