Esempio n. 1
0
void Dashboard::historyChanged(const Quackle::History &history)
{
	const Quackle::PlayerList players(history.currentPosition().endgameAdjustedScores());
	const int numberOfPlayers = players.size();
	const bool gameOver = history.currentPosition().gameOver();

	while (m_briefs.size() > numberOfPlayers)
	{
		delete m_briefs.back();
		m_briefs.pop_back();
	}

	while (m_briefs.size() < numberOfPlayers)
	{
		m_briefs.push_back(new PlayerBrief);
		m_hlayout->addWidget(m_briefs.back());
		m_briefs.back()->show();
	}

	Quackle::PlayerList winners;
	if (gameOver)
		winners = history.currentPosition().leadingPlayers();

	int playerCountFromZero = 0;
	QList<PlayerBrief *>::iterator briefIt = m_briefs.begin();
	for (Quackle::PlayerList::const_iterator playerIt = players.begin(); playerIt != players.end(); ++playerIt, ++briefIt, ++playerCountFromZero)
	{
		const bool isCurrentPlayer = !gameOver && *playerIt == history.currentPosition().playerOnTurn();

		(*briefIt)->setCurrentPlayer(isCurrentPlayer);
		(*briefIt)->setWinnerStatus(Nonwinner);

		if (gameOver)
		{
			Quackle::PlayerList::const_iterator winnersIt;
			for (winnersIt = winners.begin(); winnersIt != winners.end(); ++winnersIt)
			{
				if (*playerIt == *winnersIt)
				{
					(*briefIt)->setWinnerStatus(winners.size() > 1? Cowinner : Winner);
					break;
				}
			}
		}

		(*briefIt)->setPlayer(*playerIt);
	}
}
Esempio n. 2
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"));
	}
}
Esempio n. 3
0
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 << "&rarr;";
		else
			m_indexStream << "&nbsp;";
		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(" &nbsp;&larr;");

			if (!item.isEmpty())
				m_indexStream << "<li>" << item << "</li>" << endl;
		}
		m_indexStream << "</ol>" << endl;
	}

	m_indexStream << "\n\n";
}