示例#1
0
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"));
	}
}