- Players can now have a name

- Use player names in the ncurses interface
 - In training mode, create the hidden player in the constructor, not in start()
 - When the AI has nothing to play, change the letters instead of simply passing
 - New Makefile to build the win32 dependencies automatically (INSTALL file updated)
This commit is contained in:
Olivier Teulière 2008-01-19 19:33:08 +00:00
parent 8c3708fa99
commit 0a4b342f78
9 changed files with 247 additions and 91 deletions

103
INSTALL
View file

@ -1,83 +1,86 @@
Installation on Linux/Unix
==========================
Installation sous Linux (Un*x) (bien/facile)
------------------------------
* Pour installer à partir de l'archive CVS :
In the following, do not forget that the ./configure command can take options.
Run ./configure --help to have the list of available options.
* If you build from a CVS snapshot, run the following commands:
./bootstrap
./configure
make
Then, as root:
make install
* Pour installer à partir de l'archive tar.gz
No graphical interface is built by default, see below for more details.
* If you build from a release tarball, run the following commands:
./configure
make
Then, as root:
make install
No graphical interface is built by default, see below for more details.
Il existe en fait 3 versions d'eliot, une en mode texte, une avec une
interface curses et une avec wxwidgets. Les modes peuvent être
sélectionnés à l'aide de la commande configure lors de la compilation
du programme.
./configure --enable-text --enable-ncurses --enable-wxwidgets
There are in fact several interfaces to Eliot:
- one in text mode: mostly useful to debug Eliot
- one using the ncursesw library: nice but not really graphical
- a wxWidgets interface: complete, but it does not allow multiplayer
modes, only training mode
- a Qt interface: currently under construction, it will replace the
wxWidgets interface when finished. It will support all Eliot features.
These interfaces can be enabled or disabled at configuration time. Example:
./configure --disable-text --enable-ncurses --disable-wxwidgets --enable-qt
Installation pour Windows (moins bien/facile)
-------------------------
Windows build
=============
Il y a 2 principales façons de procéder :
* directement depuis Windows, en utilisant Cygwin (http://www.cygwin.com/).
* depuis GNU/Linux, en utilisant le cross-compilateur Mingw32.
There are 2 ways to proceed:
* cross-compilation from a Linux host, using the mingw32 cross-compiler
* directly on Windows, using Cygwin (http://www.cygwin.com/)
Only the cross-compilation is officially supported (but adapting these
instructions for Cygwin shouldn't be too hard; patches welcome!).
Here are the steps for the cross-compilation:
Dans les 2 cas, les étapes sont les mêmes :
* installation de l'environnement de compilation (cette étape n'est pas
décrite ici, car elle ne rentre pas dans le cadre de ce document)
* install the build environment (this step is not documented here,
as it is out of the scope of this document)
* compilation et installation des dépendances (même remarque):
* build and install dependencies:
The Makefile in the 'extras/contrib' directory should be able to do it for you:
- wxWidgets (http://www.wxwidgets.org/), version 2.4.2 ou ultérieure, avec
support de l'unicode
cd extras/contrib && make all
- libiconv (http://www.gnu.org/software/libiconv/), de préférence compilée
en mode statique (--disable-shared --enable-static)
Eliot dependencies (libiconv, boost, wxWidgets and Qt) will be downloaded
and cross-compiled, except Qt, which is only downloaded. Install it with
Wine, ignoring the warning that mingw is not found.
The dependencies are installed in 'extras/contrib/inst'
- boost (http://www.boost.org/). Eliot n'utilise pas de librairie de Boost
(uniquement des headers), donc il n'y a pas vraiment besoin de compiler
* build Eliot:
* compilation d'Eliot :
- si vous utilisez l'archive CVS, il faut générer le script 'configure'
(aussi bien sous Cygwin que sous GNU/Linux) :
- if you don't have the 'configure' script, generate it:
./bootstrap
- à cause d'un bug de gettext, il faut appliquer un patch aux fichiers installés
dans intl/ :
- télécharger le patch ici (lien en haut à gauche) :
- because of a bug in gettext, you need to apply a little patch to the files
installed in the 'intl' directory:
- download the patch here (link in the top-left-hand corner)
http://www.koders.com/noncode/fid46DF595700FEB564B6EF45BFF55067F95DCF0420.aspx
- exécuter la commande suivante :
- apply the patch:
patch -p2 < gettext-win32.patch
- avec Cygwin, configurer avec la ligne de commande suivante :
CPPFLAGS=-I/path/to/installs/include LDFLAGS=-L/path/to/installs/lib \
CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin" \
./configure --enable-wxwidgets --with-wx-config=/path/to/wx-config \
--with-boost=/path/to/boost/installs
en prenant soin de remplacer les différents chemins par les bonnes valeurs.
Ensuite, un simple 'make' suffit pour terminer la compilation,
éventuellement suivi de 'make install'.
- pour la cross-compilation depuis GNU/Linux, configurer avec la ligne
de commande suivante :
CPPFLAGS=-I/path/to/installs/include LDFLAGS=-L/path/to/installs/lib \
- configure with the following command:
export INST=`pwd`/extras/contrib/inst && \
CPPFLAGS=-I${INST}/include LDFLAGS=-L${INST}/lib \
CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ \
./configure --host=i586-mingw32msvc --build=i386-linux \
--enable-wxwidgets --with-wx-config=/path/to/wx-config \
--with-boost=/path/to/installs
en prenant soin de remplacer les différents chemins par les bonnes valeurs.
Ensuite, un simple 'make' suffit pour terminer la compilation,
éventuellement suivi de 'make install'.
--enable-wxwidgets --with-wx-config=${INST}/bin/wx-config \
--with-boost=${INST}
- to compile, run 'make', possibly followed with 'make install'

85
extras/contrib/Makefile Normal file
View file

@ -0,0 +1,85 @@
ICONV_VERSION = 1.12
WX_VERSION = 2.6.4
BOOST_VERSION = 1_34_1
QT_VERSION = 4.3.3
PREFIX = $(shell pwd)/inst
WGET = wget -c
# XXX: Hardcoded for mingw on linux, at the moment
CC = i586-mingw32msvc-gcc
CXX = i586-mingw32msvc-g++
CPPFLAGS += -I$(PREFIX)/include
CONFIGURE = CC=$(CC) CXX=$(CXX) CPPFLAGS=$(CPPFLAGS) ./configure --host=i586-mingw32msvc --build=i386-linux --prefix=$(PREFIX)
.PHONY: help all
help:
echo "Usage: make all"
all: .iconv .wxWidgets .boost .qt
### iconv ###
ICONV_DIR = libiconv-$(ICONV_VERSION)
ICONV_ARCHIVE = libiconv-$(ICONV_VERSION).tar.gz
$(ICONV_DIR):
$(WGET) http://ftp.gnu.org/pub/gnu/libiconv/$(ICONV_ARCHIVE)
tar xzf $(ICONV_ARCHIVE)
.iconv: $(ICONV_DIR)
(cd $< && $(CONFIGURE) --enable-static --disable-shared && make && make install)
touch $@
### wxWidgets ###
WX_ARCHIVE = wxMSW-$(WX_VERSION).zip
WX_DIR = wxWidgets-$(WX_VERSION)
WX_DOS_FILES = config* *.sh install-sh mkinstalldirs
$(WX_DIR):
$(WGET) http://heanet.dl.sourceforge.net/sourceforge/wxwindows/$(WX_ARCHIVE)
unzip $(WX_ARCHIVE)
.wxWidgets: $(WX_DIR)
(cd $< && dos2unix $(WX_DOS_FILES) && chmod +x $(WX_DOS_FILES))
(cd $< && $(CONFIGURE) --disable-shared --enable-optimise --disable-debug --enable-unicode --without-libtiff --without-expat --without-zlib --without-libpng --without-libjpeg --without-regex --disable-mediactrl && make && make install)
dos2unix $(PREFIX)/bin/wx-config
touch $@
### Boost ###
BOOST_DIR = boost_$(BOOST_VERSION)
BOOST_ARCHIVE = boost_$(BOOST_VERSION).tar.bz2
$(BOOST_DIR):
$(WGET) http://garr.dl.sourceforge.net/sourceforge/boost/$(BOOST_ARCHIVE)
tar xjf $(BOOST_ARCHIVE)
# We don't build any library, because we don't need them (and it is really
# hard to cross-compile with their crappy build system)
.boost: $(BOOST_DIR)
#(cd $< && ./configure --prefix=$(PREFIX) && ./tools/jam/src/bin.linuxx86/bjam --toolset=gcc --prefix=$(PREFIX) --without-date_time --without-filesystem --without-graph --without-iostreams --without-program_options --without-python --without-regex --without-serialization --without-signals --without-test --without-thread --without-wave install)
cp -r $</boost $(PREFIX)/include
touch $@
### Qt ###
# FIXME: No automated way at the moment :-(
QT_ARCHIVE = qt-win-opensource-$(QT_VERSION)-mingw.exe
$(QT_ARCHIVE):
$(WGET) ftp://ftp.trolltech.com/qt/source/qt-win-opensource-4.3.3-mingw.exe
.qt: $(QT_ARCHIVE)
@echo "=============== Important note ==============="
@echo "You need to install $(QT_ARCHIVE) yourself using wine!"
@echo "=============================================="
touch $@

View file

@ -19,7 +19,7 @@
noinst_LIBRARIES = libgame.a
AM_CPPFLAGS = -I$(top_srcdir)/dic
AM_CPPFLAGS = -I$(top_srcdir)/dic -I../intl -I$(top_srcdir)/intl
libgame_a_SOURCES= \
ai_percent.cpp ai_percent.h \

View file

@ -53,9 +53,12 @@ Move AIPercent::getMove() const
{
if (m_results.size() == 0)
{
// If there is no result, simply pass the turn
// XXX: it is forbidden in duplicate mode, but well, what else to do?
return Move(L"");
// If there is no result, change all the letters
// XXX: it is forbidden in duplicate mode (even passing is forbidden),
// but well, what else to do?
Rack rack;
getCurrentRack().getRack(rack);
return Move(rack.toString());
}
else
{

View file

@ -26,18 +26,27 @@
#include <fstream>
#include <exception>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) String
#endif
#include "game_factory.h"
#include "game.h"
#include "training.h"
#include "freegame.h"
#include "duplicate.h"
#include "player.h"
#include "dic.h"
#include "encoding.h"
GameFactory *GameFactory::m_factory = NULL;
GameFactory::GameFactory(): m_dic(NULL), m_human(0), m_ai(0), m_joker(false)
GameFactory::GameFactory(): m_dic(NULL), m_joker(false)
{
}
@ -94,12 +103,12 @@ Game *GameFactory::createFromCmdLine(int argc, char **argv)
{"dictionary", required_argument, NULL, 'd'},
{"dict", required_argument, NULL, 'd'},
{"mode", required_argument, NULL, 'm'},
{"human", no_argument, NULL, 300},
{"ai", no_argument, NULL, 400},
{"human", required_argument, NULL, 'u'},
{"ai", required_argument, NULL, 'a'},
{"joker", no_argument, NULL, 500},
{0, 0, 0, 0}
};
static char short_options[] = "hvd:m:";
static char short_options[] = "hvd:m:u:a:";
int option_index = 1;
int res;
@ -126,11 +135,22 @@ Game *GameFactory::createFromCmdLine(int argc, char **argv)
m_modeStr = optarg;
found_m = true;
break;
case 300:
m_human++;
break;
case 400:
m_ai++;
case 'u':
case 'a':
// Handle both types of players together
{
wstring name;
if (optarg == NULL)
{
// TODO: use Boost.Format
char s[200];
snprintf(s, 200, _("Player %u"), m_players.size() + 1);
name = convertToWc(s);
}
else
name = convertToWc(optarg);
m_players.push_back(make_pair<bool, wstring>(res == 'u', name));
}
break;
case 500:
m_joker = true;
@ -184,10 +204,15 @@ Game *GameFactory::createFromCmdLine(int argc, char **argv)
}
// 5) Add the players
for (int i = 0; i < m_human; i++)
for (unsigned int i = 0; i < m_players.size(); ++i)
{
// Human?
if (m_players[i].first)
game->addHumanPlayer();
for (int i = 0; i < m_ai; i++)
else
game->addAIPlayer();
const_cast<Player*>(&game->getPlayer(i))->setName(m_players[i].second);
}
// 6) Set the variant
if (m_joker)
@ -225,9 +250,9 @@ void GameFactory::printUsage(const string &iBinaryName) const
<< " -v, --version Print version information and exit" << endl
<< " -m, --mode {duplicate,d,freegame,f,training,t}" << endl
<< " Choose game mode (mandatory)" << endl
<< " -d, --dict <string> Choose a dictionary (mandatory)" << endl
<< " --human Add a human player" << endl
<< " --ai Add a AI (Artificial Intelligence) player" << endl
<< " -d, --dict <path> Choose a dictionary (mandatory)" << endl
<< " -u --human <name> Add a human player" << endl
<< " -a --ai <name> Add a AI (Artificial Intelligence) player" << endl
<< " --joker Play with the \"Joker game\" variant" << endl;
}

View file

@ -22,8 +22,12 @@
#define _GAME_FACTORY_H_
#include <string>
#include <vector>
using std::string;
using std::wstring;
using std::vector;
using std::pair;
class Dictionary;
class Game;
@ -85,15 +89,12 @@ private:
/// Game mode
string m_modeStr;
/// Number of human players
int m_human;
/// Number of AI players
int m_ai;
/// Variant of the game
bool m_joker;
typedef pair<bool, wstring> PlayerDesc;
vector<PlayerDesc> m_players;
//@}
/// Print command-line usage

View file

@ -27,6 +27,8 @@
#include "pldrack.h"
#include "history.h"
using std::wstring;
class Turn;
@ -43,12 +45,17 @@ public:
// Pseudo RTTI
virtual bool isHuman() const = 0;
/// Get the name of the player
const wstring & getName() const { return m_name; }
/// Set the name of the player
void setName(const wstring &iName) { m_name = iName; }
/**************************
* General getters
**************************/
// Get the (possibly incomplete) rack of the player
/// Get the (possibly incomplete) rack of the player
const PlayedRack & getCurrentRack() const;
// Get the previous rack
/// Get the previous rack
const PlayedRack & getLastRack() const;
/// Get the previous move (corresponding to the previous rack...)
const Move & getLastMove() const;
@ -56,6 +63,7 @@ public:
void setCurrentRack(const PlayedRack &iPld);
const History& getHistory() const { return m_history; }
/// Remove last turn
void removeLastTurn();
@ -84,6 +92,9 @@ private:
/// Score of the player
int m_score;
/// Name of the player
wstring m_name;
/// History of the racks and rounds for the player
History m_history;
};

View file

@ -21,6 +21,13 @@
#include <algorithm>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) String
#endif
#include "dic.h"
#include "tile.h"
#include "rack.h"
@ -37,6 +44,9 @@
Training::Training(const Dictionary &iDic)
: Game(iDic)
{
// Training mode implicitly uses 1 human player
Game::addHumanPlayer();
m_players[0]->setName(convertToWc(_("Training")));
}
@ -124,8 +134,6 @@ int Training::start()
if (getNPlayers() != 0)
return 1;
// Training mode implicitly uses 1 human player
Game::addHumanPlayer();
m_currPlayer = 0;
return 0;
}

View file

@ -27,6 +27,7 @@
#include <ctype.h>
#include <fstream>
#include <algorithm>
#include "ncurses.h"
#include "dic.h"
@ -266,14 +267,27 @@ void CursesIntf::drawBoard(WINDOW *win, int y, int x) const
void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const
{
// Compute the longest player name
unsigned int longest = 0;
for (unsigned int i = 0; i < m_game->getNPlayers(); i++)
{
longest = std::max(longest, m_game->getPlayer(i).getName().size());
}
Box box(win, y, x, m_game->getNPlayers() + 2, 25);
box.draw(_("Scores"));
// Magic formula to truncate too long names
unsigned int maxForScores =
std::min(longest,
box.getWidth() - strlen(_("%s: %d")) - 1);
for (unsigned int i = 0; i < m_game->getNPlayers(); i++)
{
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attron(A_BOLD);
mvwprintw(win, y + i + 1, x + 2,
_("Player %d: %d"), i, m_game->getPlayer(i).getPoints());
mvwprintw(win, y + i + 1, x + 2, _("%s: %d"),
truncOrPad(convertToMb(m_game->getPlayer(i).getName()),
maxForScores).c_str(),
m_game->getPlayer(i).getPoints());
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attroff(A_BOLD);
}
@ -283,13 +297,19 @@ void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const
Box box2(win, y + yOff, x, m_game->getNPlayers() + 2, 25);
box2.draw(_("Racks"));
// Magic formula to truncate too long names
unsigned int maxForRacks =
std::min(longest,
box.getWidth() - strlen(_("%s: %ls")) - 4);
for (unsigned int i = 0; i < m_game->getNPlayers(); i++)
{
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attron(A_BOLD);
wstring rack = m_game->getPlayer(i).getCurrentRack().toString(PlayedRack::RACK_SIMPLE);
mvwprintw(win, y + yOff + i + 1, x + 2,
_("Player %d: %ls"), i, rack.c_str());
mvwprintw(win, y + yOff + i + 1, x + 2, _("%s: %ls"),
truncOrPad(convertToMb(m_game->getPlayer(i).getName()),
maxForRacks).c_str(),
rack.c_str());
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attroff(A_BOLD);
// Force to refresh the whole rack