From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'noncore/games/wordgame') diff --git a/noncore/games/wordgame/.cvsignore b/noncore/games/wordgame/.cvsignore new file mode 100644 index 0000000..d498858 --- a/dev/null +++ b/noncore/games/wordgame/.cvsignore @@ -0,0 +1,6 @@ +moc_* +Makefile +newgamebase.h +rulesbase.h +newgamebase.cpp +rulesbase.cpp diff --git a/noncore/games/wordgame/Makefile.in b/noncore/games/wordgame/Makefile.in new file mode 100644 index 0000000..5627414 --- a/dev/null +++ b/noncore/games/wordgame/Makefile.in @@ -0,0 +1,168 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) +INCPATH = -I$(QPEDIR)/include +LFLAGS = $(SYSCONF_LFLAGS_QT) $(SYSCONF_RPATH_QT) $(SYSCONF_LFLAGS) $(QT_LFLAGS_MT) +LIBS = $(SUBLIBS) -lqpe $(SYSCONF_LIBS_QT) $(SYSCONF_LIBS) $(SYSCONF_LIBS_QTAPP) +MOC = $(SYSCONF_MOC) +UIC = $(SYSCONF_UIC) + +####### Target + +DESTDIR = $(QPEDIR)/bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = wordgame +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = wordgame.h +SOURCES = main.cpp \ + wordgame.cpp +OBJECTS = main.o \ + wordgame.o \ + newgamebase.o \ + rulesbase.o +INTERFACES = newgamebase.ui \ + rulesbase.ui +UICDECLS = newgamebase.h \ + rulesbase.h +UICIMPLS = newgamebase.cpp \ + rulesbase.cpp +SRCMOC = moc_wordgame.cpp \ + moc_newgamebase.cpp \ + moc_rulesbase.cpp +OBJMOC = moc_wordgame.o \ + moc_newgamebase.o \ + moc_rulesbase.o + + +####### Implicit rules + +.SUFFIXES: .cpp .cxx .cc .C .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.C.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + + +all: $(DESTDIR)$(TARGET) + +$(DESTDIR)$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) $(SUBLIBS) + $(SYSCONF_LINK) $(LFLAGS) -o $(DESTDIR)$(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) + +moc: $(SRCMOC) + +tmake: + tmake wordgame.pro + +clean: + -rm -f $(OBJECTS) $(OBJMOC) $(SRCMOC) $(UICIMPLS) $(UICDECLS) + -rm -f *~ core + -rm -f allmoc.cpp + +####### Extension Modules + +listpromodules: + @echo + +listallmodules: + @echo + +listaddonpromodules: + @echo + +listaddonentmodules: + @echo + + +REQUIRES= + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +main.o: main.cpp \ + wordgame.h \ + newgamebase.h \ + rulesbase.h \ + $(QPEDIR)/include/qpe/qdawg.h \ + $(QPEDIR)/include/qpe/applnk.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +wordgame.o: wordgame.cpp \ + wordgame.h \ + newgamebase.h \ + rulesbase.h \ + $(QPEDIR)/include/qpe/qdawg.h \ + $(QPEDIR)/include/qpe/applnk.h \ + $(QPEDIR)/include/qpe/global.h \ + $(QPEDIR)/include/qpe/filemanager.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +newgamebase.h: newgamebase.ui + $(UIC) newgamebase.ui -o $(INTERFACE_DECL_PATH)/newgamebase.h + +newgamebase.cpp: newgamebase.ui + $(UIC) newgamebase.ui -i newgamebase.h -o newgamebase.cpp + +rulesbase.h: rulesbase.ui + $(UIC) rulesbase.ui -o $(INTERFACE_DECL_PATH)/rulesbase.h + +rulesbase.cpp: rulesbase.ui + $(UIC) rulesbase.ui -i rulesbase.h -o rulesbase.cpp + +newgamebase.o: newgamebase.cpp + +rulesbase.o: rulesbase.cpp + +moc_wordgame.o: moc_wordgame.cpp \ + wordgame.h \ + newgamebase.h \ + rulesbase.h \ + $(QPEDIR)/include/qpe/qdawg.h \ + $(QPEDIR)/include/qpe/applnk.h + +moc_newgamebase.o: moc_newgamebase.cpp \ + newgamebase.h + +moc_rulesbase.o: moc_rulesbase.cpp \ + rulesbase.h + +moc_wordgame.cpp: wordgame.h + $(MOC) wordgame.h -o moc_wordgame.cpp + +moc_newgamebase.cpp: newgamebase.h + $(MOC) newgamebase.h -o moc_newgamebase.cpp + +moc_rulesbase.cpp: rulesbase.h + $(MOC) rulesbase.h -o moc_rulesbase.cpp + + diff --git a/noncore/games/wordgame/calcdist b/noncore/games/wordgame/calcdist new file mode 100755 index 0000000..faf31f1 --- a/dev/null +++ b/noncore/games/wordgame/calcdist @@ -0,0 +1,27 @@ +#!/usr/bin/perl + +# Usage: cat dictionaries | grep -v '[^a-z]' | calcdist n score +# +# Given a lot of words, find an appropriate distribution +# into n tiles with tile values proportional to the square root +# of the ratio of score to the tile's frequency. + +$n = shift; +$score = shift; + +while (<>) { + chomp; + for $c ( split "", $_ ) { + $freq{$c}++; + $t++; + } +} + +for $c ( sort { $freq{$a} <=> $freq{$b} } keys %freq ) { + #print "$c: $freq{$c}\n"; + $need = int($freq{$c}*$n/$t+0.5) || 1; + $value = int(sqrt($score/($freq{$c}*$n/$t))+0.5) || 1; + $t -= $freq{$c}; + $n -= $need; + print "$need $c $value\n"; +} diff --git a/noncore/games/wordgame/main.cpp b/noncore/games/wordgame/main.cpp new file mode 100644 index 0000000..cd4600e --- a/dev/null +++ b/noncore/games/wordgame/main.cpp @@ -0,0 +1,34 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "wordgame.h" + +#include + +int main( int argc, char ** argv ) +{ + QPEApplication a( argc, argv ); + + WordGame mw; + //QPEApplication::setInputMethodHint( &mw, QPEApplication::AlwaysOff ); + a.showMainWidget(&mw); + + return a.exec(); +} diff --git a/noncore/games/wordgame/newgamebase.ui b/noncore/games/wordgame/newgamebase.ui new file mode 100644 index 0000000..3b6570b --- a/dev/null +++ b/noncore/games/wordgame/newgamebase.ui @@ -0,0 +1,337 @@ + +NewGameBase + + QWidget + + name + Form1 + + + geometry + + 0 + 0 + 290 + 443 + + + + caption + Form1 + + + layoutMargin + + + layoutSpacing + + + + margin + 8 + + + spacing + 3 + + + QGroupBox + + name + GroupBox1 + + + title + Players + + + layoutMargin + + + layoutSpacing + + + + margin + 7 + + + spacing + 2 + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player0 + + + editable + true + + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player1 + + + editable + true + + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player2 + + + editable + true + + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player3 + + + editable + true + + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player4 + + + editable + true + + + + QComboBox + + + text + + + + + + text + AI3: Smart AI player + + + + name + player5 + + + editable + true + + + + + + QGroupBox + + name + GroupBox2 + + + title + Rules + + + layoutMargin + + + layoutSpacing + + + + margin + 7 + + + spacing + 2 + + + QComboBox + + name + rules + + + sizePolicy + + 3 + 0 + + + + + + + + name + Spacer1 + + + orientation + Vertical + + + sizeType + Expanding + + + sizeHint + + 20 + 20 + + + + sizeHint + + 20 + 20 + + + + + QLayoutWidget + + name + Layout1 + + + + margin + 0 + + + spacing + 6 + + + + name + Horizontal Spacing2 + + + orientation + Horizontal + + + sizeType + Expanding + + + sizeHint + + 20 + 20 + + + + sizeHint + + 20 + 20 + + + + + QPushButton + + name + buttonOk + + + text + &Start + + + autoDefault + true + + + default + true + + + + + + + diff --git a/noncore/games/wordgame/qpe-wordgame.control b/noncore/games/wordgame/qpe-wordgame.control new file mode 100644 index 0000000..2293f52 --- a/dev/null +++ b/noncore/games/wordgame/qpe-wordgame.control @@ -0,0 +1,10 @@ +Files: bin/wordgame apps/Games/wordgame.desktop +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Crossword game + A crossword game for the Qtopia environment. + Play against the computer or human opponents. diff --git a/noncore/games/wordgame/rulesbase.ui b/noncore/games/wordgame/rulesbase.ui new file mode 100644 index 0000000..31cc402 --- a/dev/null +++ b/noncore/games/wordgame/rulesbase.ui @@ -0,0 +1,274 @@ + +RulesBase + + QDialog + + name + RulesBase + + + geometry + + 0 + 0 + 283 + 264 + + + + caption + Game Rules + + + sizeGripEnabled + false + + + + margin + 11 + + + spacing + 6 + + + QLayoutWidget + + name + Layout3 + + + + margin + 0 + + + spacing + 6 + + + QLabel + + name + TextLabel1 + + + text + Name: + + + + QLineEdit + + name + gamename + + + + + + QGroupBox + + name + GroupBox3 + + + title + Board + + + layoutMargin + + + layoutSpacing + + + + margin + 5 + + + spacing + 4 + + + QLabel + + name + TextLabel2 + + + sizePolicy + + 0 + 1 + + + + text + Size: + + + + QSpinBox + + name + width + + + maxValue + 15 + + + minValue + 3 + + + value + 15 + + + + QSpinBox + + name + height + + + maxValue + 15 + + + minValue + 3 + + + value + 15 + + + + QPushButton + + name + editboard + + + text + Edit... + + + + + + QTable + + name + tiletable + + + + QLayoutWidget + + name + Layout3 + + + + margin + 0 + + + spacing + 6 + + + QPushButton + + name + buttonDelete + + + text + Delete + + + autoDefault + true + + + + + name + Horizontal Spacing2 + + + orientation + Horizontal + + + sizeType + Expanding + + + sizeHint + + 20 + 20 + + + + + QPushButton + + name + buttonOk + + + text + &OK + + + autoDefault + true + + + default + true + + + + QPushButton + + name + buttonCancel + + + text + &Cancel + + + autoDefault + true + + + + + + + + + buttonOk + clicked() + RulesBase + accept() + + + buttonCancel + clicked() + RulesBase + reject() + + + diff --git a/noncore/games/wordgame/wordgame.cpp b/noncore/games/wordgame/wordgame.cpp new file mode 100644 index 0000000..ca4352d --- a/dev/null +++ b/noncore/games/wordgame/wordgame.cpp @@ -0,0 +1,1476 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +#include "wordgame.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum RuleEffects { + Multiplier=15, + MultiplyAll=64, + Start=128 +}; + +static const int rack_tiles=7; + +const char* sampleWGR= + "wordgame_shapes\n" + "15 15\n" + "400001040100004\n" + "030000000000030\n" + "002002000200200\n" + "000300020003000\n" + "000020000020000\n" + "102001000100201\n" + "000000202000000\n" + "400200050002004\n" + "000000202000000\n" + "102001000100201\n" + "000020000020000\n" + "000300020003000\n" + "002002000200200\n" + "030000000000030\n" + "400001040100004\n" + "1 2 3 66 67 194 100 0\n" + "1 j 8\n" + "1 q 7\n" + "1 x 6\n" + "1 z 6\n" + "1 w 4\n" + "1 k 4\n" + "1 v 3\n" + "1 f 3\n" + "2 y 3\n" + "2 h 2\n" + "2 b 2\n" + "2 m 2\n" + "3 p 2\n" + "3 g 2\n" + "3 u 2\n" + "4 d 2\n" + "4 c 2\n" + "5 l 1\n" + "5 o 1\n" + "7 t 1\n" + "7 n 1\n" + "7 a 1\n" + "7 r 1\n" + "8 s 1\n" + "8 i 1\n" + "11 e 1\n" + "0\n"; + +WordGame::WordGame( QWidget* parent, const char* name, WFlags fl ) : + QMainWindow(parent, name, fl) +{ + setIcon( Resource::loadPixmap( "wordgame" ) ); + setCaption( tr("Word Game") ); + + setToolBarsMovable( FALSE ); + vbox = new QVBox(this); + + setCentralWidget(vbox); + toolbar = new QPEToolBar(this); + addToolBar(toolbar, Bottom); + reset = new QToolButton(Resource::loadPixmap("back"), tr("Back"), "", this, SLOT(resetTurn()), toolbar); + done = new QToolButton(Resource::loadPixmap("done"), tr("Done"), "", this, SLOT(endTurn()), toolbar); + scoreinfo = new ScoreInfo(toolbar); + scoreinfo->setFont(QFont("Helvetica",10)); + new QToolButton(Resource::loadPixmap("finish"), tr("Close"), "", this, SLOT(endGame()), toolbar); + toolbar->setStretchableWidget(scoreinfo); + + cpu = 0; + board = 0; + bag = 0; + racks = 0; + + aiheart = new QTimer(this); + connect(aiheart, SIGNAL(timeout()), this, SLOT(think())); + + readConfig(); +} + +WordGame::~WordGame() +{ + writeConfig(); +} + +void WordGame::writeConfig() +{ + Config cfg("WordGame"); + cfg.setGroup("Game"); + cfg.writeEntry("NameList",namelist,';'); + cfg.writeEntry("CurrentPlayer",gameover ? 0 : player+1); + if ( !gameover ) { + cfg.writeEntry("Rules",rules); + bag->writeConfig(cfg); + board->writeConfig(cfg); + scoreinfo->writeConfig(cfg); + } + for (int p=0; pwriteConfig(cfg); + } +} + +void WordGame::readConfig() +{ + Config cfg("WordGame"); + cfg.setGroup("Game"); + int currentplayer = cfg.readNumEntry("CurrentPlayer",0); + QStringList pnames = cfg.readListEntry("NameList",';'); + if ( currentplayer ) { + gameover = FALSE; + rules = cfg.readEntry("Rules"); + if ( rules.find("x-wordgamerules") >= 0 ) { + // rules files moved + rules = "Sample.rules"; + } + if ( loadRules(rules) ) { + startGame(pnames); + bag->readConfig(cfg); + board->readConfig(cfg); + scoreinfo->readConfig(cfg); + for (int p=0; preadConfig(cfg); + } + player=currentplayer-1; + readyRack(player); + return; + } + } + // fall-back + openGameSelector(pnames); +} + +void WordGame::openGameSelector(const QStringList& initnames) +{ + toolbar->hide(); + gameover = FALSE; + + delete board; + board = 0; + delete racks; + racks = 0; + + delete cpu; + cpu = 0; + + newgame = new NewGame(vbox); + + //Rules rules(this); + //connect(game.editrules, SIGNAL(clicked()), &rules, SLOT(editRules())); + //connect(&rules, SIGNAL(rulesChanged()), &game, SLOT(updateRuleSets())); + struct passwd* n = getpwuid(getuid()); + QString playername = n ? n->pw_name : ""; + if ( playername.isEmpty() ) { + playername = "Player"; + } + newgame->player0->changeItem(playername,0); + newgame->player1->setCurrentItem(1); + newgame->updateRuleSets(); + newgame->show(); + + connect(newgame->buttonOk, SIGNAL(clicked()), this, SLOT(startGame())); +} + +void WordGame::startGame() +{ + rules = newgame->ruleslist[newgame->rules->currentItem()]; + if ( loadRules(rules) ) { + QStringList names; + names.append(newgame->player0->currentText()); + names.append(newgame->player1->currentText()); + names.append(newgame->player2->currentText()); + names.append(newgame->player3->currentText()); + names.append(newgame->player4->currentText()); + names.append(newgame->player5->currentText()); + delete newgame; + startGame(names); + } else { + // error... + delete newgame; + close(); + } +} + +void WordGame::startGame(const QStringList& playerlist) +{ + toolbar->show(); + racks = new QWidgetStack(vbox); + namelist.clear(); + nplayers=0; + for (QStringList::ConstIterator it=playerlist.begin(); it!=playerlist.end(); ++it) + addPlayer(*it); + scoreinfo->init(namelist); + + if ( nplayers ) { + player=0; + readyRack(player); + } + + board->show(); + racks->show(); +} + +bool WordGame::loadRules(const QString &name) +{ + QString filename = Global::applicationFileName( "wordgame", name ); + QFile file( filename ); + if ( !file.open( IO_ReadOnly ) ) + return FALSE; + + QTextStream ts( &file ); + + QString title = name; + title.truncate( title.length() - 6 ); + setCaption( title ); + + QString shapepixmap; + ts >> shapepixmap; + int htiles,vtiles; + ts >> htiles >> vtiles; + + if ( htiles < 3 || vtiles < 3 ) + return FALSE; + + QPixmap bgshapes = Resource::loadPixmap(shapepixmap); + QString rule_shapes; + for (int i=0; i> line; + rule_shapes += line; + } + static int rule_effects[12]; + int re=0,e; + ts >> e; + while ( e && re < 10 ) { + rule_effects[re] = e; + if ( re++ < 10 ) ts >> e; + } + rule_effects[re++] = 100; // default bonus + board = new Board(bgshapes, htiles, vtiles, vbox); + board->setRules(rule_shapes, rule_effects); + connect(board, SIGNAL(temporaryScore(int)), scoreinfo, SLOT(showTemporaryScore(int))); + + bag = new Bag; + + int count; + ts >> count; + while ( count ) { + QString text; + int value; + ts >> text >> value; + if ( text == "_" ) + text = ""; + + Tile t(text, value); + for (int n=count; n--; ) + bag->add(t); + + ts >> count; + } + + return TRUE; +} + + +NewGame::NewGame(QWidget* parent) : + NewGameBase(parent) +{ +} + +void NewGame::updateRuleSets() +{ + rules->clear(); + + QString rulesDir = Global::applicationFileName( "wordgame", "" ); + QDir dir( rulesDir, "*.rules" ); + ruleslist = dir.entryList(); + if ( ruleslist.isEmpty() ) { + // Provide a sample + QFile file( rulesDir + "Sample.rules" ); + if ( file.open( IO_WriteOnly ) ) { + file.writeBlock( sampleWGR, strlen(sampleWGR) ); + file.close(); + updateRuleSets(); + } + return; + } + int newest=0; + int newest_age=INT_MAX; + QDateTime now = QDateTime::currentDateTime(); + QStringList::Iterator it; + for ( it = ruleslist.begin(); it != ruleslist.end(); ++it ) { + QFileInfo fi((*it)); + int age = fi.lastModified().secsTo(now); + QString name = *it; + name.truncate( name.length()-6 ); // remove extension + rules->insertItem( name ); + if ( age < newest_age ) { + newest_age = age; + newest = rules->count()-1; + } + } + rules->setCurrentItem(newest); +} + +Rules::Rules(QWidget* parent) : + RulesBase(parent,0,TRUE) +{ +} + +void Rules::editRules() +{ + if ( exec() ) { + // ### create a new set of rules + emit rulesChanged(); + } +} + +void Rules::deleteRuleSet() +{ + // ### delete existing rule set + emit rulesChanged(); +} + +void WordGame::addPlayer(const QString& name) +{ + if ( !name.isEmpty() ) { + int colon = name.find(':'); + int cpu = (colon >=0 && name.left(2) == "AI") ? name.mid(2,1).toInt() : 0; + addPlayer(name,cpu); + } +} + +void WordGame::addPlayer(const QString& name, int cpu) +{ + Rack* r = new Rack(rack_tiles,racks); + r->setPlayerName(name); + r->setComputerization(cpu); + racks->addWidget(r, nplayers); + refillRack(nplayers); + namelist.append(name); + + ++nplayers; +} + +void WordGame::nextPlayer() +{ + if ( !refillRack(player) ) { + endGame(); + } else { + player = (player+1)%nplayers; + scoreinfo->setBoldOne(player); + readyRack(player); + } +} + +bool WordGame::mayEndGame() +{ + int out=-1; + int i; + for (i=0; icount() ) + out = i; + if ( out<0 ) { + if ( QMessageBox::warning(this,tr("End game"), + tr("Do you want to end the game early?"), + tr("Yes"), tr("No") )!=0 ) + { + return FALSE; + } + } + return TRUE; +} + +void WordGame::endGame() +{ + if ( gameover ) { + close(); + return; + } + + if ( !mayEndGame() ) + return; + int out=-1; + int totalleft=0; + int i; + for (i=0; icount(); + if ( c ) { + int lose=0; + for ( int j=0; jtileRef(j)->value(); + totalleft += lose; + scoreinfo->addScore(i,-lose); + } else { + out = i; + } + } + int highest=0; + int winner=0; + for (i=0; iplayerScore(i); + if ( s > highest ) { + highest = s; + winner = i; + } + } + if ( out >= 0 ) + scoreinfo->addScore(out,totalleft); + scoreinfo->setBoldOne(winner); + gameover = TRUE; + done->setEnabled(TRUE); + reset->setEnabled(FALSE); +} + +void WordGame::endTurn() +{ + if ( gameover ) { + openGameSelector(namelist); + } else { + if ( board->checkTurn() ) { + if ( board->turnScore() >= 0 ) { + scoreinfo->addScore(player,board->turnScore()); + board->finalizeTurn(); + } else { + QApplication::beep(); + } + nextPlayer(); + } + } +} + +void WordGame::resetTurn() +{ + board->resetRack(); +} + +void WordGame::passTurn() +{ + // ######## trade? + nextPlayer(); +} + +bool WordGame::refillRack(int i) +{ + Rack* r = rack(i); + while ( !bag->isEmpty() && !r->isFull() ) { + r->addTile(bag->takeRandom()); + } + return r->count() != 0; +} + +void WordGame::readyRack(int i) +{ + Rack* r = rack(i); + racks->raiseWidget(i); + board->setCurrentRack(r); + + done->setEnabled( !r->computerized() ); + reset->setEnabled( !r->computerized() ); + + if ( r->computerized() ) { + cpu = new ComputerPlayer(board, r); + aiheart->start(0); + } +} + +Rack* WordGame::rack(int i) const +{ + return (Rack*)racks->widget(i); +} + +void WordGame::think() +{ + if ( !cpu->step() ) { + delete cpu; + cpu = 0; + aiheart->stop(); + if ( board->turnScore() < 0 ) + passTurn(); + else + endTurn(); + } +} + +ComputerPlayer::ComputerPlayer(Board* b, Rack* r) : + board(b), rack(r), best(new const Tile*[rack_tiles]), + best_blankvalues(new Tile[rack_tiles]) +{ + best_score = -1; + across=FALSE; + dict=0; +} + +ComputerPlayer::~ComputerPlayer() +{ + delete [] best; + delete [] best_blankvalues; +} + +bool ComputerPlayer::step() +{ + const QDawg::Node* root = dict ? Global::dawg("WordGame").root() + : Global::fixedDawg().root(); + QPoint d = across ? QPoint(1,0) : QPoint(0,1); + const Tile* tiles[99]; // ### max board size + uchar nletter[4095]; // QDawg only handles 0..4095 + memset(nletter,0,4096); + for (int i=0; icount(); i++) { + const Tile* r = rack->tileRef(i); + if ( r->isBlank() ) + nletter[0]++; + else + nletter[r->text()[0].unicode()]++; + } + Tile blankvalues[99]; // ### max blanks + findBest(current, d, root, 0, nletter, tiles, 0, blankvalues, 0); + if ( ++current.rx() == board->xTiles() ) { + current.rx() = 0; + if ( ++current.ry() == board->yTiles() ) { + if ( across ) { + if ( dict == 1 ) { + if ( best_score >= 0 ) { + rack->arrangeTiles(best,best_n); + rack->setBlanks(best_blankvalues); + board->scoreTurn(best_start, best_n, best_dir); + board->showTurn(); + } + return FALSE; + } + dict++; + across = FALSE; + current = QPoint(0,0); + } else { + across = TRUE; + current = QPoint(0,0); + } + } + } + return TRUE; +} + +void ComputerPlayer::findBest(QPoint at, const QPoint& d, const QDawg::Node* node, ulong used, uchar* nletter, const Tile** tiles, int n, Tile* blankvalues, int blused) +{ + if ( !node ) + return; + QChar l = node->letter(); + const Tile* cur = board->tile(at); + if ( cur ) { + if ( cur->text()[0] == l ) { + bool nextok = board->contains(at+d); + if ( node->isWord() && n && (!nextok || !board->tile(at+d)) ) + noteChoice(tiles,n,d,blankvalues,blused); + if ( nextok ) + findBest(at+d, d, node->jump(), used, nletter, tiles, n, blankvalues, blused); + // #### text()[1]... + } + } else { + if ( nletter[l.unicode()] || nletter[0] ) { + int rc = rack->count(); + ulong msk = 1; + for ( int x=0; xtileRef(x); + if ( t->isBlank() || t->text() == l ) { // #### multi-char value()s + bool nextok = board->contains(at+d); + tiles[n++] = t; + if ( t->isBlank() ) + blankvalues[blused++] = Tile(l,0); + if ( node->isWord() && (!nextok || !board->tile(at+d)) ) + noteChoice(tiles,n,d,blankvalues,blused); + used |= msk; // mark + nletter[t->text()[0].unicode()]--; + if ( nextok ) + findBest(at+d, d, node->jump(), used, nletter, tiles, n, blankvalues, blused); + n--; + nletter[t->text()[0].unicode()]++; + if ( t->isBlank() ) { + // keep looking + blused--; + used &= ~msk; // unmark + } else { + break; + } + } + } + msk <<= 1; + } + } + // #### text()[1]... + } + findBest(at, d, node->next(), used, nletter, tiles, n, blankvalues, blused); +} + +void ComputerPlayer::noteChoice(const Tile** tiles, int n, const QPoint& d, const Tile* blankvalues, int blused) +{ + int s = board->score(current, tiles, n, blankvalues, d, TRUE, 0); +/* +if (s>0 || current==QPoint(5,1)){ +QString st; +for ( int i=0; itext(); +qDebug("%d,%d: %s (%d) for %d",current.x(),current.y(),st.latin1(),n,s); +} +*/ + if ( s > best_score ) { + int i; + for ( i=0; itilesHorizontally()*canvas()->tilesVertically(); + for (int i=0; itile().key() : QString(".") ); + cfg.writeEntry("Board",t,';'); +} + +void Board::readConfig(Config& cfg) +{ + clear(); + QStringList t = cfg.readListEntry("Board",';'); + int i=0; + int h=canvas()->tilesHorizontally(); + for (QStringList::ConstIterator it=t.begin(); it!=t.end(); ++it) { + if ( *it != "." ) { + QPoint p(i%h,i/h); + setTile(p,Tile(*it)); + } + i++; + } + canvas()->update(); +} + +void Board::clear() +{ + int n=canvas()->tilesHorizontally()*canvas()->tilesVertically(); + for (int i=0; iupdate(); +} + +void Board::contentsMousePressEvent(QMouseEvent* e) +{ + dragstart = e->pos(); +} + +void Board::contentsMouseMoveEvent(QMouseEvent* e) +{ + if ( current_rack && !current_rack->computerized() ) { + QPoint d = e->pos() - dragstart; + if ( d.x() <= 0 && d.y() <= 0 ) { + // None + resetRack(); + } else { + int n; + QPoint start=boardPos(dragstart); + QPoint end=boardPos(e->pos()); + QPoint diff=end-start; + QPoint dir; + if ( d.x() > d.y() ) { + n = diff.x()+1; + dir = QPoint(1,0); + } else { + n = diff.y()+1; + dir = QPoint(0,1); + } + + unshowTurn(); + + // Subtract existing tiles from n + QPoint t = start; + for ( int i=n; i--; ) { + if ( contains(t) && tile(t) ) + n--; + t += dir; + } + + // Move start back to real start + while (contains(start-dir) && tile(start-dir)) + start -= dir; + + scoreTurn(start, n, dir); + showTurn(); + } + } +} + +void Board::finalizeTurn() +{ + int i=0; + QPoint at = shown_at; + while ( istate() == TileItem::Floating ) { + current_rack->remove(item(at)->tile()); + setTileState(at,TileItem::Firm); + i++; + } + at += shown_step; + } + canvas()->update(); +} + +void Board::unshowTurn() +{ + int i=0; + QPoint at = shown_at; + while ( icount() && contains(at) ) { + if ( item(at) && item(at)->state() == TileItem::Floating ) { + unsetTile(at); + i++; + } + at += shown_step; + } +} + +void Board::showTurn() +{ + unshowTurn(); + QPoint at = shown_at; + int i=0; + while ( icount() && contains(at) ) { + if ( !tile(at) ) { + Tile t = current_rack->tile(i); + setTile(at,t); + setTileState(at,TileItem::Floating); + i++; + } + at += shown_step; + } + canvas()->update(); +} + +int Board::bonussedValue(const QPoint& at, int base, int& all_mult) const +{ + int rule = rule_shape[idx(at)]-'0'; + int effect = rule_effect[rule]; + int mult = effect&Multiplier; + if ( effect & MultiplyAll ) { + all_mult *= mult; + return base; + } else { + return base * mult; + } +} + +bool Board::isStart(const QPoint& at) const +{ + int rule = rule_shape[idx(at)]-'0'; + int effect = rule_effect[rule]; + return effect&Start; +} + +bool Board::checkTurn() +{ + if ( current_rack->computerized() ) + return TRUE; // computer doesn't cheat, and has already set blanks. + + QPoint at = shown_at; + int n = shown_n; + QPoint d = shown_step; + const Tile* tiles[99]; + Tile blankvalues[99]; + if ( n > current_rack->count() ) + n = current_rack->count(); + + QDialog check(this,0,TRUE); + (new QVBoxLayout(&check))->setAutoAdd(TRUE); + + QHBox mw(&check); + new QLabel(tr("Blanks: "),&mw); + + int bl=0; + QLineEdit* le[99]; + for (int i=0; itileRef(i); + if ( tiles[i]->isBlank() ) { + QLineEdit *l = new QLineEdit(&mw); + le[bl++] = l; + l->setMaxLength(1); + l->setFixedSize(l->minimumSizeHint()); + } + } + + QHBox btns(&check); + connect(new QPushButton(tr("OK"),&btns), SIGNAL(clicked()), &check, SLOT(accept())); + connect(new QPushButton(tr("Cancel"),&btns), SIGNAL(clicked()), &check, SLOT(reject())); + + if ( bl ) { +retry: + if ( !check.exec() ) { + unshowTurn(); + canvas()->update(); + return FALSE; + } + + for (int b=0; btext(); + blankvalues[b]=Tile(v,0); + if ( v.length() != 1 ) + goto retry; + } + } + + QStringList words; + unshowTurn(); + turn_score = score(at,tiles,n,blankvalues,d,FALSE,&words); + showTurn(); + QStringList to_add; + for (QStringList::Iterator it=words.begin(); it!=words.end(); ++it) { + if ( !Global::fixedDawg().contains(*it) + && !Global::dawg("WordGame").contains(*it) ) { + switch (QMessageBox::warning(this, tr("Unknown word"), + tr("

