From 9306cb60c32082c5403931de0823a9fd5daa196c Mon Sep 17 00:00:00 2001 From: Jason Katz-Brown Date: Sun, 25 Aug 2013 02:17:13 -0700 Subject: Initial git commit. --- reporter.cpp | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 reporter.cpp (limited to 'reporter.cpp') diff --git a/reporter.cpp b/reporter.cpp new file mode 100644 index 0000000..62fce18 --- /dev/null +++ b/reporter.cpp @@ -0,0 +1,310 @@ +/* + * Quackle -- Crossword game artificial intelligence and analysis tool + * Copyright (C) 2005-2006 Jason Katz-Brown and John O'Laughlin. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include "alphabetparameters.h" +#include "computerplayer.h" +#include "datamanager.h" +#include "game.h" + +#include "reporter.h" + +using namespace Quackle; + +void Reporter::reportPosition(const GamePosition &position, ComputerPlayer *computerPlayer, UVString *report) +{ + UVOStringStream s; + + UVOStringStream titleStream; + + if (!position.gameOver()) + titleStream << position.currentPlayer().name() << MARK_UV(": Turn ") << position.turnNumber() << MARK_UV('\n'); + + const Quackle::PlayerList players(position.endgameAdjustedScores()); + + for (PlayerList::const_iterator it = players.begin(); it != players.end(); ++it) + { + s.width(3); + s << right << ((*it) == position.currentPlayer()? MARK_UV("->") : MARK_UV(" ")); + s << MARK_UV(' '); + s.width(24); + s << left << (*it).name() << MARK_UV(' '); + s.width(9); + s << (*it).rack().toString() << MARK_UV(' '); + s.width(4); + s << (*it).score(); + s << MARK_UV('\n'); + } + + if (computerPlayer && !position.gameOver()) + { + computerPlayer->setPosition(position); + + if (position.committedMove().isAMove()) + computerPlayer->considerMove(position.committedMove()); + + const unsigned int movesToShow = 10; + MoveList moves = computerPlayer->moves(movesToShow); + + int ourMoveIndex = 0; + int i = 1; + for (Quackle::MoveList::const_iterator it = moves.begin(); it != moves.end(); ++it, ++i) + { + if ((*it) == position.committedMove()) + { + ourMoveIndex = i; + break; + } + } + + bool isUrp = false; + + if (position.committedMove().isAMove()) + { + // our move not in list + if (ourMoveIndex == 0) + { + if (moves.size() == movesToShow) + moves.pop_back(); + + isUrp = true; + ourMoveIndex = movesToShow; + moves.push_back(position.committedMove()); + } + } + + int highestScore = 0; + double highestEquity = 0; + unsigned int widestPositionString = 0; + unsigned int widestMove = 0; + bool hasWinPercentages = false; + const Quackle::MoveList::const_iterator end(moves.end()); + for (Quackle::MoveList::const_iterator it = moves.begin(); it != end; ++it) + { + if ((*it).prettyTiles().length() > widestMove) + widestMove = (*it).prettyTiles().length(); + if ((*it).positionString().length() > widestPositionString) + widestPositionString = (*it).positionString().length(); + if ((*it).win > 0) + hasWinPercentages = true; + if ((*it).equity > highestEquity) + highestEquity = (*it).equity; + if ((*it).score > highestScore) + highestScore = (*it).score; + } + + s << MARK_UV("--"); + + UVOStringStream headerStream; + headerStream << computerPlayer->name(); + + headerStream << "'s choices (your play: "; + if (isUrp) + headerStream << "urp"; + else + headerStream << ourMoveIndex; + headerStream << ")"; + + s.width(43); + s << setfill(MARK_UV('-')); + s << left << headerStream.str() << MARK_UV('\n'); + s << setfill(MARK_UV(' ')); + + i = 1; + for (Quackle::MoveList::const_iterator it = moves.begin(); it != end; ++it, ++i) + { + // column 2, the valuation. + s.width(5); + if ((*it).equity > (highestEquity - .01) && (*it).equity < (highestEquity + .01)) + { + s << MARK_UV("best"); + } + else + { + s << right << showpoint; + s.precision(3); + s << (highestEquity - (*it).equity); + } + + s << (i == ourMoveIndex? MARK_UV("*") : MARK_UV(" ")); + + // column 3, the position string. + s << left; + s.width(widestPositionString); + switch ((*it).action) + { + case Move::Place: + s << (*it).positionString(); + break; + + case Move::Exchange: + s << MARK_UV("xch"); + break; + + case Move::Pass: + s << MARK_UV("pas"); + break; + case Move::UnusedTilesBonus: + case Move::TimePenalty: + case Move::Nonmove: + break; + } + s << MARK_UV(" "); + + // column 4, the word + s.width(widestMove); + s << left << QUACKLE_ALPHABET_PARAMETERS->userVisible((*it).prettyTiles()) << MARK_UV(" "); + + // column 5, the score + s.width(highestScore >= 100? 3 : (highestScore >= 10? 2 : 1)); + s << left << (*it).score << MARK_UV(" "); + + // column 6, the win percentage + if (hasWinPercentages) + { + s.precision(4); + s.width(5); + s << showpoint << ((*it).win * 100.0) << MARK_UV("% "); + } + + // column 7, the leave + + s << (position.currentPlayer().rack() - (*it)).toString() << MARK_UV('\n'); + } + } + + if (position.gameOver()) + { + s << MARK_UV("\n Game over.\n\n"); + } + + int j = 0; + UVString wrappedTiles; + LongLetterString unseenTiles = position.unseenBag().tiles(); + for (Quackle::LongLetterString::const_iterator it = unseenTiles.begin(); it != unseenTiles.end(); ++it, ++j) + { + if (j >= 44) + { + wrappedTiles += MARK_UV('\n'); + j = 0; + } + + wrappedTiles += QUACKLE_ALPHABET_PARAMETERS->userVisible(*it); + } + + s << MARK_UV("--"); + s.width(43); + s << setfill(MARK_UV('-')); + s << MARK_UV("Tracking") << MARK_UV('\n'); + s << wrappedTiles << MARK_UV(" ") << unseenTiles.size() << MARK_UV('\n'); + + UVString reportString = s.str(); + UVString boardString = position.board().toString(); + + *report = titleStream.str(); + + // Ensure that the board ends with a newline. + boardString += MARK_UV("\n"); + + // Put board and report side by side. + UVString::const_iterator boardIt = boardString.begin(); + UVString::const_iterator reportIt = reportString.begin(); + UVString::const_iterator reportLineBeginning = reportString.begin(); + UVString::const_iterator boardLineBeginning = boardString.begin(); + const UVString::const_iterator reportEnd = reportString.end(); + const UVString::const_iterator boardEnd = boardString.end(); + while (true) + { + if (boardIt == boardEnd && reportIt == reportEnd) + break; + + if (boardIt != boardEnd && (*boardIt) != MARK_UV('\n')) + { + ++boardIt; + continue; + } + + if (reportIt != reportEnd && (*reportIt) != MARK_UV('\n')) + { + ++reportIt; + continue; + } + + if (boardIt != boardEnd) + { + report->append(boardLineBeginning, boardIt); + } + if (reportIt != reportEnd) + { + report->append(MARK_UV(" ")); + report->append(reportLineBeginning, reportIt); + } + + boardLineBeginning = boardIt + 1; + reportLineBeginning = reportIt + 1; + + if (boardIt != boardEnd) + ++boardIt; + if (reportIt != reportEnd) + ++reportIt; + + report->append(MARK_UV("\n")); + } +} + +void Reporter::reportHeader(const Game & /* game */, UVString *report) +{ + UVOStringStream s; + s << MARK_UV("Game Report\nGenerated by Quackle crossword game AI and analysis software\nhttp://quackle.org\n\n"); + *report = s.str(); +} + +void Reporter::reportGameStatistics(const Game &game, UVString *report) +{ + (void) game; + UVOStringStream s; + *report = s.str(); +} + +void Reporter::reportGame(const Game &game, ComputerPlayer *computerPlayer, UVString *report) +{ + UVOStringStream s; + + UVString header; + reportHeader(game, &header); + s << header; + + const PositionList::const_iterator end(game.history().end()); + for (PositionList::const_iterator it = game.history().begin(); it != end; ++it) + { + UVString subreport; + reportPosition(*it, computerPlayer, &subreport); + + s << subreport << MARK_UV('\n'); + } + + UVString stats; + reportGameStatistics(game, &stats); + s << stats; + + *report = s.str(); +} -- cgit v1.2.3