- 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

117
INSTALL
View file

@ -1,83 +1,86 @@
Installation on Linux/Unix
==========================
Installation sous Linux (Un*x) (bien/facile) In the following, do not forget that the ./configure command can take options.
------------------------------ Run ./configure --help to have the list of available options.
* Pour installer à partir de l'archive CVS :
./bootstrap * If you build from a CVS snapshot, run the following commands:
./bootstrap
./configure
make
./configure Then, as root:
make make install
make install
* Pour installer à partir de l'archive tar.gz No graphical interface is built by default, see below for more details.
./configure
make
make install
Il existe en fait 3 versions d'eliot, une en mode texte, une avec une * If you build from a release tarball, run the following commands:
interface curses et une avec wxwidgets. Les modes peuvent être ./configure
sélectionnés à l'aide de la commande configure lors de la compilation make
du programme.
./configure --enable-text --enable-ncurses --enable-wxwidgets Then, as root:
make install
No graphical interface is built by default, see below for more details.
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 : There are 2 ways to proceed:
* directement depuis Windows, en utilisant Cygwin (http://www.cygwin.com/). * cross-compilation from a Linux host, using the mingw32 cross-compiler
* depuis GNU/Linux, en utilisant le cross-compilateur Mingw32. * 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 : * install the build environment (this step is not documented here,
* installation de l'environnement de compilation (cette étape n'est pas as it is out of the scope of this document)
décrite ici, car elle ne rentre pas dans le cadre de ce 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 cd extras/contrib && make all
support de l'unicode
- libiconv (http://www.gnu.org/software/libiconv/), de préférence compilée Eliot dependencies (libiconv, boost, wxWidgets and Qt) will be downloaded
en mode statique (--disable-shared --enable-static) 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 * build Eliot:
(uniquement des headers), donc il n'y a pas vraiment besoin de compiler
* compilation d'Eliot : - if you don't have the 'configure' script, generate it:
- si vous utilisez l'archive CVS, il faut générer le script 'configure'
(aussi bien sous Cygwin que sous GNU/Linux) :
./bootstrap ./bootstrap
- à cause d'un bug de gettext, il faut appliquer un patch aux fichiers installés - because of a bug in gettext, you need to apply a little patch to the files
dans intl/ : installed in the 'intl' directory:
- télécharger le patch ici (lien en haut à gauche) : - download the patch here (link in the top-left-hand corner)
http://www.koders.com/noncode/fid46DF595700FEB564B6EF45BFF55067F95DCF0420.aspx http://www.koders.com/noncode/fid46DF595700FEB564B6EF45BFF55067F95DCF0420.aspx
- exécuter la commande suivante : - apply the patch:
patch -p2 < gettext-win32.patch patch -p2 < gettext-win32.patch
- avec Cygwin, configurer avec la ligne de commande suivante : - configure with the following command:
CPPFLAGS=-I/path/to/installs/include LDFLAGS=-L/path/to/installs/lib \ export INST=`pwd`/extras/contrib/inst && \
CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin" \ CPPFLAGS=-I${INST}/include LDFLAGS=-L${INST}/lib \
./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 \
CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ \ CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ \
./configure --host=i586-mingw32msvc --build=i386-linux \ ./configure --host=i586-mingw32msvc --build=i386-linux \
--enable-wxwidgets --with-wx-config=/path/to/wx-config \ --enable-wxwidgets --with-wx-config=${INST}/bin/wx-config \
--with-boost=/path/to/installs --with-boost=${INST}
en prenant soin de remplacer les différents chemins par les bonnes valeurs.
Ensuite, un simple 'make' suffit pour terminer la compilation, - to compile, run 'make', possibly followed with 'make install'
éventuellement suivi de '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 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= \ libgame_a_SOURCES= \
ai_percent.cpp ai_percent.h \ ai_percent.cpp ai_percent.h \

View file

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

View file

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

View file

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

View file

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

View file

@ -21,6 +21,13 @@
#include <algorithm> #include <algorithm>
#if ENABLE_NLS
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) String
#endif
#include "dic.h" #include "dic.h"
#include "tile.h" #include "tile.h"
#include "rack.h" #include "rack.h"
@ -37,6 +44,9 @@
Training::Training(const Dictionary &iDic) Training::Training(const Dictionary &iDic)
: Game(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) if (getNPlayers() != 0)
return 1; return 1;
// Training mode implicitly uses 1 human player
Game::addHumanPlayer();
m_currPlayer = 0; m_currPlayer = 0;
return 0; return 0;
} }

View file

@ -27,6 +27,7 @@
#include <ctype.h> #include <ctype.h>
#include <fstream> #include <fstream>
#include <algorithm>
#include "ncurses.h" #include "ncurses.h"
#include "dic.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 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 box(win, y, x, m_game->getNPlayers() + 2, 25);
box.draw(_("Scores")); 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++) for (unsigned int i = 0; i < m_game->getNPlayers(); i++)
{ {
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer()) if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attron(A_BOLD); attron(A_BOLD);
mvwprintw(win, y + i + 1, x + 2, mvwprintw(win, y + i + 1, x + 2, _("%s: %d"),
_("Player %d: %d"), i, m_game->getPlayer(i).getPoints()); 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()) if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attroff(A_BOLD); 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); Box box2(win, y + yOff, x, m_game->getNPlayers() + 2, 25);
box2.draw(_("Racks")); 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++) for (unsigned int i = 0; i < m_game->getNPlayers(); i++)
{ {
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer()) if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attron(A_BOLD); attron(A_BOLD);
wstring rack = m_game->getPlayer(i).getCurrentRack().toString(PlayedRack::RACK_SIMPLE); wstring rack = m_game->getPlayer(i).getCurrentRack().toString(PlayedRack::RACK_SIMPLE);
mvwprintw(win, y + yOff + i + 1, x + 2, mvwprintw(win, y + yOff + i + 1, x + 2, _("%s: %ls"),
_("Player %d: %ls"), i, rack.c_str()); truncOrPad(convertToMb(m_game->getPlayer(i).getName()),
maxForRacks).c_str(),
rack.c_str());
if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer()) if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
attroff(A_BOLD); attroff(A_BOLD);
// Force to refresh the whole rack // Force to refresh the whole rack