The word \"%1\" is not in the dictionary.").arg(*it), + tr("Add"), tr("Ignore"), tr("Cancel"))) + { + case 0: + // ####### add to wordgame dictionary + to_add.append(*it); + break; + case 1: + break; + case 2: + unshowTurn(); + canvas()->update(); + return FALSE; + } + } + } + if ( to_add.count() ) + Global::addWords("WordGame",to_add); + return TRUE; +} + +void Board::scoreTurn(const QPoint& at, int n, const QPoint& d) +{ + unshowTurn(); + shown_at = at; + shown_n = n; + shown_step = d; + const Tile* tiles[99]; + if ( n > current_rack->count() ) + n = current_rack->count(); + for (int i=0; itileRef(i); + turn_score = score(at,tiles,n,0,d,FALSE,0); + emit temporaryScore(turn_score); +} + +int Board::score(QPoint at, const Tile** tiles, int n, const Tile* blankvalue, const QPoint& d, bool checkdict, QStringList* words) const +{ + int total=0; + int totalsidetotal=0; + + // words gets filled with words made + + // mainword==0 -> + // Checks side words, but not main word + + // -1 means words not in dict, or illegally positioned (eg. not connected) + + // text is assumed to fit on board. + + if ( words ) *words=QStringList(); + + QPoint otherd(d.y(), d.x()); + + int all_mult = 1; + int bl=0; + + bool connected = FALSE; + + QString mainword=""; + + if ( contains(at-d) && tile(at-d) ) { + return -1; // preceeding tiles + } + + const Tile* t; + for (int i=0; contains(at) && ((t=tile(at)) || itext(); + total += t->value(); + connected = TRUE; + } else { + QString sideword; + QString tt; + if ( tiles[i]->isBlank() ) { + if ( blankvalue ) + tt = blankvalue[bl++].text(); + } else { + tt = tiles[i]->text(); + } + sideword=tt; + if ( checkdict || words ) mainword += tt; + int side_mult = 1; + int tilevalue = bonussedValue(at,tiles[i]->value(),side_mult); + all_mult *= side_mult; + if ( !connected && isStart(at) ) + connected = TRUE; + total += tilevalue; + int sidetotal = tilevalue; + { + QPoint side = at-otherd; + + while ( contains(side) && (t=tile(side)) ) { + sidetotal += t->value(); + sideword.prepend(t->text()); + side -= otherd; + } + } + { + QPoint side = at+otherd; + while ( contains(side) && (t=tile(side)) ) { + sidetotal += t->value(); + sideword.append(t->text()); + side += otherd; + } + } + if ( sideword.length() > 1 ) { + if ( words ) + words->append(sideword); + if ( checkdict && !Global::fixedDawg().contains(sideword) + && !Global::dawg("WordGame").contains(sideword) ) + return -1; + totalsidetotal += sidetotal * side_mult; + connected = TRUE; + } + i++; + } + at += d; + } + + if ( words ) + words->append(mainword); + if ( checkdict && !Global::fixedDawg().contains(mainword) + && !Global::dawg("WordGame").contains(mainword) ) + return -1; + + if ( n == rack_tiles ) + totalsidetotal += rack_tiles_bonus; + + return connected ? totalsidetotal + total * all_mult : -1; +} + +QPoint Board::boardPos(const QPoint& p) const +{ + return QPoint(p.x()/canvas()->tileWidth(), p.y()/canvas()->tileHeight()); +} + +void Board::contentsMouseReleaseEvent(QMouseEvent*) +{ + if ( current_rack ) { + } +} + + +void Board::setRules(const QString& shapes, const int* effects) +{ + rule_shape=shapes; rule_effect=effects; + int i=0; + int maxre=0; + for (int y=0; y maxre ) maxre = re; + canvas()->setTile(x,y,re); + } + } + rack_tiles_bonus=effects[maxre+1]; +} + +void Board::unsetTile(const QPoint& p) +{ + delete item(p); + grid[idx(p)] = 0; +} + +void Board::setTile(const QPoint& p, const Tile& t) +{ + TileItem* it=item(p); + if ( !it ) { + it = grid[idx(p)] = new TileItem(t,FALSE,canvas()); + it->move(p.x()*canvas()->tileWidth(), p.y()*canvas()->tileHeight()); + it->show(); + } else { + it->setTile(t); + } +} + +Rack::Rack(int ntiles, QWidget* parent) : QCanvasView( + new QCanvas(ntiles*TileItem::bigWidth(),TileItem::bigHeight()), + parent), + item(ntiles) +{ + setLineWidth(1); + setFixedHeight(sizeHint().height()); + n = 0; + for (int i=0; isetBackgroundColor(gray); + dragging = 0; +} + +Rack::~Rack() +{ + clear(); + delete canvas(); +} + +void Rack::clear() +{ + for (int i=0; imove(x++,0); + i->show(); + item[n++] = i; + } + layoutTiles(); +} + +static int cmp_tileitem(const void *a, const void *b) +{ + const TileItem* ia = *(TileItem**)a; + const TileItem* ib = *(TileItem**)b; + return int(ia->x() - ib->x()); +} + +void Rack::layoutTiles() +{ + int w = TileItem::bigWidth()+2; + + if ( dragging ) dragging->moveBy(dragging_adj,0); + qsort(item.data(), n, sizeof(TileItem*), cmp_tileitem); + if ( dragging ) dragging->moveBy(-dragging_adj,0); + + for (int i=0; isetZ(1); + } else { + item[i]->move(i*w, 0); + item[i]->setZ(0); + } + canvas()->update(); +} + +void Rack::setBlanks(const Tile* bv) +{ + for (int j=0; jtile(); + if ( tt.isBlank() ) { + tt.setText(bv->text()); + item[j]->setTile(tt); + bv++; + } + } +} + +bool Rack::arrangeTiles(const Tile** s, int sn) +{ + bool could = TRUE; + for (int j=0; jtile(); + int f=-1; + for (int i=0; i= 0 ) { + item[j]->move(f-999,0); + } else { + could = FALSE; + } + } + layoutTiles(); + return could; +} + +void Rack::addTile(const Tile& t) +{ + TileItem *i = new TileItem(t,TRUE,canvas()); + i->show(); + item[n++] = i; + layoutTiles(); +} + +void Rack::remove(Tile t) +{ + for (int i=0; itile() == t ) { + remove(i); + return; + } +} + +void Rack::remove(int i) +{ + delete item[i]; + n--; + for (;iresize(width()-frameWidth()*2,height()-frameWidth()*2); + QCanvasView::resizeEvent(e); +} + +void Rack::contentsMousePressEvent(QMouseEvent* e) +{ + if ( computerized() ) + return; + QCanvasItemList list = canvas()->collisions(e->pos()); + if (list.count()) { + dragging = list.first(); + dragstart = e->pos()-QPoint(int(dragging->x()),int(dragging->y())); + } else { + dragging = 0; + } +} + +void Rack::contentsMouseMoveEvent(QMouseEvent* e) +{ + if ( computerized() ) + return; + //int w = TileItem::bigWidth()+2; + if ( dragging ) { + dragging_adj = TileItem::bigWidth()/2; + if ( dragging->x() > e->x()-dragstart.x() ) + dragging_adj = -dragging_adj; + dragging->move(e->x()-dragstart.x(),0); + layoutTiles(); + } +} + +void Rack::contentsMouseReleaseEvent(QMouseEvent* e) +{ + if ( computerized() ) + return; + if ( dragging ) { + dragging=0; + layoutTiles(); + } +} + +Tile::Tile(const QString& key) +{ + int a=key.find('@'); + txt = key.left(a); + val = key.mid(a+1).toInt(); + blank = txt.isEmpty(); +} + +QString Tile::key() const +{ + return txt+"@"+QString::number(val); +} + +Bag::Bag() +{ + tiles.setAutoDelete(TRUE); +} + +void Bag::writeConfig(Config& cfg) +{ + QStringList t; + for (QListIterator it(tiles); it; ++it) + t.append((*it)->key()); + cfg.writeEntry("Tiles",t,';'); +} + +void Bag::readConfig(Config& cfg) +{ + tiles.clear(); + QStringList t = cfg.readListEntry("Tiles",';'); + for (QStringList::ConstIterator it=t.begin(); it!=t.end(); ++it ) + add(Tile(*it)); +} + +void Bag::add(const Tile& t) +{ + tiles.append(new Tile(t)); +} + +Tile Bag::takeRandom() +{ + Tile* rp = tiles.take(random()%tiles.count()); + Tile r=*rp; + return r; +} + +ScoreInfo::ScoreInfo( QWidget* parent, const char* name, WFlags fl ) : + QLabel("

",parent,name,fl) +{ + score=0; + msgtimer = new QTimer(this); + connect(msgtimer, SIGNAL(timeout()), this, SLOT(showScores())); + setBackgroundMode( PaletteButton ); +} + +ScoreInfo::~ScoreInfo() +{ + if ( score ) delete [] score; +} + +void ScoreInfo::writeConfig(Config& cfg) +{ + QStringList l; + for (int i=0; i<(int)names.count(); i++) + l.append(QString::number(score[i])); + cfg.writeEntry("Scores",l,';'); +} + +void ScoreInfo::readConfig(Config& cfg) +{ + QStringList l = cfg.readListEntry("Scores",';'); + int i=0; + for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it ) + score[i++]=(*it).toInt(); + showScores(); +} + + +QSize ScoreInfo::sizeHint() const +{ + return QSize(QLabel::sizeHint().width(),fontMetrics().height()); +} + +void ScoreInfo::init(const QStringList& namelist) +{ + names = namelist; + if ( score ) delete [] score; + score = new int[names.count()]; + memset(score,0,sizeof(int)*names.count()); + boldone = -1; + showScores(); +} + +void ScoreInfo::addScore(int player, int change) +{ + score[player] += change; + showScores(); +} + +void ScoreInfo::setBoldOne(int b) +{ + boldone=b; + showScores(); +} + +void ScoreInfo::showScores() +{ + QString r="

"; + int i=0; + //int spl=(names.count()+1)/2; // 2 lines + for (QStringList::ConstIterator it=names.begin(); it!=names.end(); ) { + if ( i==boldone ) r += ""; + QString n = *it; + n.replace(QRegExp(":.*"),""); + r += n; + r += ":"; + r += QString::number(score[i]); + if ( i==boldone ) r += ""; + + ++i; + ++it; + if ( it != names.end() ) + r += " "; + } + setText(r); +} + +void ScoreInfo::showTemporaryScore(int amount) +{ + if ( amount < 0 ) + setText(tr("

Invalid move")); + else + setText(tr("

Score: ")+QString::number(amount)); + msgtimer->start(3000,TRUE); +} + diff --git a/noncore/games/wordgame/wordgame.h b/noncore/games/wordgame/wordgame.h new file mode 100644 index 0000000..0ffa56a --- a/dev/null +++ b/noncore/games/wordgame/wordgame.h @@ -0,0 +1,376 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef WORDGAME_H +#define WORDGAME_H + +#include "newgamebase.h" +#include "rulesbase.h" + +#include +#include + +#include +#include +#include + +class QVBox; +class QLabel; +class QWidgetStack; +class QToolButton; +class Config; + +class Tile { +public: + Tile() {} + + Tile(const Tile& t) + { + txt = t.txt; + val = t.val; + blank = t.blank; + } + + Tile(QString text, int value) + { + txt = text; + val = value; + blank = txt.isEmpty(); + } + + Tile(const QString& key); + + int value() const { return val; } + bool isBlank() const { return blank; } + QString text() const { return txt; } + void setText(const QString& t) + { + txt = t; + } + + int operator==(const Tile& o) const + { return o.txt == txt && o.val == val && o.blank == blank; } + int operator!=(const Tile& o) const + { return !operator==(o); } + Tile& operator=(const Tile& o) + { txt=o.txt; val=o.val; blank=o.blank; return *this; } + + QString key() const; + +private: + QString txt; + int val; + bool blank; +}; + +class Bag { +public: + Bag(); + + void readConfig(Config&); + void writeConfig(Config&); + + void add(const Tile&); + bool isEmpty() const { return tiles.isEmpty(); } + Tile takeRandom(); +private: + QList tiles; +}; + +class TileItem : public QCanvasRectangle { +public: + TileItem(const Tile& tile, bool b, QCanvas* c) : + QCanvasRectangle(0,0, + b?bigWidth():smallWidth(), + b?bigHeight():smallHeight(),c), + t(tile), big(b), s(Firm) + { + } + + static int smallWidth(); + static int smallHeight(); + static int bigWidth(); + static int bigHeight(); + + enum State { Firm, Floating }; + void setState( State state ); + State state() const { return s; } + const Tile& tile() const { return t; } + void setTile(const Tile&); + void setBig(bool); + +protected: + void drawShape(QPainter&); + +private: + Tile t; + bool big; + State s; +}; + +class Rack : public QCanvasView { +public: + Rack(int ntiles, QWidget* parent); + ~Rack(); + + void readConfig(Config&); + void writeConfig(Config&); + + bool isFull() const { return count()==max(); } + int max() const { return item.count(); } + int count() const { return n; } + void addTile(const Tile& t); + Tile tile(int i) const { return item[i]->tile(); } + const Tile* tileRef(int i) const { return &item[i]->tile(); } + void remove(int i); + void remove(Tile); + bool arrangeTiles(const Tile** s, int sn); + void setBlanks(const Tile*); + + void setPlayerName(const QString& name) { nm = name; } + QString playerName() const { return nm; } + void setComputerization(int level) { cpu=level; } + bool computerized() const { return cpu>0; } + +protected: + void resizeEvent(QResizeEvent*e); + void contentsMousePressEvent(QMouseEvent*); + void contentsMouseMoveEvent(QMouseEvent*); + void contentsMouseReleaseEvent(QMouseEvent*); + +private: + void clear(); + void layoutTiles(); + int n; + QArray item; + int dragging_adj; + QPoint dragstart; + QCanvasItem* dragging; + QString nm; + int cpu; +}; + +class Board : public QCanvasView { + Q_OBJECT +public: + Board(QPixmap bgshapes, int w, int h, QWidget* parent); + ~Board(); + + void readConfig(Config&); + void writeConfig(Config&); + + int xTiles() const { return canvas()->tilesHorizontally(); } + int yTiles() const { return canvas()->tilesVertically(); } + + bool contains(const QPoint& p) const + { return p.x() >= 0 && p.y() >= 0 + && p.x() < canvas()->tilesHorizontally() + && p.y() < canvas()->tilesVertically(); } + const Tile* tile(const QPoint& p) const + { TileItem* it=item(p); return it ? &it->tile() : 0; } + + void setRules(const QString& shapes, const int* effects); + + void clear(); + void unsetTile(const QPoint& p); + void setTile(const QPoint& p, const Tile& t); + + void setTileState(const QPoint& p, TileItem::State s) + { + TileItem* it=item(p); + if (it) it->setState(s); + } + + void setCurrentRack(Rack*); + void resetRack(); + void finalizeTurn(); + void showTurn(); + void scoreTurn(const QPoint& at, int n, const QPoint& d); + bool checkTurn(); + int score(QPoint at, const Tile** tiles, int n, + const Tile* blankvalue, + const QPoint& d, bool ignoredict, QStringList* words) const; + int bonussedValue(const QPoint& at, int base, int& all_mult) const; + bool isStart(const QPoint& at) const; + + int turnScore() const { return turn_score; } + +signals: + void temporaryScore(int); + +protected: + void contentsMousePressEvent(QMouseEvent*); + void contentsMouseMoveEvent(QMouseEvent*); + void contentsMouseReleaseEvent(QMouseEvent*); + +private: + int idx(const QPoint& p) const + { return p.x()+p.y()*canvas()->tilesHorizontally(); } + TileItem*& item(const QPoint& p) const + { return grid[idx(p)]; } + TileItem **grid; + QString rule_shape; + const int* rule_effect; + int rack_tiles_bonus; + Rack* current_rack; + QPoint boardPos(const QPoint&) const; + QPoint dragstart; + QPoint shown_at; + int shown_n; + QPoint shown_step; + void unshowTurn(); + int turn_score; +}; + +class ComputerPlayer +{ + Board* board; + Rack* rack; + + bool across; + int dict; + QPoint current; + + const Tile** best; + int best_n; + Tile* best_blankvalues; + int best_blused; + int best_score; + QPoint best_dir; + QPoint best_start; + +public: + ComputerPlayer(Board* b, Rack* r); + ~ComputerPlayer(); + + bool step(); + +private: + void findBest(QPoint at, const QPoint& d, const QDawg::Node* node, ulong used, uchar *nletter, const Tile** tiles, int n, Tile* blankvalues, int blused); + void noteChoice(const Tile** tiles, int n, const QPoint& d, const Tile* blankvalues, int blused); +}; + +class ScoreInfo : public QLabel { + Q_OBJECT +public: + ScoreInfo( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~ScoreInfo(); + + void init(const QStringList&); + void addScore(int player, int change); + int playerScore(int player) const { return score[player]; } + void setShowWinner(bool); + void setBoldOne(int); + + void readConfig(Config&); + void writeConfig(Config&); + +protected: + QSize sizeHint() const; + +public slots: + void showTemporaryScore(int amount); + +private slots: + void showScores(); + +private: + QStringList names; + int *score; + QTimer* msgtimer; + bool showwinner; + int boldone; +}; + +class NewGame; + +class WordGame : public QMainWindow { + Q_OBJECT +public: + WordGame( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~WordGame(); + +private slots: + void endTurn(); + void resetTurn(); + void passTurn(); + void think(); + void endGame(); + void startGame(); + +private: + void writeConfig(); + void readConfig(); + + void startGame(const QStringList& pnames); + bool mayEndGame(); + void openGameSelector(const QStringList& initnames); + bool loadRules(const QString& filename); + void addPlayer(const QString& name); + void addPlayer(const QString& name, int cpu); + void nextPlayer(); + bool refillRack(int i); + void readyRack(int i); + Rack* rack(int i) const; + + QWidgetStack *racks; + QToolBar* toolbar; + QVBox *vbox; + Board *board; + Bag *bag; + ScoreInfo *scoreinfo; + QToolButton *done; + QToolButton *reset; + QTimer* aiheart; + ComputerPlayer *cpu; + int player; + int nplayers; + QStringList namelist; + bool gameover; + QString rules; + NewGame* newgame; +}; + +class NewGame : public NewGameBase { + Q_OBJECT +public: + NewGame(QWidget* parent); + QStringList ruleslist; + +public slots: + void updateRuleSets(); +}; + +class Rules : public RulesBase { + Q_OBJECT + +public: + Rules(QWidget* parent); + +signals: + void rulesChanged(); + +public slots: + void editRules(); + +private: + void deleteRuleSet(); +}; + +#endif // WORDGAME_H diff --git a/noncore/games/wordgame/wordgame.pro b/noncore/games/wordgame/wordgame.pro new file mode 100644 index 0000000..7feacf9 --- a/dev/null +++ b/noncore/games/wordgame/wordgame.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = wordgame.h +SOURCES = main.cpp \ + wordgame.cpp +INTERFACES = newgamebase.ui rulesbase.ui +TARGET = wordgame +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/wordgame.ts -- cgit v0.9.0.2