author | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
---|---|---|
committer | kergoth <kergoth> | 2002-01-25 22:14:26 (UTC) |
commit | 15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff) | |
tree | c2fa0399a2c47fda8e2cd0092c73a809d17f68eb /noncore/games | |
download | opie-15318cad33835e4e2dc620d033e43cd930676cdd.zip opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2 |
Initial revision
145 files changed, 21180 insertions, 0 deletions
diff --git a/noncore/games/chess/Makefile.in b/noncore/games/chess/Makefile.in new file mode 100644 index 0000000..7354d76 --- a/dev/null +++ b/noncore/games/chess/Makefile.in @@ -0,0 +1,134 @@ +############################################################################# + +####### Compiler, tools and options + +CXX = $(SYSCONF_CXX) $(QT_CXX_MT) +CXXFLAGS= $(SYSCONF_CXXFLAGS_QT) $(SYSCONF_CXXFLAGS) -DQCONFIG=\"qpe\" +CC = $(SYSCONF_CC) $(QT_C_MT) +CFLAGS = $(SYSCONF_CFLAGS) -DQCONFIG=\"qpe\" +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 = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = chess +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = chess.h +SOURCES = chess.cpp \ + main.cpp +OBJECTS = chess.o \ + main.o \ + mainwindow.o +INTERFACES = mainwindow.ui +UICDECLS = mainwindow.h +UICIMPLS = mainwindow.cpp +SRCMOC = moc_chess.cpp \ + moc_mainwindow.cpp +OBJMOC = moc_chess.o \ + moc_mainwindow.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 chess.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 + +chess.o: chess.cpp \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/resource.h \ + chess.h + +main.o: main.cpp \ + mainwindow.h + +mainwindow.h: mainwindow.ui + $(UIC) mainwindow.ui -o $(INTERFACE_DECL_PATH)/mainwindow.h + +mainwindow.cpp: mainwindow.ui + $(UIC) mainwindow.ui -i mainwindow.h -o mainwindow.cpp + +mainwindow.o: mainwindow.cpp \ + mainwindow.h \ + mainwindow.ui + +moc_chess.o: moc_chess.cpp \ + chess.h + +moc_mainwindow.o: moc_mainwindow.cpp \ + mainwindow.h + +moc_chess.cpp: chess.h + $(MOC) chess.h -o moc_chess.cpp + +moc_mainwindow.cpp: mainwindow.h + $(MOC) mainwindow.h -o moc_mainwindow.cpp + + diff --git a/noncore/games/chess/boardview.cw b/noncore/games/chess/boardview.cw new file mode 100644 index 0000000..020af96 --- a/dev/null +++ b/noncore/games/chess/boardview.cw @@ -0,0 +1,23 @@ +<!DOCTYPE CW><CW> +<customwidgets> + <customwidget> + <class>BoardView</class> + <header location="global">/home/luke/depot/qpe/chess/chess.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + </sizepolicy> + <pixmap> + <data format="XPM.GZ" length="4605">789c6dd7d96ee33a1206e0fb7e8aa0ebae31a863c9966d613017d9e3ecce9e0ce6a228c94b6c67f192d83998771f9af517e10493b4daf89a25b258a428f75f7fb61e2ecfb6fefcf56b3697f9b0d82a0632ddfa532e2693d5bffff3afbf7ffd4ed3adf027d94a7fffe3d76ff7b9556c9dbfbe5401ef9bf8d8c464136f9b186ee27513cf9bd8dec47c13d30d74bfb52c3d28cdd322a9058fd6aee7f5a29e047f697bbd96b483573fe2173ffc82fbdbb87fb0762389fdcdd6ee859fe0716ccfd7e6def7fed8c5f1d5c5f77c58c2788959ea70230dfd3982dba9de7f6ff9693b757ee4dbb7f9a3fdf5473d7aea464dfb23fa3e3fdafe319f3d75a3a1edbc0fb7913f9991df8b19f7977081f1ae83c5da89cd8dd0bf34601bffceaced14facfd22c53f36db484f95570a9e3398ed6f1c27ec8c4e239877378d79c85bd4f477089f117d1219ee666c4d7d4cd04fddd98d1de5ebb995abc3ca863fb04467eb26746fc398c7ce5c0aced7c1dade3bfc2983f5766acf7be19f59f466b3d4b752bc1fd9a9f58ffd28311cf6d33f2b9323735ff17752bc17855b4f697c119f2cbcd884fe15cd757d6c711b5ea2dd48766708efd959871ffb319f53c86ad1e67d1fafc89ba9d60bcaf68edffca8ce7ab8033c4b7a2b57e3bc1ae95b7eac1db70091fa9db895a6e61ab472b3af4277730e6cb5d33e69bc3781e6865c6f31ce6d3f6f9b75c881738d3f5e2b119ed27708ef655b4aedf0d6cf5fc50e709f27d84510fb930e3f94a615bdf6bb3f627f7b0cd47f3f5f36d877a5103b67af6cddace23759e20fe00b6e77da016acb77370a6e71df5cc18bf1fadfb610c0bcef304ae6aeab619ef83f57b92f286e5c3cfd1a1de3c803378095bbd9bea98cf305af7430b16d47319adf53f34637daee00af9f7d52ed57c692f5acf7fbdbfc8f3bc113c834be43b35a37d185d84feeed482fd47e77086fdbf0b57d81f75b54b311f8ad6f95e9a319f1adc44fed3689ddf132c589f8e59e385a3b5fdcc8cf1bb30d697a2311eea53a07e1cce7b6948a2f52007676ad956bb14e7e53e6cebb382adff67339eb7a5dac6930f33ce87266cf5388dd6f50ccf83f87a8baed77bb4aed78edaa5c877085738ff3fcdd89f13b58d4f68b7f1e5d48cfd589a118ff10bd49b9ea235fe12aef0fc55669c6fe17c718d42701ececcfafea2118cfb3935e3bcf98cd6f18ecc785fbd99f1beabab4bab77c38cef2b613d5c5908ced357b8c2799aa9637c12ade32dcc787fedc04d7c1fb935e33c7b8cd6f509df578aac10acef02aef0bc76ccbade7caeb6fb656ec6fe1c98f1fc5ec2a82f9f9931bf5ab4e67b0263bf70d80f455956e8efc6acf9d185ba4a51bfb119e779789f97be7f9d1fbda9637b19adf73b33e21fe026ea7162c6f31ad6a7acaad4e9fe1fc1d6be1badf53b36a39e4fb0e5771f1dda257c7fa89a668a76657013b6f509eb5bf99f225bbb3b5fff32b1b0e3c25fffefb3d4288de78a7bdce7010ffdf5cca38dabef7fc73ce1177fcf6b8c77fcc6ef3cf56d6f3ce3392ff8833f79c92bfee26ddef1f1bbbcc785c6f3be8f3be0433ef2b11d3ee6133ee5333ee70bbee42e5ff135dff02ddff13d5388179fc5d4f7f4c08ffcc4354e38e53a3738f39f4d6e719b73ce898958d7a7c74312725450491537a9477d1ad0909e69e4e39b34a609bdf01dbdb2d6abf0fd3ff8e8377aa729cd684e8b704de8833e69e97f57f4e5fbdf8efd3fd30eed724a7bb44f733ff6fa3ae0aebf6be5a30f7d2f473ebe8378f1f1c77442a77416fb3ea70bba0c77f47c465dbaa2eb6ffddfd0adefddfabea37b7aa0477aa21a25beff25a5a17fcbff994a4ea88ebe1b9451d3d734a116b529f7d15df1cbefe71bfbe753ba145af72d224e7ca5f84c4aa9bc7b7edca5f4bfe72f03df3ea485f83b652463bf0a19d765e2df012febfcb9f53d7f79f5f16ff22e5399c95c16f2219f7ec512ffe9eb232bf9fa96ff48b67ddb8eecca9eef719fbb72208772b45ee175fda523c7dff2efcb899cfad57a973339478de672219721ba2b573fea3fe61db9f6792eb9292c37722b77d4926558dbaecfa62ff73eff4eec7fc2d7f2208f612dfde5ef3c44e493cfa523354924953af22fa5e1f7f7adaf9dff4f9d5fcb25aeae7468202d1fdd96dcb123ddcfe179d9f3fbef3a5c95131abbf54fc1fe0deb3771e9a32bd7e35e7cbefc4e757d377043f78c6be4af71f87be25edcab7b73ef6eaaf16eb67e92dddc2ddc87fbf4ff6e9f9ffe73e93f57eecb6dfb081ff7fbbffffcf53f54dd2532</data> + </pixmap> + <slot access="public">newGame()</slot> + <slot access="public">swapSides()</slot> + <slot access="public">setTheme(QString)</slot> + </customwidget> +</customwidgets> +</CW> diff --git a/noncore/games/chess/chess.cpp b/noncore/games/chess/chess.cpp new file mode 100644 index 0000000..96a838a --- a/dev/null +++ b/noncore/games/chess/chess.cpp @@ -0,0 +1,358 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + + +// human is not offered a promotion yet + +#include <qcanvas.h> +#include <qmainwindow.h> +#include <qlist.h> +#include <qimage.h> +#include <qpainter.h> +#include <qmessagebox.h> +#include <qregexp.h> + +#include <qpe/config.h> +#include <qpe/resource.h> + +#include "chess.h" + +#define CHESS_DEBUG + +int pieceSize = 40; +static QVector < QImage > imgList; +int timeMoves, timeTime; + +int BoardView::convertToRank(int r) +{ + r = r / pieceSize; + if (humanSide == sideWhite) + r = 8 - r; + else + r++; + return r; +} + +char BoardView::convertToFile(int f) +{ + f = f / pieceSize; + if (humanSide == sideWhite) + return f + 'a'; + else + return 'h' - f; +} + +int BoardView::convertFromFile(char f) +{ + if (humanSide == sideWhite) + f = f - 'a'; + else + f = 'h' - f; + return f * pieceSize; +} + +int BoardView::convertFromRank(int r) +{ + if (humanSide == sideWhite) + r = 8 - r; + else + r--; + return r * pieceSize; +} + +// Pieces +Piece::Piece(QCanvas * canvas, int t):QCanvasRectangle(canvas) +{ + type = t; + setSize(pieceSize, pieceSize); + show(); +} + +Piece *BoardView::newPiece(int t, char f, int r) +{ + Piece *tmpPiece = new Piece(canvas(), t); + tmpPiece->move(convertFromFile(f), convertFromRank(r)); + list.append(tmpPiece); + return tmpPiece; +} + +void BoardView::deletePiece(Piece * p) +{ + list.remove(p); + canvas()->update(); +} + +void Piece::drawShape(QPainter & p) +{ + p.drawImage(int (x()), int (y()), *(imgList[type])); +} + +void BoardView::buildImages(QImage theme) +{ + imgList.resize(12); + int x; + int y = 0; + + for (int j = 0; j < 2; j++) { + x = 0; + for (int i = 0; i < 6; i++) { + imgList.insert(i + (j * 6), + new QImage(theme. + copy(x, y, pieceSize, pieceSize))); + x += pieceSize; + } + y += pieceSize; + } +} + +void BoardView::readStdout() +{ + QString input( crafty->readStdout() ); +#ifdef CHESS_DEBUG + qDebug("received this string from crafty->\n%s\n", input.latin1()); +#endif + + int startPosition = input.find("setboard"); + if (startPosition != -1) + decodePosition(input.remove(0, startPosition + 9)); + + if (input.contains("Black mates")) { + playingGame = FALSE; + emit(showMessage("Black mates")); + } else if (input.contains("White mates")) { + playingGame = FALSE; + emit(showMessage("White mates")); + } else if (input.contains(" resigns")) { + playingGame = FALSE; + emit(showMessage("Computer resigns")); + } else if (input.contains("Draw")) { + playingGame = FALSE; + emit(showMessage("Draw")); + } +} + +// this is pretty close to getting done right +// maybe dont use sprites and just draw a picture +// there'll be lots of drawing done anyway +// eg creating pictures for the webpages, +// and presenting options for promotions +void BoardView::decodePosition(const QString & t) +{ + qDebug("decode copped %s \n", t.latin1()); + + int count = 0; + int stringPos = 0; + for (int file = 0; file < 8; file++) { + for (int rank = 0; rank < 8; rank++) { + if (count) + count--; + else { + if (t.at(stringPos).isNumber()) + count = t.at(stringPos).digitValue(); + else { + newPiece(t.at(stringPos).latin1(), 'a' + file, + rank + 1); + } + } + } + } +} + +void BoardView::undo() +{ + crafty->writeToStdin("undo\n"); + crafty->writeToStdin("savepos\nclock\n"); +} + +void BoardView::emitErrorMessage() +{ + if (activeSide != humanSide) + emit(showMessage("Not your move")); + else + emit(showMessage("You are not playing a game")); +} + +void BoardView::annotateGame() +{ + crafty-> + writeToStdin + ("savegame game.save\nannotateh game.save bw 0 1.0 1\n"); + emit(showMessage("Annotating game")); +} + +Piece *BoardView::findPiece(char f, int r) +{ + QListIterator < Piece > it(list); + Piece *tmpPiece; + for (; it.current(); ++it) { + tmpPiece = it.current(); + if (convertToRank(tmpPiece->x()) == r + && convertToFile(tmpPiece->y()) == f) + return tmpPiece; + } + return 0; +} + +void BoardView::newGame() +{ + activeSide = sideWhite; + emit(showMessage("New game")); + crafty->writeToStdin("new\n"); + crafty->writeToStdin("savepos\n"); + crafty->writeToStdin("time " + + QString::number(timeMoves) + + "/" + QString::number(timeTime) + "\n"); + activeSide = sideWhite; + if (humanSide == sideBlack) + crafty->writeToStdin("go\n"); +} + +void BoardView::setTheme(QString filename) +{ + QImage theme = Resource::loadImage(QString("chess/") + filename); + pieceSize = theme.height() / 2; + setFrameStyle(QFrame::Plain); + setFixedSize(8 * pieceSize, 8 * pieceSize); + canvas()->setBackgroundColor(Qt::red); + canvas()->resize(8 * pieceSize, 8 * pieceSize); + whiteSquare = theme.copy(6 * pieceSize, 0, pieceSize, pieceSize); + activeWhiteSquare = theme.copy(7 * pieceSize, 0, pieceSize, pieceSize); + blackSquare = + theme.copy(6 * pieceSize, pieceSize, pieceSize, pieceSize); + activeBlackSquare = + theme.copy(7 * pieceSize, pieceSize, pieceSize, pieceSize); + buildImages(theme); + drawBackgroundImage(QPoint(-1, -1)); +} + + +// sets the bg to the default background image for the current theme +// also resposible for drawing the "active" marker +void BoardView::drawBackgroundImage(QPoint activeSquare) +{ + bg = QPixmap(8 * pieceSize, 8 * pieceSize); + QPainter p(&bg); + bool col = FALSE; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + QPoint point(i * pieceSize, j * pieceSize); + if (col) { + if (point.x() == activeSquare.x() + && point.y() == activeSquare.y()) + p.drawImage(point, activeBlackSquare); + else + p.drawImage(point, blackSquare); + col = FALSE; + } else { + if (point.x() == activeSquare.x() + && point.y() == activeSquare.y()) + p.drawImage(point, activeWhiteSquare); + else + p.drawImage(point, whiteSquare); + col = TRUE; + } + } + col = !col; + } + canvas()->setBackgroundPixmap(bg); + canvas()->update(); +} + + +// Board view widget +void BoardView::contentsMousePressEvent(QMouseEvent * e) +{ + QCanvasItemList cList = canvas()->collisions(e->pos()); + if (activeSide == humanSide && playingGame) { + if (!activePiece) { + if (cList.count()) { + activePiece = (Piece *) (*(cList.at(0))); + drawBackgroundImage(QPoint + (activePiece->x(), activePiece->y())); + } + } else { + if (!(activePiece == (Piece *) (*(cList.at(0))))) { + char fromFile = convertToFile(activePiece->x()); + int fromRank = convertToRank(activePiece->y()); + char toFile = convertToFile(e->pos().x()); + int toRank = convertToRank(e->pos().y()); + QString moveS; + moveS.append(fromFile); + moveS.append(moveS.number(fromRank)); + moveS.append(toFile); + moveS.append(moveS.number(toRank)); + if ((activePiece->type == wPawn + && fromRank == 7 && toRank == 8) + || (activePiece->type == bPawn + && fromRank == 2 && toRank == 1)) { + // offer a promotion + emit(showMessage + ("you are meant to be offered a promotion here")); + char promoteTo = wQueen; // doesnt matter for now + moveS.append(promoteTo); + moveS.append("\n"); + crafty->writeToStdin(moveS.latin1()); + } + } + activePiece = 0; + drawBackgroundImage(QPoint(-1, -1)); + } + } + + else { + emitErrorMessage(); + } +} + +void BoardView::swapSides() +{ + if (activeSide == humanSide && playingGame) { + humanSide = !humanSide; + crafty->writeToStdin("savepos\ngo\n"); + } else + emitErrorMessage(); +} + +BoardView::BoardView(QCanvas *c, QWidget *w, const char *name) + : QCanvasView(c, w, name) { + humanSide = sideWhite; + activeSide = sideWhite; + playingGame = TRUE; + activePiece = 0; + list.setAutoDelete(TRUE); + setCanvas(new QCanvas()); + Config c("Chess", Config::User); + c.setGroup("Theme"); + QString theme = c.readEntry("imagefile", "simple-28"); + setTheme(theme); + crafty = new CraftyProcess(this); + crafty->addArgument("crafty"); + if (!crafty->start()) { + QMessageBox::critical(0, + tr("Could not find crafty chess engine"), + tr("Quit")); + exit(-1); + } + + connect(crafty, SIGNAL(readyReadStdout()), this, SLOT(readStdout())); + connect(crafty, SIGNAL(processExited()), this, SLOT(craftyDied())); +// crafty->writeToStdin("xboard\nics\nkibitz=2\n"); + newGame(); +} diff --git a/noncore/games/chess/chess.db b/noncore/games/chess/chess.db new file mode 100644 index 0000000..b520b30 --- a/dev/null +++ b/noncore/games/chess/chess.db @@ -0,0 +1,2 @@ +<!DOCTYPE DB><DB version="1.0"> +</DB> diff --git a/noncore/games/chess/chess.h b/noncore/games/chess/chess.h new file mode 100644 index 0000000..067b2f8 --- a/dev/null +++ b/noncore/games/chess/chess.h @@ -0,0 +1,128 @@ +/********************************************************************** +** 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. +** +** $Id$ +** +**********************************************************************/ +#ifndef CHESS_H +#define CHESS_H + +#include <qwidget.h> +#include <qcanvas.h> +#include <qmainwindow.h> +#include <qpixmap.h> +#include <qimage.h> +#include <qstack.h> +#include <qvector.h> +#include <qpe/process.h> + +#define wPawn 'P' +#define wKnight 'N' +#define wBishop 'B' +#define wRook 'R' +#define wQueen 'Q' +#define wKing 'K' +#define bPawn 'p' +#define bKnight 'n' +#define bBishop 'b' +#define bRook 'r' +#define bQueen 'q' +#define bKing 'k' +#define NONE N + +#define sideWhite 0 +#define sideBlack 1 + + +class Piece:public QCanvasRectangle { + public: + Piece(QCanvas *, int); + ~Piece() { + }; + + char type; + + protected: + void drawShape(QPainter &); +}; + + +class CraftyProcess : public Process { + public: + CraftyProcess(QObject *parent) : Process( parent ) { qDebug("CraftyProcess functions not implemented"); } + ~CraftyProcess() { } + bool start() { qDebug("CraftyProcess functions not implemented"); return FALSE; } + const char *readStdout() { qDebug("CraftyProcess functions not implemented"); return "Blah"; } + void writeToStdin(const char *) { qDebug("CraftyProcess functions not implemented"); } +}; + + +class BoardView:public QCanvasView { + Q_OBJECT public: + BoardView(QCanvas *, QWidget *, const char *); + ~BoardView() { + }; + + protected: + void contentsMousePressEvent(QMouseEvent *); + + signals: + void showMessage(const QString &); + + public slots:void readStdout(); + void craftyDied() { + qFatal("Crafty died unexpectedly\n"); + }; + void newGame(); + void setTheme(QString); + void swapSides(); + void undo(); + void annotateGame(); + + private: + CraftyProcess * crafty; + QList < Piece > list; + Piece *activePiece; + + void revertLastMove(); + void emitErrorMessage(); + void drawBackgroundImage(QPoint activeSquare); + + void buildImages(QImage); + + char convertToFile(int); + int convertToRank(int); + int convertFromFile(char); + int convertFromRank(int); + + void decodePosition(const QString & t); + + Piece *findPiece(char f, int r); + Piece *newPiece(int, char, int); + void deletePiece(Piece *); + + int pieceSize; + QPixmap bg; + QImage whiteSquare, blackSquare, activeWhiteSquare, activeBlackSquare; + + bool humanSide; + bool activeSide; + bool playingGame; +}; + +#endif diff --git a/noncore/games/chess/chess.pro b/noncore/games/chess/chess.pro new file mode 100644 index 0000000..f6650a0 --- a/dev/null +++ b/noncore/games/chess/chess.pro @@ -0,0 +1,14 @@ +SOURCES += chess.cpp main.cpp +HEADERS += chess.h +DESTDIR = ../bin +TARGET = chess +DEPENDPATH += $(QPEDIR)/include +INTERFACES = mainwindow.ui +IMAGES = images/new.png images/repeat.png images/txt.png images/back.png +TEMPLATE =app +CONFIG += qt warn_on release +INCLUDEPATH += $(QPEDIR)/include +LIBS += -lqpe +DBFILE = chess.db +LANGUAGE = C++ +CPP_ALWAYS_CREATE_SOURCE = TRUE diff --git a/noncore/games/chess/main.cpp b/noncore/games/chess/main.cpp new file mode 100644 index 0000000..a56913f --- a/dev/null +++ b/noncore/games/chess/main.cpp @@ -0,0 +1,51 @@ +/********************************************************************** +** 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. +** +** $Id$ +** +**********************************************************************/ +#include <qpe/qpeapplication.h> +#include <qpe/qpetoolbar.h> +#include <qmainwindow.h> +#include <qcanvas.h> +#include "chess.h" + + +class CanvasMainWindow : public QMainWindow { +public: + CanvasMainWindow(QWidget* parent=0, const char* name=0, WFlags f=0) + : QMainWindow(parent,name,f), canvas(232, 258) { + view = new BoardView(&canvas, this, 0); + setToolBarsMovable( FALSE ); + QPEToolBar* toolbar = new QPEToolBar(this); + toolbar->setHorizontalStretchable( TRUE ); + } + +private: + QCanvas canvas; + BoardView *view; +}; + + +int main( int argc, char **argv ) { + QPEApplication a(argc,argv); + CanvasMainWindow *mw = new CanvasMainWindow(); + a.showMainWidget( mw ); + return a.exec(); +} + diff --git a/noncore/games/chess/mainwindow.ui b/noncore/games/chess/mainwindow.ui new file mode 100644 index 0000000..dc3ae0f --- a/dev/null +++ b/noncore/games/chess/mainwindow.ui @@ -0,0 +1,220 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>MainWindow</class> +<widget class="QMainWindow"> + <property name="name"> + <cstring>MainWindow</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>256</width> + <height>338</height> + </rect> + </property> + <property name="caption"> + <string>Chess</string> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>236</y> + <width>221</width> + <height>31</height> + </rect> + </property> + <property name="text"> + <string>TextLabel1</string> + </property> + </widget> + <widget class="BoardView"> + <property name="name"> + <cstring>ChessBoard</cstring> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>224</width> + <height>224</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>224</width> + <height>224</height> + </size> + </property> + </widget> +</widget> +<menubar> + <property name="name"> + <cstring>menubar</cstring> + </property> + <item text="Game" name="PopupMenu_2"> + <action name="newGame"/> + <action name="annotateGame"/> + </item> + <item text="Position" name="PopupMenu_3"> + <action name="swapSides"/> + <action name="undo"/> + </item> +</menubar> +<toolbars> +</toolbars> +<customwidgets> + <customwidget> + <class>BoardView</class> + <header location="global">/home/luke/depot/qpe/chess/chess.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + <signal>showMessage(const QString&)</signal> + <slot access="public" specifier="">newGame()</slot> + <slot access="public" specifier="">swapSides()</slot> + <slot access="public" specifier="">setTheme(QString)</slot> + <slot access="public" specifier="">undo()</slot> + <slot access="public" specifier="">annotateGame()</slot> + </customwidget> +</customwidgets> +<actions> + <actiongroup> + <property name="name"> + <cstring>gameActions</cstring> + </property> + <property name="text"> + <string>ActionGroup</string> + </property> + <property name="usesDropDown"> + <bool>false</bool> + </property> + <action> + <property name="name"> + <cstring>newGame</cstring> + </property> + <property name="iconSet"> + <iconset>new.png</iconset> + </property> + <property name="text"> + <string>New Game</string> + </property> + <property name="menuText"> + <string>New Game</string> + </property> + <property name="toolTip"> + <string>New Game</string> + </property> + </action> + <action> + <property name="name"> + <cstring>swapSides</cstring> + </property> + <property name="iconSet"> + <iconset>repeat.png</iconset> + </property> + <property name="text"> + <string>Swap sides</string> + </property> + <property name="toolTip"> + <string>Swap sides</string> + </property> + </action> + <action> + <property name="name"> + <cstring>annotateGame</cstring> + </property> + <property name="iconSet"> + <iconset>txt.png</iconset> + </property> + <property name="text"> + <string>Annotate game</string> + </property> + <property name="toolTip"> + <string>Annotate game</string> + </property> + </action> + <action> + <property name="name"> + <cstring>undo</cstring> + </property> + <property name="iconSet"> + <iconset>back.png</iconset> + </property> + <property name="text"> + <string>Undo move</string> + </property> + <property name="toolTip"> + <string>Undo move</string> + </property> + </action> + <action> + <property name="name"> + <cstring>saveGame</cstring> + </property> + <property name="text"> + <string>Action</string> + </property> + </action> + </actiongroup> +</actions> +<images> + <image name="image0"> + <data format="XPM.GZ" length="3456">789ce5d35d5313491406e07b7e458abea3b68e99cfccd4d65ee0079ac8a720a2d65ef474cf2424229004152dffbba7cf795941182a59bcd8aa6548524fbafb9d9ed3278fd63a47bb5b9db5472bb3b99d1fbb8e1bd96967cd5f9c9c5cbefffbaf6f2bab49dce1ff5eaf13affeb1b24aa6e33aa62b7f620fa7b01517ec423c850bb571b0c3f8bbe0a8db7591ae1fa9c3257e0aa7b0ac8f0ab6aeefc305bc073b783d38ee462ed6f5953a5ce20d38859f894b7629de820bb519c20ee3af829328764924be50275d7806a76a732c2ed9ba7e08176a33811d2cf548a3c4a59a97a9d3aedad4708af153b1655bf14bb880bfc00e3e0fcee2ac9be9f926629b65998eefc21e3e0acee3cce73affb33acfe037ff58e737629b97f026ece128b897e4be9788bfaa7b119cc319fc445cb12bf1215caa8d813d2cfd59243d5fe8faaeb82ab242d7d770097f803d2ce751a66554a6e28f70a636d24fa5633b191fc325fc1cf6f049b04d6d6435ef139cc16fc5ce5aabf3b7e11ade09ae525b573a7f5f5dc5f00bb1aff2ca8b07b0559b315c63fc20d86555ed32f15ced62f812ce61e95fe7d99a67610b3770ada65eb0e776f1bafe4c5cb36bf16bd8c245709dd7719d8b5371cddfc8b821d8aa290e6e78b4d1f9a5ba89e1c7e2a6b14d13bc37879b2bdf7f91b9fffadf65d8df90519123ffc08c9a1a1ad2a86d3ff767d0318d69421fe8843ed229a72c9d4167742ef79ed28ce69c7471f713b567d027beef675ea733bfd0257da5f5bb52da32e8313de18ca7f48c67add30657f539bde07df597c818d04bdae41a84593557654a5bb44d3bb44b7bbfeea53563c2ab467c1a61569f77123e5fd13e1d704a7533a535e3351dd21b3afa65dfeb9cf09677f86ec19a7679e64cea71f3daa788ebb45846cccf93dcaae1942bbb793be38e339ff2b34f28e5f7ab6f4e29e33a8c68f3f6dd5a320cdf29a7deb58c824aeeb31d434b64f48de1351b5736b6fd17d192e1a9321577d5cfe73e5c32c31ac79db16dfccf3e30f55219533e8b53634c73bd3bcc90e285332cf7f21177f51977d9f046775d2e9e6146fc8bbdabcab816c89872270f1e98e1f909c6b4c5cf7f71f5e2f7637e9fe9e742f5e8d3399feb3e0dcc9877744083f613693d174b23befbcc4ccc84b2f0fa1719d7d37c783d28a3b58affd18cef7faefc007d894af5</data> + </image> +</images> +<connections> + <connection> + <sender>newGame</sender> + <signal>activated()</signal> + <receiver>ChessBoard</receiver> + <slot>newGame()</slot> + </connection> + <connection> + <sender>swapSides</sender> + <signal>activated()</signal> + <receiver>ChessBoard</receiver> + <slot>swapSides()</slot> + </connection> + <connection> + <sender>annotateGame</sender> + <signal>activated()</signal> + <receiver>ChessBoard</receiver> + <slot>annotateGame()</slot> + </connection> + <connection> + <sender>undo</sender> + <signal>activated()</signal> + <receiver>ChessBoard</receiver> + <slot>undo()</slot> + </connection> + <connection> + <sender>ChessBoard</sender> + <signal>showMessage(const QString&)</signal> + <receiver>TextLabel1</receiver> + <slot>setText(const QString&)</slot> + </connection> +</connections> +<pixmapinproject/> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/noncore/games/chess/pieces.png b/noncore/games/chess/pieces.png Binary files differnew file mode 100644 index 0000000..4baeb4a --- a/dev/null +++ b/noncore/games/chess/pieces.png diff --git a/noncore/games/chess/qpe-chess.control b/noncore/games/chess/qpe-chess.control new file mode 100644 index 0000000..2a7d2d2 --- a/dev/null +++ b/noncore/games/chess/qpe-chess.control @@ -0,0 +1,9 @@ +Files: bin/chess apps/Games/chess.desktop +Priority: optional +Section: qpe/games +Maintainer: Luke Graham <luke@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Crafty GUI + A GUI for the crafty chess engine diff --git a/noncore/games/chess/simple-l.png b/noncore/games/chess/simple-l.png Binary files differnew file mode 100644 index 0000000..908e2e1 --- a/dev/null +++ b/noncore/games/chess/simple-l.png diff --git a/noncore/games/fifteen/.cvsignore b/noncore/games/fifteen/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/noncore/games/fifteen/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/noncore/games/fifteen/Makefile.in b/noncore/games/fifteen/Makefile.in new file mode 100644 index 0000000..23c7334 --- a/dev/null +++ b/noncore/games/fifteen/Makefile.in @@ -0,0 +1,118 @@ +############################################################################# + +####### 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 = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = fifteen +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = fifteen.h +SOURCES = fifteen.cpp \ + main.cpp +OBJECTS = fifteen.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_fifteen.cpp +OBJMOC = moc_fifteen.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 fifteen.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 + +fifteen.o: fifteen.cpp \ + fifteen.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +main.o: main.cpp \ + fifteen.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_fifteen.o: moc_fifteen.cpp \ + fifteen.h + +moc_fifteen.cpp: fifteen.h + $(MOC) fifteen.h -o moc_fifteen.cpp + + diff --git a/noncore/games/fifteen/fifteen.cpp b/noncore/games/fifteen/fifteen.cpp new file mode 100644 index 0000000..293cd65 --- a/dev/null +++ b/noncore/games/fifteen/fifteen.cpp @@ -0,0 +1,364 @@ +/********************************************************************** +** 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 "fifteen.h" + +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qvbox.h> +#include <qaction.h> +#include <qlayout.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qmessagebox.h> +#include <qpe/qpetoolbar.h> +#include <qpe/qpemenubar.h> +#include <qstringlist.h> +#include <qapplication.h> + +#include <stdlib.h> +#include <time.h> + +FifteenMainWindow::FifteenMainWindow(QWidget *parent, const char* name) + : QMainWindow( parent, name ) +{ + // random seed + srand(time(0)); + + setToolBarsMovable( FALSE ); + QVBox *vbox = new QVBox( this ); + PiecesTable *table = new PiecesTable( vbox ); + setCentralWidget(vbox); + + QPEToolBar *toolbar = new QPEToolBar(this); + toolbar->setHorizontalStretchable( TRUE ); + addToolBar(toolbar); + + QPEMenuBar *menubar = new QPEMenuBar( toolbar ); + menubar->setMargin(0); + + QPopupMenu *game = new QPopupMenu( this ); + + QWidget *spacer = new QWidget( toolbar ); + spacer->setBackgroundMode( PaletteButton ); + toolbar->setStretchableWidget( spacer ); + + QAction *a = new QAction( tr( "Randomize" ), Resource::loadPixmap( "new" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), table, SLOT( slotRandomize() ) ); + a->addTo( game ); + a->addTo( toolbar ); + + a = new QAction( tr( "Solve" ), Resource::loadPixmap( "repeat" ), + QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), table, SLOT( slotReset() ) ); + a->addTo( game ); + a->addTo( toolbar ); + + menubar->insertItem( tr( "Game" ), game ); +} + +PiecesTable::PiecesTable(QWidget* parent, const char* name ) + : QTableView(parent, name), _menu(0), _randomized(false) +{ + // setup table view + setFrameStyle(StyledPanel | Sunken); + setBackgroundMode(NoBackground); + setMouseTracking(true); + + setNumRows(4); + setNumCols(4); + + // init arrays + initMap(); + readConfig(); + initColors(); + + // set font + QFont f = font(); + f.setPixelSize(18); + f.setBold( TRUE ); + setFont(f); +} + +PiecesTable::~PiecesTable() +{ + writeConfig(); +} + +void PiecesTable::writeConfig() +{ + Config cfg("Fifteen"); + cfg.setGroup("Game"); + QStringList map; + for (unsigned int i = 0; i < 16; i++) + map.append( QString::number( _map[i] ) ); + cfg.writeEntry("Map", map, '-'); + cfg.writeEntry("Randomized", _randomized ); +} + +void PiecesTable::readConfig() +{ + Config cfg("Fifteen"); + cfg.setGroup("Game"); + QStringList map = cfg.readListEntry("Map", '-'); + _randomized = cfg.readBoolEntry( "Randomized", FALSE ); + unsigned int i = 0; + for ( QStringList::Iterator it = map.begin(); it != map.end(); ++it ) { + _map[i] = (*it).toInt(); + i++; + if ( i > 15 ) break; + } +} + +void PiecesTable::paintCell(QPainter *p, int row, int col) +{ + int w = cellWidth(); + int h = cellHeight(); + int x2 = w - 1; + int y2 = h - 1; + + int number = _map[col + row * numCols()] + 1; + + // draw cell background + if(number == 16) + p->setBrush(colorGroup().background()); + else + p->setBrush(_colors[number-1]); + p->setPen(NoPen); + p->drawRect(0, 0, w, h); + + // draw borders + if (height() > 40) { + p->setPen(colorGroup().text()); + if(col < numCols()-1) + p->drawLine(x2, 0, x2, y2); // right border line + + if(row < numRows()-1) + p->drawLine(0, y2, x2, y2); // bottom boder line + } + + // draw number + if (number == 16) return; + p->setPen(black); + p->drawText(0, 0, x2, y2, AlignHCenter | AlignVCenter, QString::number(number)); +} + +void PiecesTable::resizeEvent(QResizeEvent *e) +{ + QTableView::resizeEvent(e); + + setCellWidth(contentsRect().width()/ numRows()); + setCellHeight(contentsRect().height() / numCols()); +} + +void PiecesTable::initColors() +{ + _colors.resize(numRows() * numCols()); + for (int r = 0; r < numRows(); r++) + for (int c = 0; c < numCols(); c++) + _colors[c + r *numCols()] = QColor(255 - 70 * c,255 - 70 * r, 150); +} + +void PiecesTable::initMap() +{ + _map.resize(16); + for (unsigned int i = 0; i < 16; i++) + _map[i] = i; + + _randomized = false; +} + +void PiecesTable::randomizeMap() +{ + initMap(); + _randomized = true; + // find the free position + int pos = _map.find(15); + + int move = 0; + while ( move < 333 ) { + + int frow = pos / numCols(); + int fcol = pos - frow * numCols(); + + // find click position + int row = rand()%4; + int col = rand()%4; + + // sanity check + if ( row < 0 || row >= numRows() ) continue; + if ( col < 0 || col >= numCols() ) continue; + if ( row != frow && col != fcol ) continue; + + move++; + + // rows match -> shift pieces + if(row == frow) { + + if (col < fcol) { + for(int c = fcol; c > col; c--) { + _map[c + row * numCols()] = _map[ c-1 + row *numCols()]; + } + } + else if (col > fcol) { + for(int c = fcol; c < col; c++) { + _map[c + row * numCols()] = _map[ c+1 + row *numCols()]; + } + } + } + // cols match -> shift pieces + else if (col == fcol) { + + if (row < frow) { + for(int r = frow; r > row; r--) { + _map[col + r * numCols()] = _map[ col + (r-1) *numCols()]; + } + } + else if (row > frow) { + for(int r = frow; r < row; r++) { + _map[col + r * numCols()] = _map[ col + (r+1) *numCols()]; + } + } + } + // move free cell to click position + _map[pos=(col + row * numCols())] = 15; + repaint(); + } +} + +void PiecesTable::checkwin() +{ + if(!_randomized) return; + + int i; + for (i = 0; i < 16; i++) + if(i != _map[i]) + break; + + if (i == 16) { + QMessageBox::information(this, tr("Fifteen Pieces"), + tr("Congratulations!\nYou win the game!")); + _randomized = FALSE; + } + +} + +void PiecesTable::slotRandomize() +{ + randomizeMap(); +} + +void PiecesTable::slotReset() +{ + initMap(); + repaint(); +} + +void PiecesTable::mousePressEvent(QMouseEvent* e) +{ + QTableView::mousePressEvent(e); + + if (e->button() == RightButton) { + + // setup RMB pupup menu + if(!_menu) { + _menu = new QPopupMenu(this); + _menu->insertItem(tr("R&andomize Pieces"), mRandomize); + _menu->insertItem(tr("&Reset Pieces"), mReset); + _menu->adjustSize(); + } + + // execute RMB popup and check result + switch(_menu->exec(mapToGlobal(e->pos()))) { + case mRandomize: + randomizeMap(); + break; + case mReset: + initMap(); + repaint(); + break; + default: + break; + } + } + else { + // GAME LOGIC + + // find the free position + int pos = _map.find(15); + if(pos < 0) return; + + int frow = pos / numCols(); + int fcol = pos - frow * numCols(); + + // find click position + int row = findRow(e->y()); + int col = findCol(e->x()); + + // sanity check + if (row < 0 || row >= numRows()) return; + if (col < 0 || col >= numCols()) return; + if ( row != frow && col != fcol ) return; + + // valid move? + if(row != frow && col != fcol) return; + + // rows match -> shift pieces + if(row == frow) { + + if (col < fcol) { + for(int c = fcol; c > col; c--) { + _map[c + row * numCols()] = _map[ c-1 + row *numCols()]; + updateCell(row, c, false); + } + } + else if (col > fcol) { + for(int c = fcol; c < col; c++) { + _map[c + row * numCols()] = _map[ c+1 + row *numCols()]; + updateCell(row, c, false); + } + } + } + // cols match -> shift pieces + else if (col == fcol) { + + if (row < frow) { + for(int r = frow; r > row; r--) { + _map[col + r * numCols()] = _map[ col + (r-1) *numCols()]; + updateCell(r, col, false); + } + } + else if (row > frow) { + for(int r = frow; r < row; r++) { + _map[col + r * numCols()] = _map[ col + (r+1) *numCols()]; + updateCell(r, col, false); + } + } + } + // move free cell to click position + _map[col + row * numCols()] = 15; + updateCell(row, col, false); + + // check if the player wins with this move + checkwin(); + } +} diff --git a/noncore/games/fifteen/fifteen.h b/noncore/games/fifteen/fifteen.h new file mode 100644 index 0000000..703a8a7 --- a/dev/null +++ b/noncore/games/fifteen/fifteen.h @@ -0,0 +1,83 @@ +/********************************************************************** +** 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 __fifteenapplet_h__ +#define __fifteenapplet_h__ + +#include <qmainwindow.h> +#include <qtableview.h> +#include <qarray.h> + +class QPopupMenu; + +class PiecesTable : public QTableView +{ + Q_OBJECT + + public: + PiecesTable(QWidget* parent = 0, const char* name = 0); + ~PiecesTable(); + + protected slots: + void slotRandomize(); + void slotReset(); + + protected: + void resizeEvent(QResizeEvent*); + void mousePressEvent(QMouseEvent*); + + void paintCell(QPainter *, int row, int col); + + void initMap(); + void initColors(); + void randomizeMap(); + void checkwin(); + void readConfig(); + void writeConfig(); + + private: + QArray<int> _map; + QArray<QColor> _colors; + QPopupMenu *_menu; + bool _randomized; + + enum MenuOp { mRandomize = 1, mReset = 2 }; +}; + +class FifteenWidget : public QWidget +{ + Q_OBJECT + +public: + FifteenWidget(QWidget *parent = 0, const char *name = 0); + +private: + PiecesTable *_table; +}; + +class FifteenMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + FifteenMainWindow(QWidget *parent=0, const char* name=0); +}; + +#endif diff --git a/noncore/games/fifteen/fifteen.pro b/noncore/games/fifteen/fifteen.pro new file mode 100644 index 0000000..167f4f8 --- a/dev/null +++ b/noncore/games/fifteen/fifteen.pro @@ -0,0 +1,10 @@ +DESTDIR = ../bin +TEMPLATE = app +CONFIG = qt warn_on release +HEADERS = fifteen.h +SOURCES = fifteen.cpp \ + main.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +TARGET = fifteen diff --git a/noncore/games/fifteen/main.cpp b/noncore/games/fifteen/main.cpp new file mode 100644 index 0000000..4838a36 --- a/dev/null +++ b/noncore/games/fifteen/main.cpp @@ -0,0 +1,33 @@ +/********************************************************************** +** 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 "fifteen.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char ** argv) +{ + QPEApplication app( argc, argv ); + + FifteenMainWindow mw; + mw.setCaption( FifteenMainWindow::tr("Fifteen Pieces") ); + app.showMainWidget( &mw ); + return app.exec(); +} diff --git a/noncore/games/fifteen/qpe-fifteen.control b/noncore/games/fifteen/qpe-fifteen.control new file mode 100644 index 0000000..d77eb32 --- a/dev/null +++ b/noncore/games/fifteen/qpe-fifteen.control @@ -0,0 +1,11 @@ +Files: bin/fifteen apps/Games/fifteen.desktop pics/Fifteen.png +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Arch: iPAQ +Version: $QPE_VERSION-4 +Depends: qpe-base ($QPE_VERSION) +Description: Fifteen pieces game + A game for the Qtopia environment +. diff --git a/noncore/games/go/.cvsignore b/noncore/games/go/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/noncore/games/go/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/noncore/games/go/Makefile.in b/noncore/games/go/Makefile.in new file mode 100644 index 0000000..27304f1 --- a/dev/null +++ b/noncore/games/go/Makefile.in @@ -0,0 +1,158 @@ +############################################################################# + +####### 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 = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = go +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = amigo.h \ + go.h \ + goplayutils.h \ + gowidget.h +SOURCES = amigo.c \ + goplayer.c \ + goplayutils.c \ + killable.c \ + gowidget.cpp \ + main.cpp +OBJECTS = amigo.o \ + goplayer.o \ + goplayutils.o \ + killable.o \ + gowidget.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_gowidget.cpp +OBJMOC = moc_gowidget.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 go.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 + +amigo.o: amigo.c \ + go.h \ + goplayutils.h \ + amigo.h + +goplayer.o: goplayer.c \ + go.h \ + goplayutils.h \ + amigo.h + +goplayutils.o: goplayutils.c \ + goplayutils.h \ + amigo.h \ + go.h + +killable.o: killable.c \ + go.h \ + goplayutils.h \ + amigo.h + +gowidget.o: gowidget.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +main.o: main.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_gowidget.o: moc_gowidget.cpp \ + gowidget.h \ + amigo.h \ + go.h \ + goplayutils.h + +moc_gowidget.cpp: gowidget.h + $(MOC) gowidget.h -o moc_gowidget.cpp + + diff --git a/noncore/games/go/README b/noncore/games/go/README new file mode 100644 index 0000000..c6fa1f5 --- a/dev/null +++ b/noncore/games/go/README @@ -0,0 +1,3 @@ +This Go player For Qtopia is based on Xamigo, which in turn was +based on Amigo. The original README files are included as README.XAMIGO +and README.AMIGO. diff --git a/noncore/games/go/README.AMIGO b/noncore/games/go/README.AMIGO new file mode 100644 index 0000000..03978e7 --- a/dev/null +++ b/noncore/games/go/README.AMIGO @@ -0,0 +1,42 @@ + This is version 1.0 of AmiGo --- a Go board and player for the Amiga. +The Amiga interface and board manager were written by Todd R. Johnson. +The player is a C port of a Pascal player written by Stoney Ballard. +The interface allows you to play human vs. human, human vs. Amiga, or +Amiga vs. Amiga. + + The board manager and player could both use some work. Currently, +you cannot save/load games, take back a move, or automatically score a +game. It is also limited to a 19 by 19 board. I'm releasing AmiGo +now because 1) I'm in the final phases of my dissertation and probably +won't have much time to do any further work on AmiGo, and 2) a lot of +people have been asking for an Amiga Go player. I am also releasing +all of the source code so that others can add to and modify AmiGo. +Note that all of my code in this release is public domain, while the +ported go player retains the original copyright. + + If you distribute AmiGo, I urge you to include the source +code. If anyone makes changes, I would appreciate a copy. In fact, I +am willing to act as a clearinghouse for AmiGo changes. + +Todd R. Johnson +tj@cis.ohio-state.edu +8/8/89 + +Here is the message attached to the original USENET posting of Stoney +Ballard's Pascal code. Note that the board manager mentioned here is +not included in this distribution. + +This go board manager and rudimentary go player was written by +Stoney Ballard at Perq Systems in 1983-1984. It is written in +Perq Pascal and utilizes some Perq libraries for I/O. The code +is offered here if someone is interested to convert it to Unix. + +The wonderful part about it is that a game is recorded as a tree +and can be played forward or backward, branching at any point +where there were alternate moves. + +For some time, this program was also used to generate the go +boards displayed in the American Go Journal. For this it used +some large font digits which are now lost. + +Fred Hansen diff --git a/noncore/games/go/README.XAMIGO b/noncore/games/go/README.XAMIGO new file mode 100644 index 0000000..219b25f --- a/dev/null +++ b/noncore/games/go/README.XAMIGO @@ -0,0 +1,26 @@ + + Xamigo 1.1 + +This is an alpha release of xamigo --- a port (read: quick hack) of the +Amiga Go program AmiGo. I don't have time to get it real nice now, +but will spend some more time on it when my thesis is out of the way. +Sadly this is the second time I've said that :-) + +The `readme' from the original distribution is included as README.AMIGO + +An Imakefile is included, so you should be able to type + xmkmf + make +to build xamigo. Let me know if you have problems with the Imakefile, +preferably with fixes :-) + +You *have* to install the app-defaults file (Xamigo.ad) before you use +xamigo. This should either go in /usr/lib/X11/app-defaults, +or in your own app-defaults directory, as file Xamigo (ie lose the '.ad') +If you do the latter, you have to: + setenv XAPPLRESDIR <full path of your app-defaults directory> + +Feel free to mail me any comments and suggestions for improvements. + +Neil +neilb@scs.leeds.ac.uk diff --git a/noncore/games/go/amigo.c b/noncore/games/go/amigo.c new file mode 100644 index 0000000..cd61013 --- a/dev/null +++ b/noncore/games/go/amigo.c @@ -0,0 +1,656 @@ +/* Go started 4/17/88 by Todd R. Johnson */ +/* 8/8/89 cleaned up for first release */ +/* Public Domain */ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + + +extern char *playReason; +extern short playLevel, showTrees; + +struct bRec goboard[19][19]; /*-- The main go board --*/ + +struct Group GroupList[MAXGROUPS]; /*-- The list of Groups --*/ +short DeletedGroups[4]; /*-- Codes of deleted groups --*/ + +short GroupCount = 0; /*-- The total number of groups --*/ +short DeletedGroupCount; /*-- The total number of groups --*/ + /*-- deleted on a move --*/ +short ko, koX, koY; +short blackTerritory,whiteTerritory; +short blackPrisoners, whitePrisoners; +short showMoveReason = FALSE, + groupInfo = FALSE, + whitePassed = FALSE, + blackPassed = FALSE; + + +/* Arrays for use when checking around a point */ +short xVec[4] = {0, 1, 0, -1}; +short yVec[4] = {-1, 0, 1, 0}; + +short +member(group, grouplist, cnt) + short group; + short grouplist[4]; + short cnt; +{ + unsigned short i; + + + for (i = 0; i < cnt; i++) + if (grouplist[i] == group) + return TRUE; + return FALSE; +} + +/* Does a stone at x, y connect to any groups of color? */ +short +Connect( color, x, y, fGroups, fCnt, eGroups, eCnt) + enum bVal color; + short x, y; + short fGroups[4], eGroups[4]; + short *fCnt, *eCnt; +{ + unsigned short point = 0; + short tx, ty, total = 0; + enum bVal opcolor = WHITE; + + + *fCnt = 0; + *eCnt = 0; + if (color == WHITE) + opcolor = BLACK; + for (point = 0; point <= 3; point++ ) + { + tx = x + xVec[point]; + ty = y + yVec[point]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val == color) + { + total++; + if (!member(goboard[tx][ty].GroupNum, fGroups, *fCnt)) + fGroups[(*fCnt)++] = goboard[tx][ty].GroupNum; + } + else if (goboard[tx][ty].Val == opcolor) + { + total++; + if (!member(goboard[tx][ty].GroupNum, eGroups, *eCnt)) + eGroups[(*eCnt)++] = goboard[tx][ty].GroupNum; + } + } + return total; +} + +/* Returns the maximum number of liberties for a given intersection */ +short +Maxlibs(x, y) + short x, y; +{ + short cnt = 4; + + + if (x == 0 || x == 18) + cnt--; + if (y == 0 || y == 18) + cnt--; + return cnt; +} + +DeleteGroupFromStone(x,y) + short x,y; +{ + if (goboard[x][y].Val != EMPTY) + GroupCapture(goboard[x][y].GroupNum); +} + +/* Determine whether x, y is suicide for color */ +short +Suicide(color, x, y) + enum bVal color; + short x, y; +{ + enum bVal opcolor = BLACK; + short friendlycnt, friendlygroups[4], + enemycnt, enemygroups[4], + total; + short maxlibs, i, libcnt = 0; + + + if (color == BLACK) + opcolor = WHITE; + maxlibs = Maxlibs( x, y); + total = Connect(color, x, y, friendlygroups, &friendlycnt, + enemygroups, &enemycnt); + + if (total < maxlibs) + return FALSE; + + /* Check for a capture */ + for (i = 0; i < enemycnt; i++) + if (GroupList[enemygroups[i]].liberties == 1) + return FALSE; + for (i = 0; i < friendlycnt; i++) + libcnt += (GroupList[friendlygroups[i]].liberties - 1); + if (libcnt != 0) + return FALSE; + return TRUE; +} + +/* Returns the number of liberties for x, y */ +short +StoneLibs(x, y) + short x, y; +{ + short cnt = 0, tx, ty; + unsigned short point; + + + for (point = 0; point <= 3; point++) + { + tx = x + xVec[point]; + ty = y + yVec[point]; + if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY) + cnt++; + } + return cnt; +} + +void +EraseMarks() +{ + register short i; + register struct bRec *gpt = &goboard[0][0]; + + + for (i=0; i<361; gpt++,i++) + gpt->marked = FALSE; +} + +/* Place a stone of color at x, y */ +short +GoPlaceStone(color, x, y) + enum bVal color; + short x, y; +{ + short fgroups[4], egroups[4]; /* group codes surrounding stone */ + short fcnt, ecnt, i; + short lowest = GroupCount + 1; + + + DeletedGroupCount = 0; + if (goboard[x][y].Val != EMPTY || Suicide(color,x,y)) + return FALSE; + + if (ko && koX == x && koY == y) + return FALSE; + + ko = FALSE; + placestone(color, x, y); + goboard[x][y].Val = color; + /* Does the new stone connect to any friendly stone(s)? */ + Connect(color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (fcnt) + { + /* Find the connecting friendly group with the lowest code */ + for (i = 0; i < fcnt; i++) + if (fgroups[i] <= lowest) + lowest = fgroups[i]; + /*-- Renumber resulting group --*/ + /*-- Raise the stone count of the lowest by one to account --*/ + /*-- for new stone --*/ + goboard[x][y].GroupNum = lowest; + GroupList[lowest].count++; + for (i = 0; i < fcnt; i++) + if (fgroups[i] != lowest) + MergeGroups(lowest, fgroups[i]); + /* Fix the liberties of the resulting group */ + CountLiberties(lowest); + } + else + { + /* Isolated stone. Create new group. */ + GroupCount++; + lowest = GroupCount; + GroupList[lowest].color = color; + GroupList[lowest].count = 1; + GroupList[lowest].internal = 0; + GroupList[lowest].external = StoneLibs( x, y); + GroupList[lowest].liberties = GroupList[lowest].external; + GroupList[lowest].eyes = 0; + GroupList[lowest].alive = 0; + GroupList[lowest].territory = 0; + goboard[x][y].GroupNum = lowest; + } + /* Now fix the liberties of enemy groups adjacent to played stone */ + FixLibs(color, x, y, PLACED); /* Fix the liberties of opcolor */ + ReEvalGroups(color, x, y, lowest); + RelabelGroups(); + return TRUE; +} + +/* Remove a stone from the board */ +void +GoRemoveStone(x, y) + short x, y; +{ + goboard[x][y].Val = EMPTY; + goboard[x][y].GroupNum = 0; + removestone( x, y); +} + +/* Merges two groups -- Renumbers stones and deletes second group from +list. Fixes stone count of groups. This does not fix anything else. +FixLibs must be called to fix liberties, etc. */ +void +MergeGroups(g1, g2) + short g1, g2; +{ + short x, y; + + + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == g2) + goboard[x][y].GroupNum = g1; + GroupList[g1].count += GroupList[g2].count; + DeleteGroup( g2 ); /* Removes group from GroupList */ +} + +/* Stores a group code to be deleted */ +void +DeleteGroup(code) + short code; +{ + DeletedGroups[DeletedGroupCount++] = code; +} + +/* Re-evaluate the groups given the last move. This assumes that the +last move has been merged into adjoining groups and all liberty counts +are correct. Handles capture. Checks for Ko. Keeps track of captured +stones. code is the group number of the stone just played. */ +void +ReEvalGroups(color, x, y, code) + enum bVal color; + short x, y, code; +{ + short fgroups[4], egroups[4], + fcnt, ecnt, i, killcnt = 0, count = 0; + enum bVal opcolor = BLACK; + + if (color == BLACK) + opcolor = WHITE; + /* Check for capture */ + Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (ecnt) + { + /* See if any of the groups have no liberties */ + for (i = 0; i < ecnt; i++) + if (GroupList[egroups[i]].liberties == 0) + { + killcnt++; + count = GroupList[egroups[i]].count; + GroupCapture( egroups[i]); + } + } + /* Check for ko. koX and koY are set in GroupCapture above. */ + if (killcnt == 1 && count == 1 && GroupList[ code ].count == 1 + && GroupList[ code ].liberties == 1) + { + ko = TRUE; + } + if (killcnt) + intrPrisonerReport( blackPrisoners, whitePrisoners); + /* Set eye count for groups */ + CountEyes(); +} + +/* Remove a captured group from the board and fix the liberties of any + adjacent groups. Fixes prisoner count. Sets KoX and KoY */ +/*-- update display of captured stones -neilb --*/ +void +GroupCapture(code) + short code; +{ + short x, y; + + if (GroupList[code].color == BLACK) + blackPrisoners += GroupList[code].count; + else + whitePrisoners += GroupList[code].count; + intrPrisonerReport(blackPrisoners, whitePrisoners); + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == code) + { + FixLibs(GroupList[code].color,x,y,REMOVED); + GoRemoveStone(x, y); + koX = x; + koY = y; + } + DeleteGroup( code); +} + +/* Fix the liberties of groups adjacent to x, y. move indicates + whether a stone of color was placed or removed at x, y + This does not change liberty counts of friendly groups when a stone + is placed. Does not do captures. */ +void +FixLibs( color, x, y, move) + enum bVal color; + short x, y, move; +{ + short fgroups[4], fcnt, egroups[4], ecnt, i; + enum bVal opcolor = BLACK; + + if (color == BLACK) + opcolor = WHITE; + Connect( color, x, y, fgroups, &fcnt, egroups, &ecnt); + if (move == PLACED) + for (i = 0; i < ecnt; i++) + GroupList[egroups[i]].liberties--; + else /* Stone removed so increment opcolor */ + for (i = 0; i < ecnt; i++) + GroupList[egroups[i]].liberties++; +} + +void +goSetHandicap(handicap) + int handicap; +{ + if (handicap < 2) + return; + + GoPlaceStone(BLACK,3,3); + GoPlaceStone(BLACK,15,15); + + if (handicap >= 3) + GoPlaceStone(BLACK,15,3); + if (handicap >= 4) + GoPlaceStone(BLACK,3,15); + if (handicap == 5 || handicap == 7 || handicap == 9) + GoPlaceStone(BLACK,9,9); + if (handicap >= 6) + { + GoPlaceStone(BLACK,15,9); + GoPlaceStone(BLACK,3,9); + } + if (handicap >= 8) + { + GoPlaceStone(BLACK,9,15); + GoPlaceStone(BLACK,9,3); + } +} + +void +goRestart(handicap) + int handicap; +{ + register short i; + register struct bRec *gpt = &goboard[0][0]; + + + GroupCount = 0; + ko = FALSE; + blackPrisoners = whitePrisoners = 0; + intrPrisonerReport(0, 0); + for (i=0; i<361; gpt++,i++) + { + gpt->Val = EMPTY; + gpt->GroupNum = 0; + } + goSetHandicap(handicap); +} + + +/* if any groups have been deleted as a result of the last move, this + routine will delete the old group numbers from GroupList and + reassign group numbers. */ +void +RelabelGroups() +{ + unsigned short i, j, x, y; + + for (i = 0; i < DeletedGroupCount; i++) + { + /* Relabel all higher groups */ + ForeachPoint(y,x) + if (goboard[x][y].GroupNum > DeletedGroups[i]) + goboard[x][y].GroupNum--; + /* Move the groups down */ + for (y = DeletedGroups[i]; y < GroupCount; y++) + GroupList[y] = GroupList[y+1]; + /* fix the group numbers stored in the deleted list */ + for (j = i+1; j < DeletedGroupCount; j++) + if (DeletedGroups[j] > DeletedGroups[i]) + DeletedGroups[j]--; + GroupCount--; + } +} + +/* Returns liberty count for x, y intersection. Sets marked to true + for each liberty */ +short +CountAndMarkLibs( x, y) + short x, y; +{ + short tx,ty,i; + short cnt = 0; + + + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (LegalPoint(tx,ty) && goboard[tx][ty].Val == EMPTY + && goboard[tx][ty].marked == FALSE) + { + cnt++; + goboard[tx][ty].marked = TRUE; + } + } + return cnt; +} + +/* Determine the number of liberties for a group given the group code + num */ +void +CountLiberties( code) + short code; +{ + short x, y, libcnt = 0; + + ForeachPoint(y,x) + if (goboard[x][y].GroupNum == code) + libcnt += CountAndMarkLibs( x, y); + EraseMarks(); + GroupList[code].liberties = libcnt; +} + +void +CheckForEye( x, y, groups, cnt, recheck) + short x, y, groups[4], cnt, *recheck; +{ + short i; + + for (i = 0; i < (cnt-1); i++) + if (groups[i] != groups[i+1]) + { + /* Mark liberty for false eye check */ + goboard[x][y].marked = TRUE; + (*recheck)++; + return; + } + /* It is an eye */ + GroupList[groups[i]].eyes += 1; +} + +/* Set the eye count for the groups */ +void CountEyes() +{ + short i, x, y, + wgroups[4], bgroups[4], wcnt, bcnt, max, cnt, recheck = 0, eye; + + for (i = 1; i <= GroupCount; i++) + GroupList[i].eyes = 0; + + ForeachPoint(y,x) + { + if (goboard[x][y].Val != EMPTY) + continue; + cnt = Connect(WHITE,x,y,wgroups,&wcnt,bgroups,&bcnt); + max = Maxlibs( x, y); + if (cnt == max && wcnt == 1 && bcnt == 0) + GroupList[wgroups[0]].eyes++; + else if (cnt == max && bcnt == 1 && wcnt == 0) + GroupList[bgroups[0]].eyes++; + else if (cnt == max && ( bcnt == 0 || wcnt == 0 )) + { + goboard[x][y].marked = TRUE; + recheck++; + } + } + + /*-- Now recheck marked liberties to see if two or more one eye --*/ + /*-- groups contribute to a false eye */ + if (recheck == 0) + return; + + ForeachPoint(y,x) + if (goboard[x][y].marked) + { + recheck--; + goboard[x][y].marked = FALSE; + Connect( WHITE, x, y, wgroups, &wcnt, bgroups, &bcnt); + /* If all the groups have at least one eye then all the + groups are safe from capture because of the common + liberty at x, y */ + eye = TRUE; + for (i = 0; i < wcnt; i++) + if (GroupList[wgroups[i]].eyes == 0) + eye = FALSE; + if (eye) + for (i = 0; i < wcnt; i++) + GroupList[wgroups[i]].eyes++; + for (i = 0; i < bcnt; i++) + if (GroupList[bgroups[i]].eyes == 0) + eye = FALSE; + if (eye) + for (i = 0; i < bcnt; i++) + GroupList[bgroups[i]].eyes++; + if (recheck == 0) + return; + } +} + + +short foo[19][19]; + +/*---------------------------------------------------------------- +-- CountUp() -- +-- Count up final scores at the end of the game. -- +----------------------------------------------------------------*/ +CountUp( wtotal, btotal ) + int *wtotal, *btotal; +{ + short x,y; + short CountFromPoint(); + short vv; + char buff[512]; + + + blackTerritory = whiteTerritory = 0; + ForeachPoint(y,x) + { + goboard[x][y].marked = FALSE; + foo[x][y] = CNT_UNDECIDED; + } + ForeachPoint(y,x) + if (goboard[x][y].Val==EMPTY && foo[x][y]==CNT_UNDECIDED) + { + FillPoints(x,y,CountFromPoint(x,y)); + } + + *wtotal = whiteTerritory + blackPrisoners; + *btotal = blackTerritory + whitePrisoners; + /* + sprintf(buff,"White : %3d territory + %3d prisoners = %d\n\ +Black : %3d territory + %3d prisoners = %d\n\n%s.\n", + whiteTerritory,blackPrisoners,*wtotal, + blackTerritory,whitePrisoners,*btotal, + (*btotal>*wtotal?"Black wins":(*wtotal>*btotal?"White wins": + "A draw"))); + + + + XtVaSetValues(message,XtNstring,buff,0); + printf( "CountUp() %s", buff ); + */ +} + +FillPoints(x,y,val) + short x,y,val; +{ + int i; + short tx,ty; + + + if ((foo[x][y] = val) == CNT_BLACK_TERR) + blackTerritory++; + else if (val == CNT_WHITE_TERR) + whiteTerritory++; + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val==EMPTY && foo[tx][ty]==CNT_UNDECIDED) + FillPoints(tx,ty,val); + } +} + +short +CountFromPoint(x,y) + short x,y; +{ + int i; + short tx,ty; + short blkcnt=0,whtcnt=0; + short baz; + + + goboard[x][y].marked = TRUE; + for (i=0;i<4;i++) + { + tx = x + xVec[i]; + ty = y + yVec[i]; + if (!LegalPoint(tx,ty)) + continue; + if (goboard[tx][ty].Val == BLACK) + blkcnt++; + else if (goboard[tx][ty].Val == WHITE) + whtcnt++; + else + { + if (goboard[tx][ty].marked) + continue; + baz = CountFromPoint(tx,ty); + if (baz == CNT_NOONE) + return CNT_NOONE; + else if (baz == CNT_BLACK_TERR) + blkcnt++; + else if (baz == CNT_WHITE_TERR) + whtcnt++; + } + if (blkcnt && whtcnt) + return CNT_NOONE; + } + if (blkcnt && !whtcnt) + return CNT_BLACK_TERR; + else if (whtcnt && !blkcnt) + return CNT_WHITE_TERR; + else + return CNT_UNDECIDED; +} diff --git a/noncore/games/go/amigo.h b/noncore/games/go/amigo.h new file mode 100644 index 0000000..5150ac0 --- a/dev/null +++ b/noncore/games/go/amigo.h @@ -0,0 +1,146 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +/*========================================================================= +=== === +=== FILE amigo.h === +=== === +=== CONTENTS prototypes for the various AmiGo routines. === +=== added by neilb === +=== === +=========================================================================*/ + +#ifndef __amigo_h +#define __amigo_h + +#include "go.h" +#include "goplayutils.h" + +#ifdef __STDC__ +#define PROTO(fp) fp +#else +#define PROTO(fp) () +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* From goplayer.c */ + + + +/* Procedures from amigo.c */ + +short Connect PROTO((enum bVal, short, short, short[4], short[4], short *, short * )); +short Maxlibs PROTO((short, short)); +short Suicide PROTO((enum bVal, short, short)); +short StoneLibs PROTO((short, short)); +void EraseMarks PROTO(()); +short GoPlaceStone PROTO((enum bVal, short, short)); +void GoRemoveStone PROTO((short, short)); +void MergeGroups PROTO((short, short)); +void DeleteGroup PROTO((short)); +void ReEvalGroups PROTO((enum bVal, short, short, short)); +void GroupCapture PROTO((short)); +void FixLibs PROTO((enum bVal, short, short, short)); +int CountUp PROTO((int*, int*)); +/*void main PROTO(());*/ +void goRestart PROTO((int)); +void RelabelGroups PROTO(()); +short CountAndMarkLibs PROTO((short, short)); +void CountLiberties PROTO((short)); +void CheckForEye PROTO((short, short, short[4], short, short *)); +void CountEyes PROTO(()); +void printGroupReport PROTO((short, short)); + + +/* killable.c */ + +int tryPlay PROTO(( short, short, short )); +int sSpanGroup PROTO(( short, short, sPointList * )); +int spanGroup PROTO(( short, short, pointList *)); +int pause PROTO(()); + +int genState PROTO(()); +int initGPUtils PROTO(()); +int genBord PROTO((enum bVal)); + +short genMove PROTO(( enum bVal, short *, short * )); +short checkPos PROTO(( short, short, short )); +short takeCorner PROTO(( short *, short * )); +short extend PROTO(( short *, short * )); +short noNbrs PROTO(( short, short )); +short extend2 PROTO(( short *, short * )); +short lookForSave PROTO(( short *, short * )); +short lookForSaveN PROTO(( short *, short * )); +short lookForKill PROTO(( short *, short * )); +short doubleAtari PROTO(( short *, short * )); +short lookForAttack PROTO(( short *, short * )); +short threaten PROTO(( short *, short * )); +short connectCut PROTO(( short *, short * )); +short heCanCut PROTO(( short, short )); +short safeMove PROTO(( short, short )); +short extendWall PROTO(( short *, short * )); +short findAttack2 PROTO(( short *, short * )); +short blockCut PROTO(( short *, short * )); +short cutHim PROTO(( short *, short * )); +short atariAnyway PROTO(( short *, short * )); +short underCut PROTO(( short *, short * )); +short dropToEdge PROTO(( short *, short * )); +short pushWall PROTO(( short *, short * )); +short reduceHisLiberties PROTO(( short *, short * )); +short dropToEdge2 PROTO(( short *, short * )); + + +/* goplayutils.c */ + +short saveable PROTO((short, short, short *, short *)); +short killable PROTO((short, short, short *, short *)); +int initBoolBoard PROTO((boolBoard)); +int intersectPlist PROTO((pointList *, pointList *, pointList *)); +int initArray PROTO((intBoard)); +int initState PROTO(()); +int copyArray PROTO((intBoard, intBoard)); +int stake PROTO(()); +int spread PROTO(()); +int respreicen PROTO(()); +int tryPlay PROTO((short, short, short)); +int saveState PROTO(()); +int restoreState PROTO(()); +short tencen PROTO((short, short)); +int genConnects PROTO(()); +int sortLibs PROTO(()); + + +/*-- from xinterface.c --*/ +void removestone PROTO((short, short)); +void placestone PROTO((enum bVal, short, short)); + +void intrMoveReport PROTO((enum bVal,char *,char *)); +void intrPrisonerReport PROTO(( short, short )); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/noncore/games/go/go.h b/noncore/games/go/go.h new file mode 100644 index 0000000..9aa644b --- a/dev/null +++ b/noncore/games/go/go.h @@ -0,0 +1,81 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ +/* AmiGo Include */ +/* MSG types for getinput() */ + +#ifndef __go_h +#define __go_h + + +#define INTERSECTIONMSG 1 /* User buttoned an intersection */ +#define QUITMSG 2 /* User buttoned QUIT icon */ +#define PLAYMSG 3 +#define RESTARTMSG 4 +#define PASSMSG 5 + +#define TRUE 1 +#define FALSE 0 + +#define MAXGROUPS 100 + +#define PLACED 0 +#define REMOVED 1 + +#define numPoints 19 +#define maxPoint numPoints - 1 + +/*-- definitions used when counting up --*/ + +#define CNT_UNDECIDED 0 +#define CNT_BLACK_TERR 1 +#define CNT_WHITE_TERR 2 +#define CNT_NOONE 3 + +/*-- macro functions --*/ + +#define LegalPoint(x,y) (x>=0 && x<=18 && y>=0 && y<=18) +#define ForeachPoint(a,b) for(a=0;a<19;a++) for (b=0;b<19;b++) + +enum bVal {BLACK, WHITE, EMPTY}; +typedef enum bVal sType; +struct Group +{ + enum bVal color; /* The color of the group */ + short code, /* The code used to mark stones in the group */ + count, /* The number of stones in the group */ + internal, /* The number of internal liberties */ + external, /* The number of external liberties */ + liberties, /* The total number of liberties */ + eyes, /* The number of eyes */ + alive, /* A judgement of how alive this group is */ + territory; /* The territory this group controls */ +}; + +struct bRec +{ + enum bVal Val; /* What is at this intersection */ + short xOfs, + yOfs; + short mNum; + short GroupNum; /* What group the stone belongs to */ + short marked; /* TRUE or FALSE */ +}; + +#endif diff --git a/noncore/games/go/go.pro b/noncore/games/go/go.pro new file mode 100644 index 0000000..deb90c5 --- a/dev/null +++ b/noncore/games/go/go.pro @@ -0,0 +1,19 @@ +DESTDIR = ../bin +TEMPLATE = app +CONFIG = qt warn_on release +HEADERS = amigo.h \ + go.h \ + goplayutils.h \ + gowidget.h +SOURCES = amigo.c \ + goplayer.c \ + goplayutils.c \ + killable.c \ + gowidget.cpp \ + main.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +TARGET = go + +TRANSLATIONS = ../i18n/de/go.ts
\ No newline at end of file diff --git a/noncore/games/go/goplayer.c b/noncore/games/go/goplayer.c new file mode 100644 index 0000000..88c0f61 --- a/dev/null +++ b/noncore/games/go/goplayer.c @@ -0,0 +1,1499 @@ +/* The go player */ +/* Ported from Pascal to C by Todd R. Johnson 4/17/88 */ +/* From the original pascal file: +Go Move Generator +Copyright (c) 1983 by Three Rivers Computer Corp. + +Written: January 17, 1983 by Stoney Ballard +Edit History: +*/ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + +#define BIGGEST 32767 /* maximum value for short */ + +/* From go.c */ +extern struct bRec goboard[19][19]; +extern short ko, koX, koY; + +/* From goplayutils.c */ +extern intBoard bord; +extern intBoard ndbord; +extern intBoard claim; +extern intBoard legal; +extern intBoard connectMap; +extern intBoard threatBord; +extern short maxGroupID; +extern short treeLibLim; +extern short killFlag; +extern short depthLimit; +extern short showTrees; +extern short utilPlayLevel; +extern groupRec gList[maxGroup]; +extern short sGlist[maxGroup + 1]; +extern pointList pList; +extern pointList pList1; +extern pointList plist2; +extern pointList plist3; +extern intBoard groupIDs; +extern intBoard protPoints; +extern sType mySType; + + +short saveNLibs; +pointList dapList1, dapList2, dapList3; +char *playReason; +short maxPlayLevel = 7; +short playLevel = 7; + +genBord(color) + enum bVal color; +{ + short x, y, nomoves = TRUE; + char mv[8]; + + maxPlayLevel = 7; + utilPlayLevel = playLevel; + mySType = color; + if (playLevel < 2) + treeLibLim = 2; + else + treeLibLim = 3; + depthLimit = 100; + for (y = 0; y <= 18; y++) + for (x = 0; x <= 18; x++) + if (goboard[x][y].Val == color) + { + bord[x][y] = 1; + legal[x][y] = FALSE; + nomoves = FALSE; + } + else if (goboard[x][y].Val == EMPTY) + { + bord[x][y] = 0; + legal[x][y] = TRUE; + } + else + { + bord[x][y] = -1; + legal[x][y] = FALSE; + nomoves = FALSE; + } + if (ko) + { + legal[koX][koY] = FALSE; + } + + if (! nomoves) + genState(); + else + initGPUtils(); +} + + +short getMove( x, y ) +short *x, *y; +{ + if (takeCorner(x, y)) return TRUE; + if (lookForSave(x, y)) return TRUE; + if (lookForSaveN(x, y)) return TRUE; + if (extend(x, y)) return TRUE; + if (lookForKill(x, y)) return TRUE; + if (doubleAtari(x, y)) return TRUE; + if (lookForAttack(x, y)) return TRUE; + if (threaten(x, y)) return TRUE; + if (extend2(x, y)) return TRUE; + if (connectCut(x, y)) return TRUE; + if (blockCut(x, y)) return TRUE; + if (cutHim(x, y)) return TRUE; + if (extendWall(x, y)) return TRUE; + if (findAttack2(x, y)) return TRUE; + if (atariAnyway(x, y)) return TRUE; + if (underCut(x, y)) return TRUE; + if (dropToEdge(x, y)) return TRUE; + if (pushWall(x, y)) return TRUE; + if (reduceHisLiberties(x, y)) return TRUE; + if (dropToEdge2(x, y)) return TRUE; + return FALSE; +} + +short genMove( color, x, y ) +enum bVal color; +short *x, *y; +{ + if (playLevel > 2) + saveNLibs = TRUE; + else + saveNLibs = FALSE; + genBord(color); + if (getMove(x, y)) + return TRUE; + return FALSE; +} + +short checkPos(x, y, field) +short x, y, field; +{ + short ok; + ok = (((field == 0) && (claim[x][y] == 0)) || + ((field > 0) && + (claim[x][y] >= 0) && (claim[x][y] <= field)) || + ((field < 0) && + (claim[x][y] <= 0) && (claim[x][y] >= field))) && + (bord[x-1][y] == 0) && + (bord[x+1][y] == 0) && + (bord[x][y-1] == 0) && + (bord[x][y+1] == 0); + if (ok) return TRUE; else return FALSE; +} + +short takeCorner( x, y ) +short *x, *y; +{ + short field = -1, i; + i = 18 - 3; + playReason = "takeCorner"; + while (field != -4) + { + if (field == -1) field = 0; + else if (field == 0) field = 4; + else field = -4; + if (checkPos(2, 3, field)) { *x = 2; *y = 3; return TRUE; } + if (checkPos(3, 2, field)) { *x = 3; *y = 2; return TRUE; } + if (checkPos(2, i, field)) { *x = 2; *y = i; return TRUE; } + if (checkPos(3, i + 1, field)) { *x = 3; *y = i+1; return TRUE; } + if (checkPos(i, i + 1, field)) { *x = i; *y = i+1; return TRUE; } + if (checkPos(i + 1, i, field)) { *x = i+1; *y = i; return TRUE; } + if (checkPos(i, 2, field)) { *x = i; *y = 2; return TRUE; } + if (checkPos(i + 1, 3, field)) { *x = i+1; *y = 3; return TRUE; } + if (checkPos(2, 4, field)) { *x = 2; *y = 4; return TRUE; } + if (checkPos(4, 2, field)) { *x = 4; *y = 2; return TRUE; } + if (checkPos(2, i - 1, field)) { *x = 2; *y = i-1; return TRUE; } + if (checkPos(4, i + 1, field)) { *x = 4; *y = i+1; return TRUE; } + if (checkPos(i - 1, i + 1, field)) { *x = i-1; *y = i+1; return TRUE; } + if (checkPos(i + 1, i - 1, field)) { *x = i+1; *y = i-1; return TRUE; } + if (checkPos(i + 1, 4, field)) { *x = i+1; *y = 4; return TRUE; } + if (checkPos(i - 1, 2, field)) { *x = i-1; *y = 2; return TRUE; } + } + return FALSE; +} + +printBoard(brd, name) +intBoard brd; +char *name; +{ + short x, y; + printf( "%s\n", name ); + for (y = 0; y <= 18; y++) + { + for (x = 0; x <= 18; x++) + printf("%d ", brd[x][y]); + printf("\n"); + } +} + +short noNbrs( x, y ) +short x, y; +{ + if (x > 0 && bord[x-1][y] != 0) return FALSE; + if (x < 18 && bord[x+1][y] != 0) return FALSE; + if (y > 0 && bord[x][y-1] != 0) return FALSE; + if (y < 18 && bord[x][y+1] != 0) return FALSE; + return TRUE; +} + +short extend(x, y) +short *x, *y; +{ + short i; + playReason = "extend"; + for (i = 2; i <= 18-2; i++) + if (claim[2][i] == 0 && noNbrs( 2, i )) + { + *x = 2; + *y = i; + return TRUE; + } + for (i = 2; i <= 18-2; i++) + if (claim[i][18-2] == 0 && noNbrs( 2, i )) + { + *x = i; + *y = 18-2; + return TRUE; + } + for (i = 18-2; i >= 2; i--) + if (claim[18-2][i] == 0 && noNbrs( 18-2, i )) + { + *x = 18-2; + *y = i; + return TRUE; + } + for (i = 18-2; i >= 2; i--) + if (claim[i][2] == 0 && noNbrs( i, 2 )) + { + *x = i; + *y = 2; + return TRUE; + } + return FALSE; +} + +short extend2( x, y ) +short *x, *y; +{ + short i, lowest = BIGGEST, value; + playReason = "extend2"; + for (i = 3; i <= 18-3; i++) + if (legal[2][i]) /* if there is nobody there */ + { + value = claim[2][i]; /* get influence */ + if ((value < 7) && /* a reasonable hole in my wall */ + (value > -5) && /* or a reasonable gap in his */ + (bord[2][i + 1] == 0) && /* not in contact with any stones */ + (bord[2][i - 1] == 0)) + if (value < lowest) + { + lowest = value; /* lowest gets the smallest value */ + *x = 2; /* that was seen along all the 3-lines */ + *y = i; /* x and y save that location */ + } + } + for (i = 3; i <= 18-3; i++) + if (legal[i][2]) + { + value = claim[i][2]; + if ((value < 7) && + (value > -5) && + (bord[i + 1][2] == 0) && + (bord[i - 1][2] == 0)) + if (value < lowest) + { + lowest = value; + *x = i; + *y = 2; + } + } + for (i = 18-3; i >= 3; i--) + if (legal[18 - 2][i]) + { + value = claim[18 - 2][i]; + if ((value < 7) && + (value > -5) && + (bord[18 - 2][i + 1] == 0) && + (bord[18 - 2][i - 1] == 0)) + if (value < lowest) + { + lowest = value; + *x = 18 - 2; + *y = i; + } + } + for (i = 3; i <= 18-3; i++) + if (legal[i][18 - 2]) + { + value = claim[i][18 - 2]; + if ((value < 7) && + (value > -5) && + (bord[i + 1][18 - 2] == 0) && + (bord[i - 1][18 - 2] == 0)) + if (value < lowest) + { + lowest = value; + *x = i; + *y = 18 - 2; + } + } + if (lowest == BIGGEST) return FALSE; + return TRUE; +} + + /* + check to see if I can save anything in atari + */ +short lookForSave(x, y) +short *x, *y; + { /* lookForSave */ + short i; + playReason = "lookForSave"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 1) && + (ndbord[gList[i].lx][gList[i].ly] == 1)) + if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */ + return TRUE; + return FALSE; + } /* lookForSave */ + + /* + check to see if I can save anything with n libs + */ +short lookForSaveN(x, y) +short *x, *y; + { /* lookForSaveN */ + short i; + if (saveNLibs) + { + playReason = "lookForSaveN"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC > 1) && + (gList[i].libC <= treeLibLim) && + (ndbord[gList[i].lx][gList[i].ly] == 1)) + { + if (killable(gList[i].lx, gList[i].ly, x, y)) + if (saveable(gList[i].lx, gList[i].ly, x, y)) /* see if I can save it */ + return TRUE; + } + } + return FALSE; + } /* lookForSaveN */ + + +/*---------------------------------------------------------------- +-- lookForKill() -- +-- check to see if I can kill anything. -- +----------------------------------------------------------------*/ +short +lookForKill(x, y) + short *x, *y; +{ + short i; + char mv[8]; + + playReason = "lookForKill"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 1) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { /* we found a live enemy group with one liberty */ + /* find the liberty */ + spanGroup(gList[i].lx, gList[i].ly, &pList); + *x = pList.p[1].px; + *y = pList.p[1].py; + if (legal[*x][*y]) + { + return TRUE; + } + } + return FALSE; +} + +short doubleAtari(x, y) +short *x, *y; + { /* doubleAtari */ + short i, j; + playReason = "doubleAtari"; + for (i = 1; i <= maxGroupID - 1; i++) + if ((gList[i].libC == 2) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) /* found an atariable group of his */ + { + spanGroup(gList[i].lx, gList[i].ly, &dapList1); + for (j = i + 1; j <= maxGroupID; j++) + if ((gList[j].libC == 2) && + (ndbord[gList[j].lx][gList[j].ly] == -1)) + { + spanGroup(gList[j].lx, gList[j].ly, &dapList2); + intersectPlist(&dapList1, &dapList2, &dapList3); + if (dapList3.indx > 0) + if (legal[dapList3.p[1].px][dapList3.p[1].py]) + { + tryPlay(dapList3.p[1].px, dapList3.p[1].py, 1); + if (gList[groupIDs[dapList3.p[1].px][ + dapList3.p[1].py]].libC > 1) + { + *x = dapList3.p[1].px; + *y = dapList3.p[1].py; + restoreState(); + return TRUE; + } + restoreState(); + } + } + } + return FALSE; + } /* doubleAtari */ + +short lookForAttack(x, y) +short *x, *y; + { /* lookForAttack */ + short tx, ty, i; + playReason = "lookForAttack"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((! gList[i].isLive) && + (gList[i].libC > 1) && + (gList[i].libC <= (treeLibLim + 1)) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */ + { + *x = tx; /* yep - do so */ + *y = ty; + return TRUE; + } + } + return FALSE; + } /* lookForAttack */ + + /* + Plays a move that requires a response on the opponent's part + */ +short threaten(x, y) +short *x, *y; + { /* threaten */ + short i, j, gx, gy, tNum; + playReason = "threaten"; + initArray(threatBord); + for (i = 1; i <= maxGroupID; i++) + if ((! gList[i].isLive) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + spanGroup(gList[i].lx, gList[i].ly, &pList); + for (j = 1; j <= pList.indx; j++) + if (legal[pList.p[j].px][pList.p[j].py]) + { + tryPlay(pList.p[j].px, pList.p[j].py, 1); + if (gList[groupIDs[pList.p[j].px][pList.p[j].py]].libC > 1) + if (killable(gList[i].lx, gList[i].ly, &gx, &gy)) + threatBord[pList.p[j].px][pList.p[j].py] += 1; + restoreState(); + } + } + tNum = 0; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((threatBord[i][j] > tNum) && + ((threatBord[i][j] > 1) || + (connectMap[i][j] > 0))) + { + tNum = threatBord[i][j]; + *x = i; + *y = j; + } + if (tNum > 0) return TRUE; + else return FALSE; + } /* threaten */ + + /* + connects against enemy cuts + */ +short connectCut(x, y) +short *x, *y; + { /* connectCut */ + short i, j, nap, gid, infl; + playReason = "connectCut"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j] && + (protPoints[i][j] == 0)) /* not a protected point */ + { + nap = 0; /* how many of my stones am I adjacent to? */ + if ((i > 0) && (bord[i - 1][j] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i - 1; + pList.p[nap].py = j; + } + if ((j > 0) && (bord[i][j - 1] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j - 1; + } + if ((i < maxPoint) && (bord[i + 1][j] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i + 1; + pList.p[nap].py = j; + } + if ((j < maxPoint) && (bord[i][j + 1] == 1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j + 1; + } + if (nap == 1) /* possible knight's || 2-point extention */ + { + gid = groupIDs[pList.p[1].px][pList.p[1].py]; + if ((i > 0) && (i < maxPoint) && + (ndbord[i - 1][j] == 1) && + (ndbord[i + 1][j] == 0)) /* contact on left */ + { + if (((j > 0) && (ndbord[i][j - 1] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1) && + (ndbord[i + 1][j + 1] == 1) && + (gid != groupIDs[i + 1][j + 1])) || + ((((j > 0) && (ndbord[i][j - 1] == -1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1))) && + (i < (maxPoint - 1)) && + (ndbord[i + 2][j] == 1) && + (gid != groupIDs[i + 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((i < maxPoint) && (i > 0) && + (ndbord[i + 1][j] == 1) && + (ndbord[i - 1][j] == 0)) /* r */ + { + if (((j > 0) && (ndbord[i][j - 1] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (gid != groupIDs[i - 1][j - 1])) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (gid != groupIDs[i - 1][j + 1])) || + ((((j > 0) && (ndbord[i][j - 1] == -1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == -1))) && + (i > 1) && + (ndbord[i - 2][j] == 1) && + (gid != groupIDs[i - 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j - 1] == 1) && + (ndbord[i][j + 1] == 0)) /* top */ + { + if (((i > 0) && (ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j + 1] == 1) && + (gid != groupIDs[i + 1][j + 1])) || + ((((i > 0) && (ndbord[i - 1][j] == -1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1))) && + (j < (maxPoint - 1)) && + (ndbord[i][j + 2] == 1) && + (gid != groupIDs[i][j + 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j + 1] == 1) && + (ndbord[i][j - 1] == 0)) /* bottom */ + { + if (((i > 0) && (ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (gid != groupIDs[i - 1][j - 1])) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (gid != groupIDs[i + 1][j - 1])) || + ((((i > 0) && (ndbord[i - 1][j] == -1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == -1))) && + (j > 1) && + (ndbord[i][j - 2] == 1) && + (gid != groupIDs[i][j - 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + else if (nap == 2) /* diagonal or 1-point extention */ + { + if (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) + { + if ((pList.p[1].px != pList.p[2].px) && + (pList.p[1].py != pList.p[2].py)) /* diag */ + { + spanGroup(pList.p[1].px, + pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, + pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + if (plist3.indx == 1) + if ((i > 0) && (ndbord[i - 1][j] == -1) || + (i < maxPoint) && (ndbord[i + 1][j] == -1) || + (j > 0) && (ndbord[i][j - 1] == -1) || + (j < maxPoint) && (ndbord[i][j + 1] == -1)) + { /* must make direct connection */ + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + else if (heCanCut(i, j)) + { /* protect point if possible */ + infl = 1000; + if ((i > 0) && legal[i - 1][j] && + ((i == 1) || (ndbord[i - 2][j] == 0)) && + ((j == 0) || (ndbord[i - 1][j - 1] == 0)) && + ((j == maxPoint) || + (ndbord[i - 1][j + 1] == 0))) + if (safeMove(i - 1, j)) + if (claim[i - 1][j] < infl) + { + *x = i - 1; + *y = j; + infl = claim[i - 1][j]; + } + if ((j > 0) && legal[i][j - 1] && + ((j == 1) || (ndbord[i][j - 2] == 0)) && + ((i == 0) || (ndbord[i - 1][j - 1] == 0)) && + ((i == maxPoint) || + (ndbord[i + 1][j - 1] == 0))) + if (safeMove(i, j - 1)) + if (claim[i][j - 1] < infl) + { + *x = i; + *y = j - 1; + infl = claim[i][j - 1]; + } + if ((i < maxPoint) && legal[i + 1][j] && + ((i == (maxPoint - 1)) || + (ndbord[i + 2][j] == 0)) && + ((j == 0) || (ndbord[i + 1][j - 1] == 0)) && + ((j == maxPoint) || + (ndbord[i + 1][j + 1] == 0))) + if (safeMove(i + 1, j)) + if (claim[i + 1][j] < infl) + { + *x = i + 1; + *y = j; + infl = claim[i + 1][j]; + } + if ((j < maxPoint) && legal[i][j + 1] && + ((j == (maxPoint - 1)) || + (ndbord[i][j + 2] == 0)) && + ((i == 0) || (ndbord[i - 1][j + 1] == 0)) && + ((i == maxPoint) || + (ndbord[i + 1][j + 1] == 0))) + if (safeMove(i, j + 1)) + if (claim[i][j + 1] < infl) + { + *x = i; + *y = j + 1; + infl = claim[i][j + 1]; + } + if (infl < 1000) + return TRUE; + *x = i; /* direct connection */ + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else /* 1-point extension, only protect if threatened */ + { + if ((i > 0) && (ndbord[i - 1][j] == -1) || + (j > 0) && (ndbord[i][j - 1] == -1) || + (i < maxPoint) && (ndbord[i + 1][j] == -1) || + (j < maxPoint) && (ndbord[i][j + 1] == -1)) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + } + } + else if (nap == 3) /* unprotected, but me on 3 sides */ + { + if ((groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) || + (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[3].px][pList.p[3].py]) || + (groupIDs[pList.p[3].px][pList.p[3].py] != + groupIDs[pList.p[2].px][pList.p[2].py])) + { + spanGroup(pList.p[1].px, pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + spanGroup(pList.p[3].px, pList.p[3].py, &plist2); + intersectPlist(&plist2, &plist3, &pList1); + if (pList1.indx == 1) /* a common connect point */ + if (heCanCut(i, j)) + if (safeMove(i, j)) + { + *x = i; + *y = j; + return TRUE; + } + } + } + } + return FALSE; + } /* connectCut */ + +short heCanCut(x, y) +short x, y; + { /* heCanCut */ + short gx, gy, result; + if (playLevel > 3) + { + tryPlay(x, y, -1); /* try his cut */ + result = ! killable(x, y, &gx, &gy); + restoreState(); + return result; + } + else + return FALSE; + } /* heCanCut */ + + /* + Checks out a move. + If my stone is not killable then true. + */ +short safeMove(x, y) +short x, y; + { /* safeMove */ + short gbx, gby, result; + tryPlay(x, y, 1); /* try playing at point */ + if (killFlag) /* I shouldn't kill if lookForKill didn't */ + result = FALSE; + else if (gList[groupIDs[x][y]].libC < 2) + { /* if it is in atari or dead */ + result = FALSE; /* reject it */ + } + else if (gList[groupIDs[x][y]].libC <= treeLibLim) /* see if killable */ + if (playLevel > 0) + result = ! killable(x, y, &gbx, &gby); + else + result = TRUE; + else + result = TRUE; + restoreState(); + return result; + } /* safeMove */ + + /* + Extends walls in a connected fashion. + Finds the lowest influence (mine) point that is connected to one + of my groups. + Only looks in the center of the board. + */ +short extendWall(x, y) +short *x, *y; + { /* extendWall */ + short infl, i, j; + playReason = "extendWall"; + *x = iNil; + *y = iNil; + infl = 11; + for (i = 2; i <= maxPoint - 2; i++) + for (j = 2; j <= maxPoint - 2; j++) + if (legal[i][j]) + if (connectMap[i][j] > 0) + if ((claim[i][j] < infl) && + (ndbord[i - 1][j] < 1) && + (ndbord[i + 1][j] < 1) && + (ndbord[i][j - 1] < 1) && + (ndbord[i][j + 1] < 1) && + ((claim[i - 1][j] < 0) || + (claim[i + 1][j] < 0) || + (claim[i][j - 1] < 0) || + (claim[i][j + 1] < 0))) + if (safeMove(i, j)) + { + infl = claim[i][j]; + *x = i; + *y = j; + } + if (*x != iNil) return TRUE; + return FALSE; + } /* extendWall */ + + + /* + check to see if I can attack one of his groups + uses limited depth search so that it can work on larger lib counts + */ +short findAttack2(x, y) +short *x, *y; + { /* findAttack2 */ + short tx, ty, i, otll; + if (playLevel < 7) + return FALSE; + playReason = "findAttack2"; + depthLimit = 8; + otll = treeLibLim; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((! gList[i].isLive) && + (ndbord[gList[i].lx][gList[i].ly] == -1) && + (gList[i].libC > 1)) + { + treeLibLim = 6; + if (killable(gList[i].lx, gList[i].ly, &tx, &ty)) /* can we kill it? */ + { + *x = tx; /* yep - do so */ + *y = ty; + return TRUE; + } + treeLibLim = otll; + } + depthLimit = 100; + return FALSE; + } /* findAttack2 */ + + + /* + blocks enemy cuts thru 1-point extensions + */ +short blockCut(x, y) +short *x, *y; + { /* blockCut */ + short i, j; + playReason = "blockCut"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + { + if ((i > 0) && (j > 0) && (j < maxPoint)) + { + if ((ndbord[i - 1][j] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (ndbord[i - 1][j + 1] == 1) && + (groupIDs[i - 1][j - 1] != groupIDs[i - 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((i < maxPoint) && (j > 0) && (j < maxPoint)) + { + if ((ndbord[i + 1][j] == -1) && + (ndbord[i + 1][j - 1] == 1) && + (ndbord[i + 1][j + 1] == 1) && + (groupIDs[i + 1][j - 1] != groupIDs[i + 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((j > 0) && (i > 0) && (i < maxPoint)) + { + if ((ndbord[i][j - 1] == -1) && + (ndbord[i - 1][j - 1] == 1) && + (ndbord[i + 1][j - 1] == 1) && + (groupIDs[i - 1][j - 1] != groupIDs[i + 1][j - 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + if ((j < maxPoint) && (i > 0) && (i < maxPoint)) + { + if ((ndbord[i][j + 1] == -1) && + (ndbord[i - 1][j + 1] == 1) && + (ndbord[i + 1][j + 1] == 1) && + (groupIDs[i - 1][j + 1] != groupIDs[i + 1][j + 1])) + { + *x = i; + *y = j; + if (heCanCut(*x, *y)) + if (safeMove(*x, *y)) + return TRUE; + } + } + } + return FALSE; + } /* blockCut */ + + + /* + cuts the enemy + */ +short cutHim(x, y) +short *x, *y; + { /* cutHim */ + short i, j, nap, gid; + playReason = "cutHim"; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + { + nap = 0; /* how many of his stones am I adjacent to? */ + if ((i > 0) && (ndbord[i - 1][j] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i - 1; + pList.p[nap].py = j; + } + if ((j > 0) && (ndbord[i][j - 1] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j - 1; + } + if ((i < maxPoint) && (ndbord[i + 1][j] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i + 1; + pList.p[nap].py = j; + } + if ((j < maxPoint) && (ndbord[i][j + 1] == -1)) + { + nap = nap + 1; + pList.p[nap].px = i; + pList.p[nap].py = j + 1; + } + if (nap == 1) /* possible knight's or 2-point extention */ + { + gid = groupIDs[pList.p[1].px][pList.p[1].py]; + if ((i > 0) && (i < maxPoint) && + (ndbord[i - 1][j] == -1) && + (connectMap[i][j] > 0)) /* contact on left */ + { + if (((j > 0) && + (ndbord[i + 1][j - 1] == -1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j < maxPoint) && + (ndbord[i + 1][j + 1] == -1) && + (gid != groupIDs[i + 1][j + 1])) || + ((i < (maxPoint - 1)) && + (ndbord[i + 1][j] == 0) && + (ndbord[i + 2][j] == -1) && + (gid != groupIDs[i + 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((i < maxPoint) && (i > 0) && + (ndbord[i + 1][j] == -1) && + (connectMap[i][j] > 0)) /* r */ + { + if (((j > 0) && + (ndbord[i - 1][j - 1] == -1) && + (gid != groupIDs[i - 1][j - 1])) || + ((j < maxPoint) && + (ndbord[i - 1][j + 1] == -1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i > 1) && + (ndbord[i - 1][j] == 0) && + (ndbord[i - 2][j] == -1) && + (gid != groupIDs[i - 2][j]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j - 1] == -1) && + (connectMap[i][j] > 0)) /* top */ + { + if (((i > 0) && + (ndbord[i - 1][j + 1] == -1) && + (gid != groupIDs[i - 1][j + 1])) || + ((i < maxPoint) && + (ndbord[i + 1][j + 1] == -1) && + (gid != groupIDs[i + 1][j + 1])) || + ((j < (maxPoint - 1)) && + (ndbord[i][j + 1] == 0) && + (ndbord[i][j + 2] == -1) && + (gid != groupIDs[i][j + 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else if ((j > 0) && (j < maxPoint) && + (ndbord[i][j + 1] == -1) && + (connectMap[i][j] > 0)) /* bottom */ + { + if (((i > 0) && + (ndbord[i - 1][j - 1] == -1) && + (gid != groupIDs[i - 1][j - 1])) || + ((i < maxPoint) && + (ndbord[i + 1][j - 1] == -1) && + (gid != groupIDs[i + 1][j - 1])) || + ((j > 1) && + (ndbord[i][j - 1] == 0) && + (ndbord[i][j - 2] == -1) && + (gid != groupIDs[i][j - 2]))) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + else if (nap == 2) /* diagonal or 1-point extention */ + { + if (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) + { + if ((pList.p[1].px != pList.p[2].px) && + (pList.p[1].py != pList.p[2].py)) /* diag */ + { + spanGroup(pList.p[1].px, + pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, + pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + if (plist3.indx == 1) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + else /* 1-point extension, only cut if connected */ + { + if (connectMap[i][j] > 0) + { + *x = i; + *y = j; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + } + else if (nap == 3) /* unprotected, but him on 3 sides */ + { + if ((groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[2].px][pList.p[2].py]) || + (groupIDs[pList.p[1].px][pList.p[1].py] != + groupIDs[pList.p[3].px][pList.p[3].py]) || + (groupIDs[pList.p[3].px][pList.p[3].py] != + groupIDs[pList.p[2].px][pList.p[2].py])) + { + spanGroup(pList.p[1].px, pList.p[1].py, &pList1); + spanGroup(pList.p[2].px, pList.p[2].py, &plist2); + intersectPlist(&pList1, &plist2, &plist3); + spanGroup(pList.p[3].px, pList.p[3].py, &plist2); + intersectPlist(&plist2, &plist3, &pList1); + if (pList1.indx == 1) /* a common connect point */ + if (safeMove(i, j)) + { + *x = i; + *y = j; + return TRUE; + } + } + } + } + return FALSE; + } /* cutHim */ + + + /* + ataris a group just for the hell of it + */ +short atariAnyway(x, y) +short *x, *y; + { /* atariAnyway */ + short i; + playReason = "atariAnyway"; + for (i = 1; i <= maxGroupID; i++) /* scan the group list */ + if ((gList[i].libC == 2) && + (ndbord[gList[i].lx][gList[i].ly] == -1)) + { + spanGroup(gList[i].lx, gList[i].ly, &pList); + if (legal[pList.p[1].px][pList.p[1].py] && + ((connectMap[pList.p[1].px][pList.p[1].py] > 0) || + ((pList.p[1].px > 0) && + (connectMap[pList.p[1].px - 1][pList.p[1].py] > 0)) || + ((pList.p[1].px < maxPoint) && + (connectMap[pList.p[1].px + 1][pList.p[1].py] > 0)) || + ((pList.p[1].py > 0) && + (connectMap[pList.p[1].px][pList.p[1].py - 1] > 0)) || + ((pList.p[1].py < maxPoint) && + (connectMap[pList.p[1].px][pList.p[1].py + 1] > 0)))) + if (safeMove(pList.p[1].px, pList.p[1].py)) + { + *x = pList.p[1].px; + *y = pList.p[1].py; + return TRUE; + } + if (legal[pList.p[2].px][pList.p[2].py] && + ((connectMap[pList.p[2].px][pList.p[2].py] > 0) || + ((pList.p[2].px > 0) && + (connectMap[pList.p[2].px - 1][pList.p[2].py] > 0)) || + ((pList.p[2].px < maxPoint) && + (connectMap[pList.p[2].px + 1][pList.p[2].py] > 0)) || + ((pList.p[2].py > 0) && + (connectMap[pList.p[2].px][pList.p[2].py - 1] > 0)) || + ((pList.p[2].py < maxPoint) && + (connectMap[pList.p[2].px][pList.p[2].py + 1] > 0)))) + if (safeMove(pList.p[2].px, pList.p[2].py)) + { + *x = pList.p[2].px; + *y = pList.p[2].py; + return TRUE; + } + } + return FALSE; + } /* atariAnyway */ + + + /* + undercuts his groups + */ +short underCut(x, y) +short *x, *y; + { /* underCut */ + short i, j; + playReason = "underCut"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[0][i]) + { + if (ndbord[1][i] == -1) + if (safeMove(0, i)) + { + *x = 0; + *y = i; + return TRUE; + } + } + if (legal[maxPoint][i]) + { + if (ndbord[maxPoint - 1][i] == -1) + if (safeMove(maxPoint, i)) + { + *x = maxPoint; + *y = i; + return TRUE; + } + } + if (legal[i][0]) + { + if (ndbord[i][1] == -1) + if (safeMove(i, 0)) + { + *x = i; + *y = 0; + return TRUE; + } + } + if (legal[i][maxPoint]) + { + if (ndbord[i][maxPoint - 1] == -1) + if (safeMove(i, maxPoint)) + { + *x = i; + *y = maxPoint; + return TRUE; + } + } + } + return FALSE; + } /* underCut */ + + /* + drops to the edge of the board if threatened + */ +short dropToEdge(x, y) +short *x, *y; + { /* dropToEdge */ + short i; + playReason = "dropToEdge"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[1][i]) + if ((ndbord[2][i] == 1) && + (ndbord[0][i] == 0) && + (ndbord[1][i - 1] < 1) && + (ndbord[1][i + 1] < 1) && + ((ndbord[2][i - 1] == -1) || + (ndbord[2][i + 1] == -1) || + (ndbord[1][i - 1] == -1) || + (ndbord[1][i + 1] == -1))) + { + *x = 1; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[maxPoint - 1][i]) + if ((ndbord[maxPoint - 2][i] == 1) && + (ndbord[maxPoint][i] == 0) && + (ndbord[maxPoint - 1][i - 1] < 1) && + (ndbord[maxPoint - 1][i + 1] < 1) && + ((ndbord[maxPoint - 2][i - 1] == -1) || + (ndbord[maxPoint - 2][i + 1] == -1) || + (ndbord[maxPoint - 1][i - 1] == -1) || + (ndbord[maxPoint - 1][i + 1] == -1))) + { + *x = maxPoint - 1; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][1]) + if ((ndbord[i][2] == 1) && + (ndbord[i][0] == 0) && + (ndbord[i - 1][1] < 1) && + (ndbord[i + 1][1] < 1) && + ((ndbord[i - 1][2] == -1) || + (ndbord[i + 1][2] == -1) || + (ndbord[i - 1][1] == -1) || + (ndbord[i + 1][1] == -1))) + { + *x = i; + *y = 1; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][maxPoint - 1]) + if ((ndbord[i][maxPoint - 2] == 1) && + (ndbord[i][maxPoint] == 0) && + (ndbord[i - 1][maxPoint - 1] < 1) && + (ndbord[i + 1][maxPoint - 1] < 1) && + ((ndbord[i - 1][maxPoint - 2] == -1) || + (ndbord[i + 1][maxPoint - 2] == -1) || + (ndbord[i - 1][maxPoint - 1] == -1) || + (ndbord[i + 1][maxPoint - 1] == -1))) + { + *x = i; + *y = maxPoint - 1; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[0][i]) + if ((ndbord[1][i] == 1) && + (ndbord[0][i - 1] < 1) && + (ndbord[0][i + 1] < 1) && + (((ndbord[1][i - 1] == -1) && + (ndbord[1][i + 1] == -1)) || + (ndbord[0][i - 1] == -1) || + (ndbord[0][i + 1] == -1))) + { + *x = 0; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[maxPoint][i]) + if ((ndbord[maxPoint - 1][i] == 1) && + (ndbord[maxPoint][i - 1] < 1) && + (ndbord[maxPoint][i + 1] < 1) && + (((ndbord[maxPoint - 1][i - 1] == -1) && + (ndbord[maxPoint - 1][i + 1] == -1)) || + (ndbord[maxPoint][i - 1] == -1) || + (ndbord[maxPoint][i + 1] == -1))) + { + *x = maxPoint; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][0]) + if ((ndbord[i][1] == 1) && + (ndbord[i - 1][0] < 1) && + (ndbord[i + 1][0] < 1) && + (((ndbord[i - 1][1] == -1) && + (ndbord[i + 1][1] == -1)) || + (ndbord[i - 1][0] == -1) || + (ndbord[i + 1][0] == -1))) + { + *x = i; + *y = 0; + if (safeMove(*x, *y)) + return TRUE; + } + if (legal[i][maxPoint]) + if ((ndbord[i][maxPoint - 1] == 1) && + (ndbord[i - 1][maxPoint] < 1) && + (ndbord[i + 1][maxPoint] < 1) && + (((ndbord[i - 1][maxPoint - 1] == -1) && + (ndbord[i + 1][maxPoint - 1] == -1)) || + (ndbord[i - 1][maxPoint] == -1) || + (ndbord[i + 1][maxPoint] == -1))) + { + *x = i; + *y = maxPoint; + if (safeMove(*x, *y)) + return TRUE; + } + } + return FALSE; + } /* dropToEdge */ + + /* + Pushes walls in a tightly connected fashion. + Finds the lowest influence (mine) point that is connected to one + of my groups. + */ +short pushWall(x, y) +short *x, *y; + { /* pushWall */ + short infl, i, j, na; + playReason = "pushWall"; + *x = iNil; + *y = iNil; + infl = 11; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (legal[i][j]) + if (connectMap[i][j] > 0) + if ((claim[i][j] < infl) && + (((i > 0) && (ndbord[i - 1][j] == 1)) || + ((i < maxPoint) && (ndbord[i + 1][j] == 1)) || + ((j > 0) && (ndbord[i][j - 1] == 1)) || + ((j < maxPoint) && (ndbord[i][j + 1] == 1)) || + ((i > 0) && (j > 0) && (ndbord[i - 1][j - 1] == 1)) || + ((i < maxPoint) && (j > 0) && (ndbord[i + 1][j - 1] == 1)) || + ((i > 0) && (j < maxPoint) && (ndbord[i - 1][j + 1] == 1)) || + ((i < maxPoint) && (j < maxPoint) && + (ndbord[i + 1][j + 1] == 1))) && + (((i > 0) && (claim[i - 1][j] < 0)) || + ((i < maxPoint) && (claim[i + 1][j] < 0)) || + ((j > 0) && (claim[i][j - 1] < 0)) || + ((j < maxPoint) && (claim[i][j + 1] < 0)))) + { + na = 0; + if ((i > 0) && (ndbord[i - 1][j] != 0)) + na = na + 1; + if ((i < maxPoint) && (ndbord[i + 1][j] != 0)) + na = na + 1; + if ((j > 0) && (ndbord[i][j - 1] != 0)) + na = na + 1; + if ((j < maxPoint) && (ndbord[i][j + 1] != 0)) + na = na + 1; + if (na < 3) + if (safeMove(i, j)) + { + infl = claim[i][j]; + *x = i; + *y = j; + } + } + if (*x != iNil) return TRUE; + return FALSE; + } /* pushWall */ + + + /* + reduces the liberty count of one of his groups + */ +short reduceHisLiberties(x, y) +short *x, *y; + { /* reduceHisLiberties */ + short i, j; + playReason = "reduceHisLiberties"; + sortLibs(); + for (i = 1; i <= maxGroupID; i++) + if ((! gList[sGlist[i]].isLive) && + (gList[sGlist[i]].libC > 2) && + (ndbord[gList[sGlist[i]].lx][gList[sGlist[i]].ly] == -1)) + { + spanGroup(gList[sGlist[i]].lx, gList[sGlist[i]].ly, &pList); + for (j = 1; j <= pList.indx; j++) + if (legal[pList.p[j].px][pList.p[j].py] && + (connectMap[pList.p[j].px][pList.p[j].py] > 0)) + if (safeMove(pList.p[j].px, pList.p[j].py)) + { + *x = pList.p[j].px; + *y = pList.p[j].py; + return TRUE; + } + } + return FALSE; + } /* reduceHisLiberties */ + + + /* + connects a group to the edge + */ +short dropToEdge2(x, y) +short *x, *y; + { /* dropToEdge2 */ + short i; + playReason = "dropToEdge2"; + for (i = 1; i <= maxPoint - 1; i++) + { + if (legal[i][0]) + { + if ((ndbord[i][1] == 1) && + ((ndbord[i - 1][0] < 1) || + (groupIDs[i - 1][0] != groupIDs[i][1])) && + ((ndbord[i + 1][0] < 1) || + (groupIDs[i + 1][0] != groupIDs[i][1])) && + ((ndbord[i - 1][1] == -1) || + (ndbord[i + 1][1] == -1))) + { + *x = i; + *y = 0; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[0][i]) + { + if ((ndbord[1][i] == 1) && + ((ndbord[0][i - 1] < 1) || + (groupIDs[0][i - 1] != groupIDs[1][i])) && + ((ndbord[0][i + 1] < 1) || + (groupIDs[0][i + 1] != groupIDs[1][i])) && + ((ndbord[1][i - 1] == -1) || + (ndbord[1][i + 1] == -1))) + { + *x = 0; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[i][maxPoint]) + { + if ((ndbord[i][maxPoint - 1] == 1) && + ((ndbord[i - 1][maxPoint] < 1) || + (groupIDs[i - 1][maxPoint] != groupIDs[i][maxPoint - 1])) && + ((ndbord[i + 1][maxPoint] < 1) || + (groupIDs[i + 1][maxPoint] != groupIDs[i][maxPoint - 1])) && + ((ndbord[i - 1][maxPoint - 1] == -1) || + (ndbord[i + 1][maxPoint - 1] == -1))) + { + *x = i; + *y = maxPoint; + if (safeMove(*x, *y)) + return TRUE; + } + } + if (legal[maxPoint][i]) + { + if ((ndbord[maxPoint - 1][i] == 1) && + ((ndbord[maxPoint][i - 1] < 1) || + (groupIDs[maxPoint][i - 1] != groupIDs[maxPoint - 1][i])) && + ((ndbord[maxPoint][i + 1] < 1) || + (groupIDs[maxPoint][i + 1] != groupIDs[maxPoint - 1][i])) && + ((ndbord[maxPoint - 1][i - 1] == -1) || + (ndbord[maxPoint - 1][i + 1] == -1))) + { + *x = maxPoint; + *y = i; + if (safeMove(*x, *y)) + return TRUE; + } + } + } + return FALSE; + } /* dropToEdge2 */ + diff --git a/noncore/games/go/goplayutils.c b/noncore/games/go/goplayutils.c new file mode 100644 index 0000000..9e2ce4c --- a/dev/null +++ b/noncore/games/go/goplayutils.c @@ -0,0 +1,1317 @@ +/* The go player utilities */ +/* Ported from Pascal to C by Todd R. Johnson */ +/* From the original Pascal file: +Copyright (c) 1983 by Three Rivers Computer Corp. + +Written: January 17, 1983 by Stoney Ballard +*/ + +#include "goplayutils.h" +#include "amigo.h" +#include "go.h" + +extern struct bRec goboard[19][19]; + +intBoard claim, extra, bord, ndbord, sGroups, threatBord, + groupIDs, connectMap, protPoints; +boolBoard groupSeen, legal; +short maxGroupID; +pointList pList, pList1, plist2, plist3, pPlist; +intList nlcGroup, aList; +sgRec sList[401]; +groupRec gList[maxGroup]; +short killFlag, + numCapt, + utilPlayLevel, + treeLibLim; +sType mySType; +short showTrees; +short sGlist[maxGroup+1]; +short depthLimit; +intBoard markBoard; +short marker; + +short adjInAtari, adj2Libs, + intersectNum, spanNum, libMark; +playRec playStack[1025]; +short playMark, + newGID, + tryLevel, + grpMark, + gMap[maxGroup]; +short dbStop, inGenState; + + pause() +{ /* pause */ +/* if (dbStop and ! inGenState) + { + while ! tabswitch do; + repeat + if (tabYellow) + dbStop = false; + until ! tabswitch; + } */ +} /* pause */ + +sstone(w, x, y, numb) +short w, x, y, numb; +{ /* sstone */ + if (w == 1) + placestone(mySType, x, y); + else if (mySType == WHITE) + placestone(BLACK, x, y); + else + placestone(WHITE, x, y); +} /* sstone */ + +rstone(x, y) +short x, y; +{ /* rstone */ + removestone(x, y); +} /* rstone */ + +initBoolBoard(bb) +boolBoard bb; +{ /* initBoolBoard */ + short i, j; +#ifdef DEBUG + printf( "initBoolBoard\n" ); +#endif + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + bb[i][j] = FALSE; +} /* initBoolBoard */ + +sortLibs() +{ /* sortLibs */ + short i, j, t; +#ifdef DEBUG + printf( "sortLibs\n" ); +#endif + for (i = 1; i <= maxGroupID; i++) + sGlist[i] = i; + for (i = 1; i < maxGroupID; i++) + for (j = i + 1; j <= maxGroupID; j++) + if (gList[sGlist[i]].libC > gList[sGlist[j]].libC) + { + t = sGlist[i]; + sGlist[i] = sGlist[j]; + sGlist[j] = t; + } +} /* sortLibs */ + +spanGroupspan(x, y, libs, lookFor) +short x, y, lookFor; +pointList *libs; + { /* span */ + markBoard[x][y] = marker; + if (bord[x][y] == 0) + { + libs->indx = libs->indx + 1; + libs->p[libs->indx].px = x; + libs->p[libs->indx].py = y; + } + else if (bord[x][y] == lookFor) + { + groupSeen[x][y] = TRUE; + if ((x > 0) && (markBoard[x - 1][y] != marker)) + spanGroupspan(x - 1, y, libs, lookFor); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + spanGroupspan(x, y - 1, libs, lookFor); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + spanGroupspan(x + 1, y, libs, lookFor); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + spanGroupspan(x, y + 1, libs, lookFor); + } + else if (gList[gMap[groupIDs[x][y]]].libC == 1) + adjInAtari = TRUE; + else if ((gList[gMap[groupIDs[x][y]]].libC == 2) && + (! gList[gMap[groupIDs[x][y]]].isLive)) + adj2Libs = TRUE; + } /* span */ + +spanGroup(x, y, libs) +short x, y; +pointList *libs; +{ /* spanGroup */ + short lookFor; +#ifdef DEBUG + printf( "spanGroup\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + adjInAtari = FALSE; + adj2Libs = FALSE; + lookFor = bord[x][y]; + libs->indx = 0; + spanGroupspan(x, y, libs, lookFor); +} /* spanGroup */ + +sSpanGroupspan(x, y, libs, lookFor) +short x, y, lookFor; +sPointList *libs; + { /* span */ + markBoard[x][y] = marker; + if (bord[x][y] == 0) + { + libs->indx += 1; + if (libs->indx <= maxSPoint) + { + libs->p[libs->indx].px = x; + libs->p[libs->indx].py = y; + } + } + else if (bord[x][y] == lookFor) + { + groupSeen[x][y] = TRUE; + if ((x > 0) && (markBoard[x - 1][y] != marker)) + sSpanGroupspan(x - 1, y, libs, lookFor); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + sSpanGroupspan(x, y - 1, libs, lookFor); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + sSpanGroupspan(x + 1, y, libs, lookFor); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + sSpanGroupspan(x, y + 1, libs, lookFor); + } + else if (gList[gMap[groupIDs[x][y]]].libC == 1) + adjInAtari = TRUE; + else if ((gList[gMap[groupIDs[x][y]]].libC == 2) && + (! gList[gMap[groupIDs[x][y]]].isLive)) + adj2Libs = TRUE; + } /* span */ + +sSpanGroup(x, y, libs) +short x, y; +sPointList *libs; +{ /* sSpanGroup */ + short lookFor; +#ifdef DEBUG + printf( "sSpanGroup\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + adjInAtari = FALSE; + adj2Libs = FALSE; + lookFor = bord[x][y]; + libs->indx = 0; + sSpanGroupspan(x, y, libs, lookFor); +} /* sSpanGroup */ + +LAspan(x, y, me, him, iL) +short x, y, me, him; +intList *iL; + { /* span */ +#ifdef DEBUG + printf( "LAspan\n" ); +#endif + markBoard[x][y] = marker; + if (bord[x][y] == me) + { + if ((x > 0) && (markBoard[x - 1][y] != marker)) + LAspan(x - 1, y, me, him, iL); + if ((x < maxPoint) && (markBoard[x + 1][y] != marker)) + LAspan(x + 1, y, me, him, iL); + if ((y > 0) && (markBoard[x][y - 1] != marker)) + LAspan(x, y - 1, me, him, iL); + if ((y < maxPoint) && (markBoard[x][y + 1] != marker)) + LAspan(x, y + 1, me, him, iL); + } + else if (bord[x][y] == him) + if (gList[gMap[groupIDs[x][y]]].groupMark != grpMark) + { + gList[gMap[groupIDs[x][y]]].groupMark = grpMark; + iL->indx = iL->indx + 1; + iL->v[iL->indx] = gMap[groupIDs[x][y]]; + } + } /* span */ + +listAdjacents(x, y, iL) +short x, y; +intList *iL; +{ /* listAdjacents */ + short me, him; +#ifdef DEBUG + printf( "listAdjacents\n" ); +#endif + grpMark = grpMark + 1; + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + iL->indx = 0; + me = bord[x][y]; + him = -me; + LAspan(x, y, me , him, iL); +} /* listAdjacents */ + +LDspan(x, y, me, diags) +short x, y, me; +sPointList *diags; + { /* span */ +#ifdef DEBUG + printf( "LDspan\n" ); +#endif + markBoard[x][y] = marker; + if ((x > 0) && (y > 0) && + (bord[x - 1][y - 1] == 0) && + (bord[x][y - 1] != me) && + (bord[x - 1][y] != me) && + (markBoard[x - 1][y - 1] != marker)) + { + markBoard[x - 1][y - 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x - 1; + diags->p[diags->indx].py = y - 1; + } + } + if ((x < maxPoint) && (y > 0) && + (bord[x + 1][y - 1] == 0) && + (bord[x][y - 1] != me) && + (bord[x + 1][y] != me) && + (markBoard[x + 1][y - 1] != marker)) + { + markBoard[x + 1][y - 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x + 1; + diags->p[diags->indx].py = y - 1; + } + } + if ((x > 0) && (y < maxPoint) && + (bord[x - 1][y + 1] == 0) && + (bord[x][y + 1] != me) && + (bord[x - 1][y] != me) && + (markBoard[x - 1][y + 1] != marker)) + { + markBoard[x - 1][y + 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x - 1; + diags->p[diags->indx].py = y + 1; + } + } + if ((x < maxPoint) && (y < maxPoint) && + (bord[x + 1][y + 1] == 0) && + (bord[x][y + 1] != me) && + (bord[x + 1][y] != me) && + (markBoard[x + 1][y + 1] != marker)) + { + markBoard[x + 1][y + 1] = marker; + diags->indx = diags->indx + 1; + if (diags->indx <= maxSPoint) + { + diags->p[diags->indx].px = x + 1; + diags->p[diags->indx].py = y + 1; + } + } + if ((x > 0) && (bord[x - 1][y] == me) && + (markBoard[x - 1][y] != marker)) + LDspan(x - 1, y, me, diags); + if ((x < maxPoint) && (bord[x + 1][y] == me) && + (markBoard[x + 1][y] != marker)) + LDspan(x + 1, y, me, diags); + if ((y > 0) && (bord[x][y - 1] == me) && + (markBoard[x][y - 1] != marker)) + LDspan(x, y - 1, me, diags); + if ((y < maxPoint) && (bord[x][y + 1] == me) && + (markBoard[x][y + 1] != marker)) + LDspan(x, y + 1, me , diags); +} /* span */ + +listDiags(x, y, diags) +short x, y; +sPointList *diags; +{ /* listDiags */ + short me; +#ifdef DEBUG + printf( "listDiags\n" ); +#endif + me = bord[x][y]; + diags->indx = 0; + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + LDspan(x, y, me, diags); +} /* listDiags */ + +intersectPlist(p1, p2, pr) +pointList *p1, *p2, *pr; +{ /* intersectPlist */ + short i, j, k; +#ifdef DEBUG + printf( "intersectPlist\n" ); +#endif + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + pr->indx = 0; + for (i = 1; i <= p1->indx; i++) + markBoard[p1->p[i].px][p1->p[i].py] = marker; + j = 0; + for (i = 1; i <= p2->indx; i++) + if (markBoard[p2->p[i].px][p2->p[i].py] == marker) + { + j = j + 1; + pr->p[j] = p2->p[i]; + } + pr->indx = j; +} /* intersectPlist */ + +initArray(ary) +intBoard ary; +{ /* initArray */ + short i, j; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + ary[i][j] = 0; +} /* initArray */ + +initState() +{ /* initState */ + short i, j; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + { + extra[i][j] = 0; + claim[i][j] = 0; + groupIDs[i][j] = 0; + connectMap[i][j] = 0; + protPoints[i][j] = 0; + } +} /* initState */ + +copyArray( dest, src ) +intBoard dest, src; +{ + short x, y; + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + dest[x][y] = src[x][y]; +} + +/* + generates a one-point spread in the force field array (claim) + + the spread from a single point after four calls is: + + 1 + 2 2 2 + 2 4 6 4 2 + 2 4 8 10 8 4 2 + 1 2 6 10 62 10 6 2 1 + 2 4 8 10 8 4 2 + 2 4 6 4 2 + 2 2 2 + 1 + +*/ +stake() +{ + short x, y; + initArray( extra ); + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + { + extra[x][y] = extra[x][y] + claim[x][y]; + if (claim[x][y] > 0) + { + if (x > 0) extra[x-1][y] += 1; + if (y > 0) extra[x][y-1] += 1; + if (x < maxPoint) extra[x+1][y] += 1; + if (y < maxPoint) extra[x][y+1] += 1; + } + else if (claim[x][y] < 0) + { + if (x > 0) extra[x-1][y] -= 1; + if (y > 0) extra[x][y-1] -= 1; + if (x < maxPoint) extra[x+1][y] -= 1; + if (y < maxPoint) extra[x][y+1] -= 1; + } + } + copyArray( claim, extra ); +} /* stake */ + +/* + sets up claim from the current board position +*/ +spread() +{ + short x, y; + for (y = 0; y <= maxPoint; y++) + for (x = 0; x <= maxPoint; x++) + claim[x][y] = ndbord[x][y] * 50; + stake(); + stake(); + stake(); + stake(); +} /* spread */ + +/* + gList is initialized with the size, loc, and libCount of each group + groupIDs contains the serial numbers of the groups. +*/ +Resspan(x, y, gID, gSize, libCount, who) +short x, y, gID, *gSize, *libCount, who; + { /* span */ + if ((bord[x][y] == 0) && + (markBoard[x][y] != marker)) /* a liberty */ + { + markBoard[x][y] = marker; + *libCount = *libCount + 1; + } + else if ((bord[x][y] == who) && + (groupIDs[x][y] == 0)) + { + groupIDs[x][y] = gID; + *gSize = *gSize + 1; + if (x > 0) + Resspan(x - 1, y, gID, gSize, libCount, who); + if (x < maxPoint) + Resspan(x + 1, y, gID, gSize, libCount, who); + if (y > 0) + Resspan(x, y - 1, gID, gSize, libCount, who); + if (y < maxPoint) + Resspan(x, y + 1, gID, gSize, libCount, who); + } + } /* span */ + +respreicen() +{ /* respreicen */ + short i, j, gID, libCount, gSize, who; + gID = 0; +#ifdef DEBUG + printf( "respreicen\n" ); +#endif + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + groupIDs[i][j] = 0; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((bord[i][j] != 0) && /* a stone there */ + (groupIDs[i][j] == 0)) /* not seen yet */ + { + marker = marker + 1; + if (marker == 0) + { + initArray(markBoard); + marker = 1; + } + gID = gID + 1; + libCount = 0; + gSize = 0; + who = bord[i][j]; + Resspan(i, j, gID, &gSize, &libCount, who); /* span the group, collecting info */ + gList[gID].groupMark = 0; + gList[gID].atLevel = 0; + gList[gID].isLive = FALSE; /* we don't know yet */ + gList[gID].isDead = FALSE; + gList[gID].numEyes = -1; + gList[gID].size = gSize; + gList[gID].libC = libCount; + gList[gID].lx = i; + gList[gID].ly = j; + gMap[gID] = gID; /* set up identity map */ + } + maxGroupID = gID; + newGID = gID; + grpMark = 0; +} /* respreicen */ + +/* + play z at [x, y]. + killFlag is set true if anything is killed. +*/ +killGroup(x, y, me, him) +short x, y, me, him; + { /* killGroup */ +#ifdef DEBUG + printf( "killGroup\n" ); +#endif + playMark = playMark + 1; + /* record this kill */ + playStack[playMark].kind = rem; + playStack[playMark].uval.rem.who = him; + playStack[playMark].uval.rem.xl = x; + playStack[playMark].uval.rem.yl = y; + playStack[playMark].gID = groupIDs[x][y]; + playStack[playMark].uval.rem.sNumber = goboard[x][y].mNum; + if (showTrees) + rstone(x, y); + numCapt = numCapt + 1; + bord[x][y] = 0; + groupIDs[x][y] = 0; + if (x > 0) + { + if (bord[x - 1][y] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x - 1][y]]; + } + else if (bord[x - 1][y] == him) + killGroup(x - 1, y, me , him); + } + if (x < maxPoint) + { + if (bord[x + 1][y] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x + 1][y]]; + } + else if (bord[x + 1][y] == him) + killGroup(x + 1, y, me, him); + } + if (y > 0) + { + if (bord[x][y - 1] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y - 1]]; + } + else if (bord[x][y - 1] == him) + killGroup(x, y - 1, me, him); + } + if (y < maxPoint) + { + if (bord[x][y + 1] == me) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y + 1]]; + } + else if (bord[x][y + 1] == him) + killGroup(x, y + 1, me, him); + } + } /* killGroup */ + +mergeGroup(sGID, myGID) +short sGID, myGID; + { /* mergeGroup */ + short i; +#ifdef DEBUG + printf( "mergeGroup\n" ); +#endif + for (i = 1; i <= newGID; i++) + if (gMap[i] == sGID) + { + playMark = playMark + 1; + playStack[playMark].kind = reMap; + playStack[playMark].gID = i; + playStack[playMark].uval.reMap.oldGID = sGID; + gMap[i] = myGID; + } + } /* mergeGroup */ + +tryPlay(x, y, z) +short x, y, z; +{ /* plei */ + short i, me, him, myGID; + short isNew; +#ifdef DEBUG + printf( "tryPlay\n" ); +#endif + me = z; + him = -me; + killFlag = FALSE; /* set true if something is killed */ + numCapt = 0; + tryLevel = tryLevel + 1; + isNew = FALSE; + bord[x][y] = z; /* play the stone */ + if ((x > 0) && (bord[x - 1][y] == me)) /* connect to adjacent group */ + myGID = gMap[groupIDs[x - 1][y]]; + else if ((x < maxPoint) && (bord[x + 1][y] == me)) + myGID = gMap[groupIDs[x + 1][y]]; + else if ((y > 0) && (bord[x][y - 1] == me)) + myGID = gMap[groupIDs[x][y - 1]]; + else if ((y < maxPoint) && (bord[x][y + 1] == me)) + myGID = gMap[groupIDs[x][y + 1]]; + else /* nobody to connect to */ + { + newGID = newGID + 1; + isNew = TRUE; + myGID = newGID; + gList[myGID].groupMark = 0; + gList[myGID].atLevel = tryLevel; + gList[myGID].isLive = FALSE; + gList[myGID].numEyes = -1; + gList[myGID].size = -1; + gList[myGID].lx = x; + gList[myGID].ly = y; + gMap[myGID] = myGID; + } + groupIDs[x][y] = myGID; + playMark = playMark + 1; + /* record this move */ + playStack[playMark].kind = add; + playStack[playMark].uval.add.who = me; + playStack[playMark].uval.add.xl = x; + playStack[playMark].uval.add.yl = y; + playStack[playMark].gID = myGID; + playStack[playMark].uval.add.sNumber = 0; + if (isNew) + playStack[playMark].uval.add.nextGID = newGID - 1; + else + playStack[playMark].uval.add.nextGID = newGID; + if (showTrees) + sstone(me, x, y, 0); + /* merge adjacent groups */ + if ((x > 0) && (bord[x - 1][y] == me) && + (gMap[groupIDs[x - 1][y]] != myGID)) + mergeGroup(gMap[groupIDs[x - 1][y]], myGID); + if ((x < maxPoint) && (bord[x + 1][y] == me) && + (gMap[groupIDs[x + 1][y]] != myGID)) + mergeGroup(gMap[groupIDs[x + 1][y]], myGID); + if ((y > 0) && (bord[x][y - 1] == me) && + (gMap[groupIDs[x][y - 1]] != myGID)) + mergeGroup(gMap[groupIDs[x][y - 1]], myGID); + if ((y < maxPoint) && (bord[x][y + 1] == me) && + (gMap[groupIDs[x][y + 1]] != myGID)) + mergeGroup(gMap[groupIDs[x][y + 1]], myGID); + /* kill opposing groups, listing affected groups */ + nlcGroup.indx = 1; + nlcGroup.v[1] = myGID; /* init list to include me */ + if ((x > 0) && (bord[x - 1][y] == him) && + (gList[gMap[groupIDs[x - 1][y]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x - 1, y, me, him); + } + if ((x < maxPoint) && (bord[x + 1][y] == him) && + (gList[gMap[groupIDs[x + 1][y]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x + 1, y, me, him); + } + if ((y > 0) && (bord[x][y - 1] == him) && + (gList[gMap[groupIDs[x][y - 1]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x, y - 1, me, him); + } + if ((y < maxPoint) && (bord[x][y + 1] == him) && + (gList[gMap[groupIDs[x][y + 1]]].libC == 1)) + { + killFlag = TRUE; + killGroup(x, y + 1, me, him); + } + /* list groups adjacent to me */ + if ((x > 0) && (bord[x - 1][y] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x - 1][y]]; + } + if ((x < maxPoint) && (bord[x + 1][y] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x + 1][y]]; + } + if ((y > 0) && (bord[x][y - 1] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y - 1]]; + } + if ((y < maxPoint) && (bord[x][y + 1] == him)) + { + nlcGroup.indx = nlcGroup.indx + 1; + nlcGroup.v[nlcGroup.indx] = gMap[groupIDs[x][y + 1]]; + } + /* fix liberty count for affected groups */ + grpMark = grpMark + 1; + for (i = 1; i <= nlcGroup.indx; i++) + if (gList[nlcGroup.v[i]].groupMark != grpMark) + { + if (gList[nlcGroup.v[i]].atLevel != tryLevel) + { + playMark = playMark + 1; + playStack[playMark].kind = chLib; + playStack[playMark].gID = nlcGroup.v[i]; + playStack[playMark].uval.chLib.oldLevel = + gList[nlcGroup.v[i]].atLevel; + playStack[playMark].uval.chLib.oldLC = + gList[nlcGroup.v[i]].libC; + } + gList[nlcGroup.v[i]].groupMark = grpMark; + gList[nlcGroup.v[i]].atLevel = tryLevel; + spanGroup(gList[nlcGroup.v[i]].lx, gList[nlcGroup.v[i]].ly, &pPlist); + gList[nlcGroup.v[i]].libC = pPlist.indx; + } +} /* plei */ + +saveState() +{ /* saveState */ + playMark = 0; + tryLevel = 0; + newGID = maxGroupID; +} /* saveState */ + +/* + undoes a move sequence back to uMark +*/ +undoTo(uMark) +short uMark; +{ /* undoTo */ + short i, xl, yl; +#ifdef DEBUG + printf( "undoTo\n" ); +#endif + for (i = playMark; i >= uMark + 1; i--) + if (playStack[i].kind == rem) + { + xl = playStack[i].uval.rem.xl; + yl = playStack[i].uval.rem.yl; + bord[xl][yl] = playStack[i].uval.rem.who; + groupIDs[xl][yl] = playStack[i].gID; + if (showTrees) + sstone(playStack[i].uval.rem.who, xl, yl, + playStack[i].uval.rem.sNumber); + } + else if (playStack[i].kind == add) + { + xl = playStack[i].uval.add.xl; + yl = playStack[i].uval.add.yl; + bord[xl][yl] = 0; + groupIDs[xl][yl] = 0; + tryLevel = tryLevel - 1; + newGID = playStack[i].uval.add.nextGID; + if (showTrees) + rstone(xl, yl); + } + else if (playStack[i].kind == reMap) + gMap[playStack[i].gID] = playStack[i].uval.reMap.oldGID; + else /* change libs of group - gID is pre-mapped */ + { + gList[playStack[i].gID].libC = playStack[i].uval.chLib.oldLC; + gList[playStack[i].gID].atLevel = playStack[i].uval.chLib.oldLevel; + } + playMark = uMark; +} /* undoTo */ + +/* + restores the state of the world after trying a move sequence +*/ +restoreState() +{ /* restoreState */ +#ifdef DEBUG + printf( "restoreState\n" ); +#endif + if (playMark > 0) + { + undoTo(0); + playMark = 0; + tryLevel = 0; + } +} /* restoreState */ + +/* exception bpt; */ + + +/* + returns true if (the group (at gx, gy) is saveable. + if so, returns the point to play at in savex, savey +*/ +short saveable(gx, gy, savex, savey) +short gx, gy, *savex, *savey; +{ /* saveable */ + short me, him, gx1, gx2, i, j, smark, mark2, tl, result; + char sChar; + sPointList dList; + point tp; + short libList[maxSPoint+1]; +#ifdef DEBUG + printf( "saveable\n" ); +#endif + dbStop = TRUE; + me = bord[gx][gy]; + him = -me; + if (me == 1) + sChar = '|'; + else + sChar = '>'; +/* write(sChar); */ + spanGroup(gx, gy, &plist3); /* find my liberties */ + if (adjInAtari) /* one of my options is to kill */ + { + listAdjacents(gx, gy, &aList); + for (i = 1; i <= aList.indx; i++) + if (gList[aList.v[i]].libC == 1) + { + spanGroup(gList[aList.v[i]].lx, gList[aList.v[i]].ly, + &pList1); /* find it's liberty */ + plist3.indx = plist3.indx + 1; + plist3.p[plist3.indx].px = pList1.p[1].px; + plist3.p[plist3.indx].py = pList1.p[1].py; + } + } + for (i = 1; i <= maxSPoint; i++) + libList[i] = -1; + if ((utilPlayLevel > 4) && + (gList[gMap[groupIDs[gx][gy]]].libC > 1)) /* account for diags */ + { + listDiags(gx, gy, &dList); + j = 0; + i = plist3.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 100; + plist3.p[i].px = dList.p[j].px; + plist3.p[i].py = dList.p[j].py; + } + plist3.indx = i; + } + if (plist3.indx > 1) /* sort by decreasing lib count */ + { + for (i = 1; i <= plist3.indx; i++) + if (libList[i] != 100) + { + mark2 = playMark; + tryPlay(plist3.p[i].px, plist3.p[i].py, me); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + if (libList[i] > treeLibLim) /* i'm safe */ + { + *savex = plist3.p[i].px; + *savey = plist3.p[i].py; + result = TRUE; + goto one; + } + undoTo(mark2); + } + for (i = 1; i <= plist3.indx - 1; i++) + for (j = i + 1; j <= plist3.indx; j++) + if (libList[i] < libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = plist3.p[i]; + plist3.p[i] = plist3.p[j]; + plist3.p[j] = tp; + } + } + for (i = 1; i <= plist3.indx; i++) + { + *savex = plist3.p[i].px; + *savey = plist3.p[i].py; + if (legal[*savex][*savey]) + { + smark = playMark; + tryPlay(*savex, *savey, me); + pause(); + if (gList[gMap[groupIDs[*savex][*savey]]].libC > 1) + if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) + { + restoreState(); +/* sClearChar(sChar, rXor); */ + return TRUE; + } + else if (gList[gMap[groupIDs[gx][gy]]].libC > 1) + if (! killable(gx, gy, &gx1, &gx2)) + { + restoreState(); +/* sClearChar(sChar, rXor); */ + return TRUE; + } + undoTo(smark); + } + } + result = FALSE; +one: + restoreState(); +/* sClearChar(sChar, rXor); */ + return result; +} /* saveable */ + +/* + marks unsavable groups as dead +*/ +markDead() +{ /* markDead */ + short i, j, gx, gy, result; +#ifdef DEBUG + printf( "markDead\n" ); +#endif + for (i = 1; i <= maxGroupID; i++) + if (killable(gList[i].lx, gList[i].ly, &gx, &gy)) + result = ! saveable(gList[i].lx, gList[i].ly, &gx, &gy); + else + result = FALSE; + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if (bord[i][j] == 0) + ndbord[i][j] = 0; + else if (gList[groupIDs[i][j]].isDead) + ndbord[i][j] = 0; + else + ndbord[i][j] = bord[i][j]; +} /* markDead */ + +/* + marks groups with two eyes as live +*/ +MLspan(x, y, saw1, sawm1, size, sMark) +short x, y, *saw1, *sawm1, *size, sMark; + { /* span */ + if (ndbord[x][y] == 1) + *saw1 = TRUE; + else if (ndbord[x][y] == -1) + *sawm1 = TRUE; + else if (sGroups[x][y] == 0) + { + sGroups[x][y] = sMark; + *size = *size + 1; + if (x > 0) + MLspan(x - 1, y, saw1, sawm1, size, sMark); + if (x < maxPoint) + MLspan(x + 1, y, saw1, sawm1, size, sMark); + if (y > 0) + MLspan(x, y - 1, saw1, sawm1, size, sMark); + if (y < maxPoint) + MLspan(x, y + 1, saw1, sawm1, size, sMark); + } + } /* span */ + +short CLspan(x, y, numEyes, who) +short x, y, *numEyes, who; + { /* span */ + markBoard[x][y] = marker; + if (ndbord[x][y] == 0) + { + if ((sList[sGroups[x][y]].sm != marker) && + (sList[sGroups[x][y]].w == who)) + { + sList[sGroups[x][y]].sm = marker; + if (sList[sGroups[x][y]].s > 6) + return TRUE; + *numEyes = *numEyes + 1; + if (*numEyes > 1) + return TRUE; + } + } + else if (bord[x][y] == who) + { + if ((x > 0) && + (markBoard[x - 1][y] != marker)) + if (CLspan(x - 1, y, numEyes, who)) return TRUE; + if ((x < maxPoint) && + (markBoard[x + 1][y] != marker)) + if (CLspan(x + 1, y, numEyes, who)) return TRUE; + if ((y > 0) && + (markBoard[x][y - 1] != marker)) + if (CLspan(x, y - 1, numEyes, who)) return TRUE; + if ((y < maxPoint) && + (markBoard[x][y + 1] != marker)) + if (CLspan(x, y + 1, numEyes, who)) return TRUE; + } + return FALSE; + } /* span */ + +short checkLive(x, y) +short x, y; + { /* checkLive */ + short numEyes, who; +#ifdef DEBUG + printf( "checkLive\n" ); +#endif + numEyes = 0; + who = bord[x][y]; + marker = marker + 1; + return CLspan(x, y, &numEyes, who); + } /* checkLive */ + +markLive() +{ /* markLive */ + short i, j, size, sMark = 0; + short saw1, sawm1; +#ifdef DEBUG + printf( "markLive\n" ); +#endif + initArray(sGroups); + for (i = 0; i <= maxPoint; i++) + for (j = 0; j <= maxPoint; j++) + if ((sGroups[i][j] == 0) && + (ndbord[i][j] == 0)) + { + size = 0; + sMark = sMark + 1; + sawm1 = FALSE; + saw1 = FALSE; + MLspan(i, j, &saw1, &sawm1, &size, sMark); + sList[sMark].s = size; + sList[sMark].sm = 0; + if (sawm1) + if (saw1) + sList[sMark].w = 0; + else + sList[sMark].w = -1; + else if (saw1) + sList[sMark].w = 1; + else + sList[sMark].w = 0; + } + for (i = 1; i <= maxGroupID; i++) + if (! gList[i].isDead) + gList[i].isLive = checkLive(gList[i].lx, gList[i].ly); +} /* markLive */ + +/* + generates the connection map and the protected point map. +*/ +genConnects() +{ /* genConnects */ + short x, y, numStones; +#ifdef DEBUG + printf( "genConnects\n" ); +#endif + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + { + connectMap[x][y] = 0; + protPoints[x][y] = 0; + } + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + if (bord[x][y] == 1) /* map connections to this stone */ + { + if (x > 0) /* direct connection */ + connectMap[x - 1][y] += 1; + if (x < maxPoint) + connectMap[x + 1][y] += 1; + if (y > 0) + connectMap[x][y - 1] += 1; + if (y < maxPoint) + connectMap[x][y + 1] += 1; + if ((x > 0) && (y > 0) && /* diagonal connection */ + (bord[x - 1][y] == 0) && (bord[x][y - 1] == 0)) + connectMap[x - 1][y - 1] += 1; + if ((x < maxPoint) && (y > 0) && + (bord[x + 1][y] == 0) && (bord[x][y - 1] == 0)) + connectMap[x + 1][y - 1] += 1; + if ((x < maxPoint) && (y < maxPoint) && + (bord[x + 1][y] == 0) && (bord[x][y + 1] == 0)) + connectMap[x + 1][y + 1] += 1; + if ((x > 0) && (y < maxPoint) && + (bord[x - 1][y] == 0) && (bord[x][y + 1] == 0)) + connectMap[x - 1][y + 1] += 1; + if ((x > 1) && (claim[x - 1][y] > 3)) /* one point jump */ + connectMap[x - 2][y] += 1; + if ((x < (maxPoint - 1)) && (claim[x + 1][y] > 3)) + connectMap[x + 2][y] += 1; + if ((y > 1) && (claim[x][y - 1] > 3)) + connectMap[x][y - 2] += 1; + if ((y < (maxPoint - 1)) && (claim[x][y + 1] > 3)) + connectMap[x][y + 2] += 1; + if ((x > 1) && (y > 0) && /* knight's move */ + (claim[x - 1][y] > 3) && (claim[x - 1][y - 1] > 3)) + connectMap[x - 2][y - 1] += 1; + if ((x > 0) && (y > 1) && + (claim[x][y - 1] > 3) && (claim[x - 1][y - 1] > 3)) + connectMap[x - 1][y - 2] += 1; + if ((x < (maxPoint - 1)) && (y > 0) && + (claim[x + 1][y] > 3) && (claim[x + 1][y - 1] > 3)) + connectMap[x + 2][y - 1] += 1; + if ((x < maxPoint) && (y > 1) && + (claim[x][y - 1] > 3) && (claim[x + 1][y - 1] > 3)) + connectMap[x + 1][y - 2] += 1; + if ((x > 1) && (y < maxPoint) && + (claim[x - 1][y] > 3) && (claim[x - 1][y + 1] > 3)) + connectMap[x - 2][y + 1] += 1; + if ((x > 0) && (y < (maxPoint - 1)) && + (claim[x][y + 1] > 3) && (claim[x - 1][y + 1] > 3)) + connectMap[x - 1][y + 2] += 1; + if ((x < (maxPoint - 1)) && (y < maxPoint) && + (claim[x + 1][y] > 3) && (claim[x + 1][y + 1] > 3)) + connectMap[x + 2][y + 1] += 1; + if ((x < maxPoint) && (y < (maxPoint - 1)) && + (claim[x][y + 1] > 3) && (claim[x + 1][y + 1] > 3)) + connectMap[x + 1][y + 2] += 1; + } + else if (bord[x][y] == 0) /* see if protected point */ + { + numStones = 0; + if (x == 0) + numStones = numStones + 1; + if (y == 0) + numStones = numStones + 1; + if (x == maxPoint) + numStones = numStones + 1; + if (y == maxPoint) + numStones = numStones + 1; + if ((x > 0) && (bord[x - 1][y] == 1)) + numStones = numStones + 1; + if ((y > 0) && (bord[x][y - 1] == 1)) + numStones = numStones + 1; + if ((x < maxPoint) && (bord[x + 1][y] == 1)) + numStones = numStones + 1; + if ((y < maxPoint) && (bord[x][y + 1] == 1)) + numStones = numStones + 1; + if (numStones == 4) + protPoints[x][y] = 1; + else if (numStones == 3) + { + if ((x > 0) && + ((bord[x - 1][y] == 0) || + ((bord[x - 1][y] == -1) && + (gList[groupIDs[x - 1][y]].libC == 1)))) + protPoints[x][y] = 1; + else if ((x < maxPoint) && + ((bord[x + 1][y] == 0) || + ((bord[x + 1][y] == -1) && + (gList[groupIDs[x + 1][y]].libC == 1)))) + protPoints[x][y] = 1; + else if ((y > 0) && + ((bord[x][y - 1] == 0) || + ((bord[x][y - 1] == -1) && + (gList[groupIDs[x][y - 1]].libC == 1)))) + protPoints[x][y] = 1; + else if ((y < maxPoint) && + ((bord[x][y + 1] == 0) || + ((bord[x][y + 1] == -1) && + (gList[groupIDs[x][y + 1]].libC == 1)))) + protPoints[x][y] = 1; + } + } + for (x = 0; x <= maxPoint; x++) + for (y = 0; y <= maxPoint; y++) + if (bord[x][y] != 0) + { + connectMap[x][y] = 0; + protPoints[x][y] = 0; + } +} /* genConnects */ + +/* + generates the whole state of the game. +*/ +genState() +{ /* genState */ +#ifdef DEBUG + printf( "genState\n" ); +#endif + inGenState = TRUE; + respreicen(); + markDead(); + markLive(); + spread(); + genConnects(); +#ifdef DEBUG +/* printBoard( claim, "claim" ); */ +/* printBoard( bord, "bord" ); */ +/* printBoard( ndbord, "ndbord" ); + printBoard( sGroups, "sGroups" ); + printBoard( groupIDs, "groupIDs" ); + printBoard( connectMap, "connectMap" ); + printBoard( protPoints, "protPoints" ); */ +#endif + inGenState = FALSE; +} /* genState */ + +/* + generates a value for the [x, y] location that appears to get larger + for points that are saddle points in the influence graph (klein) +*/ +short tencen(x, y) +short x, y; +{ /* tencen */ + short a, b, c, d, w, z; +#ifdef DEBUG + printf( "tencen\n" ); +#endif + if (claim[x][y] > -1) /* if (he does not influence this area, return 50 */ + { + return 50; + } + w = claim[x][y]; /* w <= -1 */ + a = iNil; + if (x > 0) + if (claim[x - 1][y] > -1) /* if (neighbor is not influenced by him */ + a = claim[x - 1][y] - w; /* score is sum of his influence on central */ + b = iNil; /* point and my influence on this neighbor */ + if (y > 0) + if (claim[x][y - 1] > -1) + b = claim[x][y - 1] - w; + c = iNil; + if (x < maxPoint) + if (claim[x + 1][y] > -1) + c = claim[x + 1][y] - w; + d = iNil; + if (y < maxPoint) + if (claim[x][y + 1] > -1) + d = claim[x][y + 1] - w; + z = a; /* z = max(a, b, c, d) */ + if (z != iNil) + { + if ((b != iNil) && + (b > z)) + z = b; + } + else + z = b; + if (z != iNil) + { + if ((c != iNil) && + (c > z)) + z = c; + } + else + z = c; + if (z != iNil) + { + if ((d != iNil) && + (d > z)) + z = d; + } + else + z = d; + if ((z != iNil) && + ((x == 0) || + (y == 0) || + (x == maxPoint) || + (y == maxPoint))) + z = z * 2; /* double z if (on the edge of the board ?? */ + if (z != iNil) + return z; + else + return 50; +} /* tencen */ + +initGPUtils() +{ /* initGPUtils */ +#ifdef DEBUG + printf( "initGPUtils\n" ); +#endif + initArray(markBoard); + initState(); + marker = 0; + playMark = 0; + gList[0].isLive = FALSE; + gList[0].isDead = FALSE; + gList[0].libC = 0; + gList[0].size = 0; + gList[0].numEyes = 0; + gList[0].lx = -1; + gList[0].ly = -1; + gMap[0] = 0; + dbStop = FALSE; + inGenState = FALSE; +} /* initGPUtils */ + diff --git a/noncore/games/go/goplayutils.h b/noncore/games/go/goplayutils.h new file mode 100644 index 0000000..11ab658 --- a/dev/null +++ b/noncore/games/go/goplayutils.h @@ -0,0 +1,85 @@ +/********************************************************************** +** 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 __goplayutils_h +#define __goplayutils_h + +#define iNil 32767 /* a distinguished value like nil */ +#define maxGroup 512 +#define maxSPoint 16 +#define tryLimit 300 + +typedef short intBoard[19][19]; /* these were -2 to maxPoint + 2 */ + +typedef short boolBoard[19][19]; + +typedef struct +{ + short px, py; +} point; + +typedef struct +{ + point p[401]; + short indx; +} pointList; + +typedef struct +{ + point p[maxSPoint+1]; + short indx; +} sPointList; + +typedef struct +{ + short indx, + v[401]; +} intList; + +typedef struct { short w, s, sm; } sgRec; + +typedef struct +{ + short groupMark, + atLevel, + isLive, + isDead, + libC, + numEyes, + size, + lx, ly; +} groupRec; + +typedef enum {rem, add, chLib, reMap} playType; + +typedef struct { short who, xl, yl, nextGID, sNumber; } remAddRec; +typedef struct { short oldLC, oldLevel; } chLibRec; +typedef struct { short oldGID; } reMapRec; +typedef struct +{ + short gID; + playType kind; + union { + remAddRec rem, add; + chLibRec chLib; + reMapRec reMap; + } uval; +} playRec; + +#endif diff --git a/noncore/games/go/gowidget.cpp b/noncore/games/go/gowidget.cpp new file mode 100644 index 0000000..fca9797 --- a/dev/null +++ b/noncore/games/go/gowidget.cpp @@ -0,0 +1,449 @@ +/********************************************************************** +** 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 "gowidget.h" + +#include <qpe/config.h> +#include <qpe/resource.h> + +#include <qpainter.h> +#include <qpixmap.h> +#include <qpe/qpetoolbar.h> +#include <qpe/qpemenubar.h> +#include <qpopupmenu.h> +#include <qaction.h> +#include <qapplication.h> //processEvents() +#include <qlabel.h> + +//#include <stdio.h> + +#include "amigo.h" +#include "goplayutils.h" + +static const enum bVal computer_color = BLACK; + +static int current_handicap = 1; + +static QBrush *goBrush; +//static QImage *newBlackStone; +//static QImage *blackStone; +//static QImage *whiteStone; +static QPixmap *newBlackStone; +static QPixmap *blackStone; +static QPixmap *whiteStone; + +GoMainWidget::GoMainWidget( QWidget *parent, const char* name) : + QMainWindow( parent, name ) +{ + setToolBarsMovable( FALSE ); + GoWidget *go = new GoWidget(this); + + setCentralWidget(go); + toolbar = new QPEToolBar(this); + toolbar->setHorizontalStretchable( TRUE ); + addToolBar(toolbar); + + QPEMenuBar *mb = new QPEMenuBar( toolbar ); + mb->setMargin(0); + QPopupMenu *file = new QPopupMenu( this ); + + QAction *a = new QAction( tr( "New Game" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( newGame() ) ); + a->addTo( file ); + + a = new QAction( tr( "Pass" ), Resource::loadPixmap( "pass" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( pass() ) ); + a->addTo( file ); + a->addTo( toolbar ); + + + a = new QAction( tr( "Resign" ), Resource::loadPixmap( "reset" ), QString::null, 0, this, 0 ); + connect( a, SIGNAL( activated() ), go, SLOT( resign() ) ); + a->addTo( file ); + + a = new QAction( tr( "Two player option" ), QString::null, 0, this, 0 ); + a->setToggleAction( TRUE ); + connect( a, SIGNAL( toggled(bool) ), go, SLOT( setTwoplayer(bool) ) ); + a->addTo( file ); + + mb->insertItem( tr( "Game" ), file ); + + QLabel *turnLabel = new QLabel( toolbar ); + turnLabel->setBackgroundMode( PaletteButton ); + connect( go, SIGNAL(showTurn(const QPixmap&)), + turnLabel, SLOT(setPixmap(const QPixmap&)) ); + + + QLabel * scoreLabel = new QLabel( toolbar ); + scoreLabel->setBackgroundMode( PaletteButton ); + connect( go, SIGNAL(showScore(const QString&)), + scoreLabel, SLOT(setText(const QString&)) ); + + toolbar->setStretchableWidget( scoreLabel ); + + go->readConfig(); +} + +void GoMainWidget::resizeEvent( QResizeEvent * ) +{ + //### this won't work because of the text label... + /* + if ( width() > height() ) + moveToolBar( toolbar, Left ); + else + moveToolBar( toolbar, Top ); + */ +} + +GoWidget *GoWidget::self = 0; + +GoWidget::GoWidget( QWidget *parent, const char* name) : + QWidget( parent, name ) +{ + if ( self ) + fatal( "Only one Go widget allowed" ); + self = this; + twoplayer = FALSE; + + + d = bx = by = 1; + + QPixmap pix = Resource::loadPixmap( "pine" ); + goBrush = new QBrush( black, pix ); + /* + QString fn = Resource::findPixmap("Go-black"); + blackStone = new QImage( fn ); + fn = Resource::findPixmap("Go-black-highlight"); + newBlackStone = new QImage( fn ); + fn = Resource::findPixmap("Go-white"); + whiteStone = new QImage( fn ); + */ + blackStone = new QPixmap(Resource::loadPixmap( "Go-black" )); + whiteStone = new QPixmap(Resource::loadPixmap( "Go-white" )); + newBlackStone = new QPixmap(Resource::loadPixmap( "Go-black-highlight" )); + + init(); +} + +GoWidget::~GoWidget() +{ + writeConfig(); +} + +void GoWidget::writeConfig() +{ + Config cfg("Go"); + cfg.setGroup("Game"); + cfg.writeEntry("TwoPlayer", twoplayer); + cfg.writeEntry("CurrentPlayer", currentPlayer); + cfg.writeEntry("NPassed", nPassed); + QString b; + for (int i=0; i<19; i++) + for (int j=0; j<19; j++) + b += board[i][j] == BLACK ? 'B' : board[i][j] == WHITE ? 'W' : '.'; + cfg.writeEntry("Board", b); + cfg.writeEntry("LastX", lastX); + cfg.writeEntry("LastY", lastY); + extern int blackPrisoners, whitePrisoners; + cfg.writeEntry("BlackPrisoners", blackPrisoners); + cfg.writeEntry("WhitePrisoners", whitePrisoners); +} + +void GoWidget::readConfig() +{ + init(); + Config cfg("Go"); + cfg.setGroup("Game"); + twoplayer = cfg.readBoolEntry("TwoPlayer"); + currentPlayer = (bVal)cfg.readNumEntry("CurrentPlayer",1); + nPassed = cfg.readNumEntry("NPassed",0); + QString b = cfg.readEntry("Board"); + if ( b.length() == 19*19 ) + for (int i=0; i<19; i++) + for (int j=0; j<19; j++) { + QChar ch = b[j+19*i]; + if ( ch != '.' ) + GoPlaceStone( ch == 'B' ? BLACK : WHITE, i, j ); + } + lastX = cfg.readNumEntry("LastX"); + lastY = cfg.readNumEntry("LastY"); + extern int blackPrisoners, whitePrisoners; + blackPrisoners = cfg.readNumEntry("BlackPrisoners",0); + whitePrisoners = cfg.readNumEntry("WhitePrisoners",0); + reportPrisoners(blackPrisoners,whitePrisoners); + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); +} + +void GoWidget::resizeEvent( QResizeEvent * ) +{ + d = QMIN(width(),height())/19; + // int r = (d/2-1); + bx = (width() - 18*d)/2 ; + by = (height() - 18*d)/2 ; +} + +void GoWidget::init() +{ + lastX = lastY = newX = newY = -1; + nPassed = 0; + for ( int i = 0; i < 19; i++ ) + for ( int j = 0; j < 19; j++ ) + board[i][j]=-1; + gameActive = TRUE; + goRestart(current_handicap); + + if ( twoplayer ) { + currentPlayer = BLACK; + } else { + doComputerMove(); + currentPlayer = WHITE; + } + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); +} + +void GoWidget::paintEvent( QPaintEvent *e ) +{ + int i,j; + + int r = whiteStone->width()/2; + + QPainter p(this); + p.fillRect( bx - d/2, by - d/2, 19*d, 19*d, *goBrush ); + + int xMin = QMAX( x2board(e->rect().left()), 0 ); + int xMax = QMIN( x2board(e->rect().right()), 18 ); + int yMin = QMAX( y2board(e->rect().top()), 0 ); + int yMax = QMIN( y2board(e->rect().bottom()), 18 ); + + QColor pine( 255, 186, 89 ); + p.setPen( pine.dark() ); + + for ( i = xMin; i < xMax+1 ; i ++ ) { + p.drawLine( bx+i*d, by, bx+i*d, by+18*d ); + } + for ( j = yMin; j < yMax+1 ; j ++ ) { + p.drawLine( bx, by+j*d, bx+18*d, by+j*d); + } + + // dots are at (3,3), (3,9), (3,15) and so on + p.setBrush( black ); + for ( i = 3; i < xMax+1; i+=6 ) + for ( j = 3; j < yMax+1; j+=6 ) + p.drawEllipse( bx+i*d-2, by+j*d-2, 5, 5 ); + + + for ( i = xMin; i < xMax+1; i++ ) + for ( j = yMin; j < yMax+1; j++ ) { + if ( board[i][j] == WHITE || + currentPlayer==WHITE && newX == i && newY == j ) + p.drawPixmap( bx+i*d - r, by+j*d - r, *whiteStone ); + else if ( i == lastX && j == lastY ) + p.drawPixmap( bx+i*d - r, by+j*d - r, *newBlackStone ); + else if ( board[i][j] == BLACK || + currentPlayer==BLACK && newX == i && newY == j) + p.drawPixmap( bx+i*d - r, by+j*d - r, *blackStone ); + } +} + +void GoWidget::doMove( int x, int y ) +{ + + if ( !GoPlaceStone( currentPlayer, x, y ) ) { + //printf( "Illegal move (%d,%d)\n", x, y ); + return; + } + //printf( "you do (%d,%d)\n", x, y ); + nPassed = 0; + if ( twoplayer ) + currentPlayer = (currentPlayer==WHITE) ? BLACK : WHITE; + else + doComputerMove(); + + emit showTurn( currentPlayer == WHITE ? *whiteStone : *blackStone ); + +} + +void GoWidget::pass() +{ + if ( !gameActive ) + return; + nPassed++; + if ( nPassed >= 2 ) + endGame(); + else if ( !twoplayer ) + doComputerMove(); +} + +void GoWidget::resign() +{ + if ( gameActive ) + endGame(); +} + + +void GoWidget::newGame() +{ + init(); + update(); +} + + +void GoWidget::endGame() +{ + gameActive = FALSE; + + int w,b; + CountUp( &w, &b); + QString s = tr("White %1, Black %2. ").arg(w).arg(b); + if ( w > b ) + s += tr("White wins."); + else if ( w < b ) + s += tr("Black wins."); + else + s += tr("A draw."); + emit showScore( s ); +} + +void GoWidget::doComputerMove() +{ + int ox = lastX; + int oy = lastY; + lastX = lastY = -1; + emit showTurn( *blackStone ); + refresh( ox, oy); + qApp->processEvents(); + short int x,y; + if ( genMove( computer_color, &x, &y ) ) { + lastX = x; + lastY = y; + //printf( "I do (%d,%d)\n", x, y ); + GoPlaceStone(computer_color,x,y); + nPassed = 0; + } else { + emit showScore( tr("I pass") ); + nPassed++; + if ( nPassed >= 2 ) + endGame(); + } +} + +void GoWidget::mousePressEvent( QMouseEvent *me ) +{ + if ( !gameActive ) + return; + int x = x2board(me->x()); + int y = y2board(me->y()); + showStone(x,y,currentPlayer); +} + +void GoWidget::mouseMoveEvent( QMouseEvent *me ) +{ + if ( !gameActive ) + return; + int x = x2board(me->x()); + int y = y2board(me->y()); + if ( x != newX || y != newY ) + showStone(x,y,currentPlayer); +} + +void GoWidget::showStone( int x, int y, enum bVal c ) +{ + + if ( newX > -1 ) { + refresh( newX, newY ); + newY = newX = -1; + } + if ( x < 0 || x > 18 || y < 0 || y > 18 ) { + newX = newY = -1; + return; + } + if ( board[x][y] == -1 && !Suicide( c, x, y ) ) { + newX = x; + newY = y; + refresh(x,y); + } + +} + +void GoWidget::mouseReleaseEvent( QMouseEvent * ) +{ + if ( gameActive && newX > -1 ) + doMove( newX, newY ); + newX = newY = -1; +} + +void GoWidget::refresh( int x, int y ) +{ + update( bx+d*x-d/2-1, by+d*y-d/2-1, d+2, d+2 ); +} + +void GoWidget::removeStone(short x, short y) +{ + board[x][y]=-1; + refresh( x, y ); +} + +void GoWidget::placeStone (enum bVal c, short x, short y ) +{ + board[x][y]=c; + refresh( x, y ); +} + +void GoWidget::reportPrisoners( int blackcnt, int whitecnt ) +{ + QString s = tr( "Prisoners: black %1, white %2" ).arg(blackcnt).arg(whitecnt); + emit showScore( s ); +} + +void GoWidget::setTwoplayer( bool b ) +{ + twoplayer = b; +} + +void GoWidget::setHandicap( int h ) +{ + current_handicap = h; +} + + +extern "C" { + +void removestone(short x, short y) +{ + GoWidget::self->removeStone(x,y); +} + +void placestone (enum bVal c, short x, short y ) +{ + GoWidget::self->placeStone(c,x,y); +} + +void intrMoveReport(enum bVal c ,char *coord ,char *reason ) +{ + qDebug( "intrMoveReport colour %d, %s %s", c, coord, reason ); +} + +void intrPrisonerReport( short blackcnt, short whitecnt ) +{ + GoWidget::self->reportPrisoners(blackcnt,whitecnt); +} + +} + diff --git a/noncore/games/go/gowidget.h b/noncore/games/go/gowidget.h new file mode 100644 index 0000000..94de2cc --- a/dev/null +++ b/noncore/games/go/gowidget.h @@ -0,0 +1,111 @@ +/********************************************************************** +** 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 GOWIDGET_H +#define GOWIDGET_H + +#include <qmainwindow.h> +#include "amigo.h" + + +class QToolBar; + +class GoMainWidget : public QMainWindow +{ + Q_OBJECT +public: + GoMainWidget( QWidget *parent=0, const char* name=0); +protected: + void resizeEvent( QResizeEvent * ); +private: + QToolBar *toolbar; + +}; + + +class QLabel; +class GoWidget : public QWidget +{ + Q_OBJECT +public: + GoWidget( QWidget *parent=0, const char* name=0); + ~GoWidget(); + + void doMove( int x, int y ); + void doComputerMove(); + + void readConfig(); + void writeConfig(); + +public slots: + void pass(); + void resign(); + void newGame(); + void setTwoplayer( bool ); + void setHandicap( int ); +signals: + void showScore( const QString& ); + void showTurn( const QPixmap& ); + +protected: + void paintEvent( QPaintEvent * ); + void mousePressEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + void resizeEvent( QResizeEvent * ); +private: + void init(); + void removeStone(short x, short y); + void placeStone (enum bVal c, short x, short y ); + + void refresh( int x, int y ); + void showStone( int x, int y, enum bVal ); + void reportPrisoners(int,int); + + inline int x2board( int x ) { return (x-bx+d/2)/d; } + inline int y2board( int y ) { return (y-by+d/2)/d; } + + void endGame(); + + bool twoplayer; + enum bVal currentPlayer; + bool gameActive; + int nPassed; + signed char board[19][19]; + + int d; //distance between lines + int bx; //vertical baseline + int by; //horizontal baseline + + int lastX,lastY; + int newX,newY; + + static GoWidget *self; + + friend void removestone(short x, short y); + friend void intrPrisonerReport( short, short ); + friend void placestone(enum bVal c, short x, short y ); +}; + + + + + +#endif diff --git a/noncore/games/go/killable.c b/noncore/games/go/killable.c new file mode 100644 index 0000000..3ed2d2e --- a/dev/null +++ b/noncore/games/go/killable.c @@ -0,0 +1,373 @@ +/* By Stoney Ballard */ +/* Ported from Pascal to C by Todd R. Johnson */ + +#include "go.h" +#include "goplayutils.h" +#include "amigo.h" + +extern intBoard bord, groupIDs; +extern boolBoard legal; +extern groupRec gList[maxGroup]; +extern short gMap[maxGroup], adjInAtari, adj2Libs, playMark, treeLibLim, + utilPlayLevel, killFlag, depthLimit, dbStop, showTrees; +extern pointList plist2; + +/* + returns true if the group (at x, y) is killable. + if so, returns the point to play at in killx, killy. +*/ + + short me, him, depth, i, j, tryCount, tl, topMark, tkMark, mark2; + char sChar; + sPointList lList, dList; + point tp; + short libList[maxSPoint+1]; + short esc; + +short mtNbrs(x, y) +short x, y; + { /* mtNbrs */ + short n = 0; + if ((x > 0) && (bord[x - 1][y] == 0)) + n = n + 1; + if ((x < maxPoint) && (bord[x + 1][y] == 0)) + n = n + 1; + if ((y > 0) && (bord[x][y - 1] == 0)) + n = n + 1; + if ((y < maxPoint) && (bord[x][y + 1] == 0)) + n = n + 1; + return n; + } /* mtNbrs */ + +short killTree(tx, ty, gx, gy, escape, tkMark) +short tx, ty, gx, gy, *escape, tkMark; + { /* killTree */ + short curMark, mark2, mark3, i, j, k, tl, dStart, result; + sPointList lList1, lList2; + short libList[maxSPoint+1]; + point tp; + short esc = FALSE; + tryCount = tryCount + 1; + if (tryCount > tryLimit) + { + undoTo(tkMark); +/* for (i = 1; i <= depth - 1; i++) + { + sClearChar(sChar, rXor); + } */ + depth = 1; + return FALSE; + } +/* write(sChar); */ + depth = depth + 1; + curMark = playMark; + tryPlay(tx, ty, me); /* try my move */ + pause(); + if (gList[gMap[groupIDs[tx][ty]]].libC == 0) /* I'm dead */ + { + result = FALSE; + goto one; + } + else if (killFlag) /* I killed something of his */ + { + result = TRUE; + goto one; + } + else if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) /* safe */ + { + result = FALSE; + goto one; + } + else + { + sSpanGroup(gx, gy, &lList1); /* find his liberties */ + if (gList[gMap[groupIDs[tx][ty]]].libC == 1) /* he can kill me */ + { + if (lList1.indx < maxSPoint) /* add that option to his list */ + { + lList1.indx = lList1.indx + 1; + spanGroup(tx, ty, &plist2); /* find my liberty */ + lList1.p[lList1.indx].px = plist2.p[1].px; + lList1.p[lList1.indx].py = plist2.p[1].py; + } + else + { + result = FALSE; + goto one; + } + } + for (i = 1; i <= maxSPoint; i++) /* init liblist so diags can be marked */ + libList[i] = -1; + if ((utilPlayLevel > 4) && + (lList1.indx > 1) && + (gList[gMap[groupIDs[gx][gy]]].libC > 1)) /* try diags */ + { + listDiags(gx, gy, &dList); + j = 0; + i = lList1.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 0; /* mark this as a diag */ + lList1.p[i].px = dList.p[j].px; + lList1.p[i].py = dList.p[j].py; + } + lList1.indx = i; + } + if (lList1.indx > 1) /* sort by decreasing lib count */ + { + for (i = 1; i <= lList1.indx; i++) + if (libList[i] != 0) /* diags are tried last */ + { + mark2 = playMark; + tryPlay(lList1.p[i].px, lList1.p[i].py, him); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + if ((libList[i] > treeLibLim) || + ((libList[i] > (depthLimit - depth)) && + (libList[i] > 2))) + { + *escape = TRUE; + result = FALSE; + goto one; + } + undoTo(mark2); + } + for (i = 1; i <= lList1.indx - 1; i++) + for (j = i + 1; j <= lList1.indx; j++) + if (libList[i] < libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList1.p[i]; + lList1.p[i] = lList1.p[j]; + lList1.p[j] = tp; + } + } + for (i = 1; i <= lList1.indx + 1; i++) /* try his responses */ + { + mark2 = playMark; + if (i <= lList1.indx) /* try his move */ + { + tryPlay(lList1.p[i].px, lList1.p[i].py, him); /* play his response */ + pause(); + if (gList[gMap[groupIDs[lList1.p[i].px] + [lList1.p[i].py]]].libC < 2) + goto two; /* a bogus move */ + } + else if (gList[gMap[groupIDs[gx][gy]]].libC <= 1) + { + result = TRUE; + goto one; + } + if (gList[gMap[groupIDs[gx][gy]]].libC > treeLibLim) + { + *escape = TRUE; + result = FALSE; + goto one; + } + if (gList[gMap[groupIDs[gx][gy]]].libC > 1) + { /* look at my responses */ + sSpanGroup(gx, gy, &lList2); /* list his liberties */ + dStart = lList2.indx + 1; + if (adjInAtari) /* he wins */ + { + result = FALSE; + goto one; + } + if ((lList2.indx > 2) && adj2Libs) /* he wins */ + { + result = FALSE; + goto one; + } + for (k = 1; k <= maxSPoint; k++) + libList[k] = -1; + if (utilPlayLevel > 4) /* account for diagonal moves */ + { + listDiags(gx, gy, &dList); + j = 0; + k = lList2.indx; + while ((j < dList.indx) && + (k < maxSPoint)) + { + j = j + 1; + k = k + 1; + libList[k] = 100; + lList2.p[k].px = dList.p[j].px; + lList2.p[k].py = dList.p[j].py; + } + lList2.indx = k; + } + if (lList2.indx > 1) /* sort by increasing lib count */ + { + for (k = 1; k <= lList2.indx; k++) + if (libList[k] != 100) /* diags go last */ + { + mark3 = playMark; + tryPlay(lList2.p[k].px, lList2.p[k].py, me); + libList[k] = gList[gMap[groupIDs[gx][gy]]].libC; + undoTo(mark3); + } + for (k = 1; k <= lList2.indx - 1; k++) + for (j = k + 1; j <= lList2.indx; j++) + if (libList[k] > libList[j]) + { + tl = libList[k]; + libList[k] = libList[j]; + libList[j] = tl; + tp = lList2.p[k]; + lList2.p[k] = lList2.p[j]; + lList2.p[j] = tp; + } + else if ((libList[k] == libList[j]) && + (libList[k] == 1)) + if (mtNbrs(lList2.p[k].px, lList2.p[k].py) < + mtNbrs(lList2.p[j].px, lList2.p[j].py)) + { + tl = libList[k]; + libList[k] = libList[j]; + libList[j] = tl; + tp = lList2.p[k]; + lList2.p[k] = lList2.p[j]; + lList2.p[j] = tp; + } + } + for (j = 1; j <= lList2.indx; j++) + { + if (killTree(lList2.p[j].px, lList2.p[j].py, gx, + gy, &esc, tkMark)) + goto two; /* this kills him */ + if (esc && (j >= dStart)) + { + result = FALSE; + goto one; /* don't bother with more diags if escapes */ + } + } + result = FALSE; /* none of my responses kills him */ + goto one; + } + two: + undoTo(mark2); + } + result = TRUE; /* none of his responses saves him */ + } + one: + undoTo(curMark); +/* sClearChar(sChar, rXor); */ + depth = depth - 1; + return result; + } /* killTree */ + +short tKillTree(tx, ty, gx, gy) +short tx, ty, gx, gy; + { /* tKillTree */ + short tkMark, escape; + tryCount = 0; + tkMark = playMark; + return killTree(tx, ty, gx, gy, &escape, tkMark); + } /* tKillTree */ + +short killable(gx, gy, killx, killy) +short gx, gy, *killx, *killy; +{ /* killable */ +#ifdef DEBUG + printf( "killable\n" ); + showTrees = TRUE; +#endif + dbStop = TRUE; + him = bord[gx][gy]; /* find out who I am */ + me = -him; +/* if (me == 1) + sChar = '>'; + else + sChar = '|'; */ +/* write(sChar); */ + depth = 1; + topMark = playMark; + sSpanGroup(gx, gy, &lList); /* find his liberties */ + if (lList.indx == 1) + { + *killx = lList.p[1].px; + *killy = lList.p[1].py; + return TRUE; + } + else if (lList.indx > treeLibLim) + return FALSE; + else if (adjInAtari) + return FALSE; + else if ((lList.indx > 2) && adj2Libs) + return FALSE; + else + { + for (i = 1; i <= maxSPoint; i++) + libList[i] = -1; + if (utilPlayLevel > 4) /* account for diagonal moves */ + { + listDiags(gx, gy, &dList); + j = 0; + i = lList.indx; + while ((j < dList.indx) && + (i < maxSPoint)) + { + j = j + 1; + i = i + 1; + libList[i] = 100; + lList.p[i].px = dList.p[j].px; + lList.p[i].py = dList.p[j].py; + } + lList.indx = i; + } + if (lList.indx > 1) /* sort by increasing lib count */ + { + for (i = 1; i <= lList.indx; i++) + if (libList[i] != 100) /* diags go last */ + { + mark2 = playMark; + tryPlay(lList.p[i].px, lList.p[i].py, me); + libList[i] = gList[gMap[groupIDs[gx][gy]]].libC; + undoTo(mark2); + } + for (i = 1; i <= lList.indx - 1; i++) + for (j = i + 1; j <= lList.indx; j++) + if (libList[i] > libList[j]) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList.p[i]; + lList.p[i] = lList.p[j]; + lList.p[j] = tp; + } + else if ((libList[i] == libList[j]) && + (libList[i] == 1)) + if (mtNbrs(lList.p[i].px, lList.p[i].py) < + mtNbrs(lList.p[j].px, lList.p[j].py)) + { + tl = libList[i]; + libList[i] = libList[j]; + libList[j] = tl; + tp = lList.p[i]; + lList.p[i] = lList.p[j]; + lList.p[j] = tp; + } + } + for (i = 1; i <= lList.indx; i++) + { + if (legal[lList.p[i].px][lList.p[i].py]) + { + *killx = lList.p[i].px; + *killy = lList.p[i].py; + if (tKillTree(*killx, *killy, gx, gy)) + { +/* sClearChar(sChar, rXor); */ + return TRUE; + } + } + } + return FALSE; + } +/* sClearChar(sChar, rXor); */ +} /* killable */ + diff --git a/noncore/games/go/main.cpp b/noncore/games/go/main.cpp new file mode 100644 index 0000000..c7e2669 --- a/dev/null +++ b/noncore/games/go/main.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** 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 "gowidget.h" + +#include <qpe/qpeapplication.h> + +#include <stdio.h> + +int main( int argc, char ** argv) +{ + QPEApplication app( argc, argv ); + + GoMainWidget m; + m.setCaption( GoWidget::tr("Go") ); + app.showMainWidget( &m ); + return app.exec(); +} diff --git a/noncore/games/go/qpe-go.control b/noncore/games/go/qpe-go.control new file mode 100644 index 0000000..edc106b --- a/dev/null +++ b/noncore/games/go/qpe-go.control @@ -0,0 +1,9 @@ +Files: bin/go apps/Games/go.desktop +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: The game of Go + A game for the Qtopia environment. diff --git a/noncore/games/mindbreaker/.cvsignore b/noncore/games/mindbreaker/.cvsignore new file mode 100644 index 0000000..415ec09 --- a/dev/null +++ b/noncore/games/mindbreaker/.cvsignore @@ -0,0 +1,4 @@ +Makefile +moc_* +helpdialog.cpp +helpdialog.h diff --git a/noncore/games/mindbreaker/Makefile.in b/noncore/games/mindbreaker/Makefile.in new file mode 100644 index 0000000..88f6fb1 --- a/dev/null +++ b/noncore/games/mindbreaker/Makefile.in @@ -0,0 +1,117 @@ +############################################################################# + +####### 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 = mindbreaker +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = mindbreaker.h +SOURCES = main.cpp \ + mindbreaker.cpp +OBJECTS = main.o \ + mindbreaker.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_mindbreaker.cpp +OBJMOC = moc_mindbreaker.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 mindbreaker.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 \ + mindbreaker.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +mindbreaker.o: mindbreaker.cpp \ + mindbreaker.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +moc_mindbreaker.o: moc_mindbreaker.cpp \ + mindbreaker.h + +moc_mindbreaker.cpp: mindbreaker.h + $(MOC) mindbreaker.h -o moc_mindbreaker.cpp + + diff --git a/noncore/games/mindbreaker/main.cpp b/noncore/games/mindbreaker/main.cpp new file mode 100644 index 0000000..8ba0fde --- a/dev/null +++ b/noncore/games/mindbreaker/main.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** 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 "mindbreaker.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char **argv ) +{ + QPEApplication a( argc, argv ); + + MindBreaker w(0, "new window"); + w.setCaption("Mind Breaker"); + QPEApplication::setInputMethodHint( &w, QPEApplication::AlwaysOff ); + a.showMainWidget(&w); + + return a.exec(); +} diff --git a/noncore/games/mindbreaker/mindbreaker.cpp b/noncore/games/mindbreaker/mindbreaker.cpp new file mode 100644 index 0000000..b0e4d88 --- a/dev/null +++ b/noncore/games/mindbreaker/mindbreaker.cpp @@ -0,0 +1,818 @@ +/********************************************************************** +** 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 "mindbreaker.h" + +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qpainter.h> +#include <qpixmap.h> +#include <qpe/qpetoolbar.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qmessagebox.h> +#include <qlabel.h> +#include <qstyle.h> + +#include <stdlib.h> +#include <sys/time.h> +#include <unistd.h> + +static int pegRTTI = 3393393; + +/* helper class, */ +class Peg : public QCanvasRectangle +{ +public: + Peg(QCanvas *canvas, int type, int go = -1, int pos = -1); + int rtti() const {return pegRTTI; } + void advance(int phase); + + bool hit( const QPoint &) const; + +/* a placed peg is one that has been set down on the board correctly and + should not be moved, only copied */ + bool placed() const; + void setPlaced(bool); + + int pegGo() const; + int pegPos() const; + void setPegPos(int); + + int type() const; + + static void buildImages(); + static QImage imageForType(int t); + + static int eggLevel; + +protected: + void drawShape(QPainter &); +private: + static QVector<QImage> normalPegs; + static QVector<QImage> specialPegs; + + bool isplaced; + int pegtype; + int peg_go; + int peg_pos; + + int aniStep; +}; + +int Peg::eggLevel = 0; +QVector<QImage> Peg::normalPegs; +QVector<QImage> Peg::specialPegs; + +void Peg::buildImages() +{ + + QImage pegs = Resource::loadImage("mindbreaker/pegs"); + int x = 0; + int y = 0; + int i; + eggLevel = 0; + normalPegs.resize(10); + for (i = 0; i < 6; i++) { + normalPegs.insert(i, new QImage(pegs.copy(x, y, peg_size, peg_size))); + x += peg_size; + } + specialPegs.resize(5); + for (i = 0; i < 5; i++) { + specialPegs.insert(i, new QImage(pegs.copy(x,y,peg_size, peg_size))); + x += peg_size; + } + + QImage image = Resource::loadImage("mindbreaker/mindbreaker"); + /* copy from master image to functional images */ + x = 0; + y = panel_height; + normalPegs.insert(8, + new QImage(image.copy(x, y, panel_width, panel_height))); + y += panel_height; + y += title_height; + normalPegs.insert(9, + new QImage(image.copy(x, y, title_width, title_height))); + y += title_height; + + x = 6 * peg_size; + normalPegs.insert(6, + new QImage(image.copy(x, y, answerpeg_size, answerpeg_size))); + x += answerpeg_size; + normalPegs.insert(7, + new QImage(image.copy(x, y, answerpeg_size, answerpeg_size))); +} + +QImage Peg::imageForType(int t) +{ + if (eggLevel > t ) { + if( t < 5) { + return *specialPegs[t]; + } else { + return *normalPegs[rand() % 6]; + } + } + return *normalPegs[t]; +} + +Peg::Peg(QCanvas *canvas , int t, int g = -1, int p = -1) + : QCanvasRectangle(canvas) +{ + setSize(normalPegs[t]->width(), normalPegs[t]->height() ); + pegtype = t; + isplaced = FALSE; + peg_pos = p; + peg_go = g; + aniStep = rand() % 6; + setAnimated(TRUE); +} + +void Peg::advance(int phase) { + if (phase == 0) + aniStep = (++aniStep) % 6; + else { + hide(); + show(); + } +} + +void Peg::drawShape(QPainter &p ) +{ + if ((pegtype == 5) && eggLevel > 5) { + p.drawImage(x(), y(), *normalPegs[aniStep]); + } else + p.drawImage(x(), y(), imageForType(pegtype)); +} + +bool Peg::hit( const QPoint &p ) const +{ + int ix = p.x() - int(x()); + int iy = p.y() - int(y()); + if (!normalPegs[pegtype]->valid(ix, iy)) + return FALSE; + QRgb pixel = normalPegs[pegtype]->pixel(ix, iy); + return (qAlpha(pixel ) != 0); +} + +inline bool Peg::placed() const +{ + return isplaced; +} + +inline int Peg::pegGo() const +{ + return peg_go; +} + +inline int Peg::pegPos() const +{ + return peg_pos; +} + +inline void Peg::setPegPos(int p) +{ + peg_pos = p; +} + +inline void Peg::setPlaced(bool p) +{ + isplaced = p; +} + +inline int Peg::type() const +{ + return pegtype; +} + +/* Load the main image, copy from it the pegs, the board, and the answer image + * and use these to create the tray, answer and board + */ +MindBreaker::MindBreaker( QWidget *parent=0, const char *name=0, int wFlags=0 ) +: QMainWindow(parent, name, wFlags), + canvas(board_height, board_width) +{ + MindBreakerBoard *m = new MindBreakerBoard(canvas, this); + setCentralWidget(m); + + setToolBarsMovable( FALSE ); + + QPEToolBar *tb = new QPEToolBar(this); + tb->setHorizontalStretchable( TRUE ); + + QPixmap newicon = Resource::loadPixmap("new"); + new QToolButton(newicon, tr("New Game"), 0, + m, SLOT(clear()), tb, "NewGame"); + + score = new QToolButton(tb); + score->setText(""); + score->setMaximumHeight(20); + score->setUsesTextLabel(TRUE); + tb->setStretchableWidget(score); + + connect(m, SIGNAL(scoreChanged(int, int)), this, SLOT(setScore(int, int))); + connect(score, SIGNAL(clicked()), m, SLOT(resetScore())); + + int a, b; + m->getScore(&a, &b); + setScore(a,b); +} + +void MindBreaker::setScore(int turns, int games) +{ + double average; + double total_turns = turns; + double total_games = games; + + if(total_games > 0) + average = total_turns / total_games; + else + average = 0.0; + + score->setText(tr("win avg: %1 turns (%2 games)").arg(average).arg(games)); +} + + +MindBreakerBoard::MindBreakerBoard( QCanvas &c, QWidget *parent=0, + const char *name=0, int wFlags=0 ) + : QCanvasView(&c, parent, name, wFlags) +{ + int i, x, y; + struct timeval tv; + + current_go = 0; + gettimeofday(&tv, 0); + + srand(tv.tv_usec); + + canvas()->setAdvancePeriod(500); + + QImage image = Resource::loadImage("mindbreaker/mindbreaker"); + + /* copy from master image to functional images */ + x = 0; + y = 0; + panelImage = image.copy(x,y, panel_width, panel_height); + y += panel_height; + y += panel_height; + + titleImage = image.copy(x, y, title_width, title_height); + + Peg::buildImages(); // must be done BEFORE any pegs are made + + current_highlight = new Peg(canvas(), 8); + current_highlight->setPlaced(TRUE); + current_highlight->setX(0); + current_highlight->setY(board_height - ((current_go + 1) * panel_height)); + current_highlight->setZ(0); + current_highlight->show(); + + + /* set up the game */ + Config c("MindBreaker", Config::User); + c.setGroup("Board"); + game_over = FALSE; + if (c.readNumEntry("Answer0") < 0) { + for (i = 0; i < 4; i++) { + answer[i] = rand() % 6; + current_guess[i] = 6; + } + total_turns = 0; + total_games = 0; + } else { + int j; + c.setGroup("Score"); + total_turns = c.readNumEntry("Turns"); + total_games = c.readNumEntry("Games"); + if(total_turns < 0) + total_turns = 0; + if(total_games < 0) + total_games = 0; + + + checkScores(); + c.setGroup("Board"); + for(i = 0; i < 4; i++) + answer[i] = c.readNumEntry(QString("Answer%1").arg(i)); + /* read, and parse past guesses */ + current_go = 0; + for(j=0; j < 9; j++) { + current_guess[0] = c.readNumEntry(QString("Go%1p0").arg(j)); + if (current_guess[0] < 0) + break; + placeGuessPeg(0, current_guess[0]); + current_guess[1] = c.readNumEntry(QString("Go%1p1").arg(j)); + placeGuessPeg(1, current_guess[1]); + current_guess[2] = c.readNumEntry(QString("Go%1p2").arg(j)); + placeGuessPeg(2, current_guess[2]); + current_guess[3] = c.readNumEntry(QString("Go%1p3").arg(j)); + placeGuessPeg(3, current_guess[3]); + checkGuess(); + } + for(i = 0; i < 4; i++) { + current_guess[i] = c.readNumEntry(QString("CurrentGo%1").arg(i)); + if (current_guess[i] != 6) + placeGuessPeg(i, current_guess[i]); + } + } + + /* draw initial screen */ + drawBackground(); + canvas()->update(); +} + +MindBreakerBoard::~MindBreakerBoard() +{ + int i, j; + if (game_over) { + current_go = 0; + /* clear the answer, clear the guess */ + for (i = 0; i < 4; i++) { + answer[i] = rand() % 6; + current_guess[i] = 6; + } + } + + Config c("MindBreaker", Config::User); + c.setGroup("Board"); + c.clearGroup(); + /* write the board */ + for (i = 0; i < current_go; i++) { + for(j = 0; j < 4; j++) + c.writeEntry(tr("Go%1p%2").arg(i).arg(j), past_guesses[4*i+j]); + } + for(j = 0; j < 4; j++) + c.writeEntry(tr("CurrentGo%1").arg(j), current_guess[j]); + for(j = 0; j < 4; j++) + c.writeEntry(tr("Answer%1").arg(j), answer[j]); + + c.setGroup("Score"); + /* write the score */ + + c.writeEntry("Turns", total_turns); + c.writeEntry("Games", total_games); +} + +void MindBreakerBoard::getScore(int *a, int *b) +{ + *a = total_turns; + *b = total_games; + return; +} + +void MindBreakerBoard::placeGuessPeg(int pos, int pegId) +{ + int x = first_peg_x_diff + (pos * peg_spacing); + int y = board_height - ((current_go + 1) * panel_height) + + first_peg_y_diff; + + Peg *peg = new Peg(canvas(), pegId, current_go, pos); + peg->setPegPos(pos); + peg->setPlaced(TRUE); + peg->setX(x); + peg->setY(y); + peg->setZ(2); + peg->show(); +} + +void MindBreakerBoard::drawBackground() +{ + int i, j, x, y, x_gap, y_gap; + QPixmap background = QPixmap(canvas()->width(), canvas()->height()); + + QPainter painter(&background); + + painter.fillRect(0, 0, canvas()->width(), canvas()->height(), QColor(0,0,0)); + /* very first thing is to draw the bins, as everything else needs + * to be drawn over them */ + + QPen pen(QColor(85, 45, 27), 4); + painter.setPen(pen); + x_gap = canvas()->width() - (panel_width + (2 * bin_margin)); + //x_gap += peg_size >> 1; + if (x_gap < 1) + x_gap = 1; + + y_gap = board_height / 6; + y_gap -= (2 * bin_margin); + //y_gap += peg_size >> 1; + if (y_gap < 1) + y_gap = 1; + x = panel_width + bin_margin - (peg_size >> 1); + y = bin_margin - (peg_size >> 1) + 2; + + for (i = 0; i < 6; i++) { + for (j = 0; j < 10; j++) { + int rx = x + (rand() % x_gap); + int ry = y + (rand() % y_gap); + painter.drawImage(rx,ry, Peg::imageForType(i)); + } + y += board_height / 6; + } + /* now draw the surrounding boxes */ + x_gap = canvas()->width() - panel_width; + if (x_gap < 1) x_gap = 1; + y_gap = board_height / 6; + x = panel_width; + y = 1; + + for (i = 0; i < 6; i++) { + painter.drawRect(x, y, x_gap, y_gap); + y += y_gap; + } + + x = 0; + y = 0; + + painter.drawImage(x,y, titleImage); + y = title_height; + /* now nine gues panels */ + for (i = 0; i < 9; i ++) { + painter.drawImage(x, y, panelImage); + y += panel_height; + } + + painter.flush(); + canvas()->setBackgroundPixmap(background); +} + +void MindBreakerBoard::checkGuess() +{ + int i,j; + int num_white = 0; + int num_black = 0; + int copy_answer[4]; + int copy_guess[4]; + + for(i = 0; i < 4; i++) { + copy_answer[i] = answer[i]; + copy_guess[i] = current_guess[i]; + if (current_guess[i] == 6) + return; + if (answer[i] == current_guess[i]) { + num_black++; + copy_answer[i] = 6; + copy_guess[i] = 7; + } + } + + /* now sure that user has completed a 'guess' */ + for (i = 0; i < 4; i++) { + if (copy_guess[i] == 7) + continue; // already marked for a black + for (j = 0; j < 4; j++) { + if(copy_guess[i] == copy_answer[j]) { + copy_answer[j] = 6; + num_white++; + break; + } + } + } + + int x = answerpegx; + int y = (board_height - ((current_go + 1) * panel_height)) + answerpegy; + + if (num_black == 4) + game_over = TRUE; + + while(num_black > 0) { + Peg *p = new Peg(canvas(), 7); + p->setPlaced(TRUE); + p->setX(x); + p->setY(y); + p->setZ(1); + p->show(); + num_black--; + + if (x == answerpegx) + x = answerpegx + answerpeg_diff; + else { + x = answerpegx; + y += answerpeg_diff; + } + } + while(num_white > 0){ + Peg *p = new Peg(canvas(), 6); + p->setPlaced(TRUE); + p->setX(x); + p->setY(y); + p->setZ(1); + p->show(); + num_white--; + + if (x == answerpegx) + x = answerpegx + answerpeg_diff; + else { + x = answerpegx; + y += answerpeg_diff; + } + } + /* move to next go */ + for(i = 0; i < 4; i++) { + past_guesses[4*current_go+i] = current_guess[i]; + current_guess[i] = 6; + } + + current_go++; + if((current_go > 8) || game_over) { + total_games++; + if(!game_over) + total_turns += 10; + else + total_turns += current_go; + + emit scoreChanged(total_turns, total_games); + Peg *p = new Peg(canvas(), 9); + game_over = TRUE; + p->setPlaced(TRUE); + p->setX(0); + p->setY(0); + p->setZ(0); + p->show(); + + for (i = 0; i < 4; i++) { + p = new Peg(canvas(), answer[i], -1); + p->setX(first_peg_x_diff + (i * peg_spacing)); + p->setY(5); + p->setZ(3); + p->show(); + } + } else { + current_highlight->setY(board_height - ((current_go + 1) * panel_height)); + } + canvas()->update(); +} + +void MindBreakerBoard::clear() +{ + if(!game_over) { + total_games++; + total_turns += 10; + emit scoreChanged(total_turns, total_games); + } + int i; + /* reset the game board */ + game_over = FALSE; + /* clear the answer, clear the guess */ + for (i = 0; i < 4; i++) { + answer[i] = rand() % 6; + current_guess[i] = 6; + } + current_go = 0; + + QCanvasItemList list = canvas()->allItems(); + QCanvasItemList::Iterator it = list.begin(); + for (; it != list.end(); ++it) { + if (*it == current_highlight) + continue; + if (*it) + delete *it; + } + + current_highlight->setY(board_height - ((current_go + 1) * panel_height)); + checkScores(); + drawBackground(); + canvas()->update(); +} + +void MindBreakerBoard::resetScore() +{ + /* are u sure */ + + if (QMessageBox::information(this, tr( "Reset Statistics" ), + tr( "Reset the win ratio?" ), + tr( "OK" ), tr( "Cancel" ) ) == 0) { + total_turns = 0; + total_games = 0; + Peg::eggLevel = 0; + drawBackground(); + canvas()->update(); + emit scoreChanged(total_turns, total_games); + } +} + +/* EVENTS */ + +void MindBreakerBoard::contentsMousePressEvent(QMouseEvent *e) +{ + copy_press = FALSE; + null_press = FALSE; + /* ok, first work out if it is one of the bins that + got clicked */ + if (e->x() > panel_width) { + /* its a bin, but which bin */ + if(e->y() > board_height) + return; // missed everything + int bin = (e->y() + 2) / (board_height / 6); + + /* make new peg... set it moving */ + moving_pos = e->pos(); + moving = new Peg(canvas(), bin, current_go); + moving->setX(e->x() - (peg_size >> 1)); + moving->setY(e->y() - (peg_size >> 1)); + moving->setZ(5); + moving->show(); + canvas()->update(); + return; + } + + QCanvasItemList l = canvas()->collisions(e->pos()); + for (QCanvasItemList::Iterator it=l.begin(); it !=l.end(); ++it) { + if ( (*it)->rtti() == pegRTTI ) { + Peg *item = (Peg *)(*it); + if (!item->hit(e->pos())) + continue; + if (item->type() > 5) { + null_press = TRUE; + null_point = e->pos(); + continue; /* not a color peg */ + } + if (item->placed()) { + /* copy */ + if(item->pegGo() == -1) + return; + if(item->pegGo() == current_go) { + copy_press = TRUE; + copy_peg = item; + } + moving = new Peg(canvas(), + item->type(), current_go); + moving->setX(e->x() - (peg_size >> 1)); + moving->setY(e->y() - (peg_size >> 1)); + moving->setZ(5); + moving->show(); + moving_pos = QPoint(e->x(), e->y()); + canvas()->update(); + return; + } + moving = (Peg *)*it; + moving_pos = e->pos(); + canvas()->update(); + return; + } + } + null_press = TRUE; + null_point = e->pos(); + moving = 0; +} + +void MindBreakerBoard::contentsMouseMoveEvent(QMouseEvent* e) +{ + if (moving ) { + moving->moveBy(e->pos().x() - moving_pos.x(), + e->pos().y() - moving_pos.y()); + moving_pos = e->pos(); + canvas()->update(); + return; + } +} + +void MindBreakerBoard::contentsMouseReleaseEvent(QMouseEvent* e) +{ + /* time to put down the peg */ + if(moving) { + if(copy_press) { + /* check if collided with original. if so, delete both */ + copy_press = FALSE; + QCanvasItemList l = canvas()->collisions(e->pos()); + for (QCanvasItemList::Iterator it=l.begin(); it !=l.end(); ++it) { + if (*it == copy_peg) + copy_press = TRUE; + } + if (copy_press) { + current_guess[copy_peg->pegPos()] = 6; + delete copy_peg; + delete moving; + copy_press = FALSE; + moving = 0; + copy_peg = 0; + canvas()->update(); + return; + } + } + + /* first work out if in y */ + if (e->y() > (board_height - (current_go * panel_height))) { + delete moving; + moving = 0; + canvas()->update(); + return; + } + if (e->y() < (board_height - ((current_go + 1) * panel_height))) { + delete moving; + moving = 0; + canvas()->update(); + return; + } + /* ok, a valid go, but which peg */ + int x_bar = first_peg_x_diff - (peg_size >> 1); + x_bar += peg_spacing; + int pos = 0; + if (e->x() > x_bar) + pos = 1; + x_bar += peg_spacing; + if (e->x() > x_bar) + pos = 2; + x_bar += peg_spacing; + if (e->x() > x_bar) + pos = 3; + x_bar += peg_spacing; + + if (e->x() > x_bar) { + /* invalid x */ + delete moving; + moving = 0; + canvas()->update(); + return; + } + + int x = first_peg_x_diff + (pos * peg_spacing); + int y = board_height - ((current_go + 1) * panel_height) + + first_peg_y_diff; + moving->setPegPos(pos); + moving->setX(x); + moving->setY(y); + moving->setZ(2); + + /* remove all other pegs from this position */ + QCanvasItemList l = canvas()->collisions(QPoint(x,y)); + for (QCanvasItemList::Iterator it=l.begin(); it !=l.end(); ++it) { + if ( (*it)->rtti() == pegRTTI ) { + Peg *item = (Peg *)(*it); + if ((item != moving) && (item != current_highlight)) + delete item; + } + } + current_guess[pos] = ((Peg *)moving)->type(); + + ((Peg *)moving)->setPlaced(true); + canvas()->update(); + return; + } + moving = 0; + null_point -= e->pos(); + if(null_point.manhattanLength() < 6) { + if (game_over) + clear(); + else + checkGuess(); + } +} + +void MindBreakerBoard::resizeEvent(QResizeEvent *e) +{ + QSize s = e->size(); + int fw = style().defaultFrameWidth(); + s.setWidth(s.width() - fw); + s.setHeight(s.height() - fw); + + /* min size is 200 x 260 */ + if (s.width() < board_width) + s.setWidth(board_width); + + if (s.height() < board_height) + s.setHeight(board_height); + + canvas()->resize(s.width() - fw, s.height() - fw); + drawBackground(); +} + + +/* Easter egg function... beat the clock */ +void MindBreakerBoard::checkScores() +{ + double games = total_games; + double turns = total_turns; + double g = games / 10.0; + Peg::eggLevel = 0; + + double break_even = 5.0; + if (g < 1.0) + return; + double avg = turns / games; + g--; + while (break_even >= 0.0) { + if (avg >= (break_even + g)) + return; + // score a peg. + break_even -= 1.0; + Peg::eggLevel = int(5.0 - break_even); + } +} diff --git a/noncore/games/mindbreaker/mindbreaker.h b/noncore/games/mindbreaker/mindbreaker.h new file mode 100644 index 0000000..fca649a --- a/dev/null +++ b/noncore/games/mindbreaker/mindbreaker.h @@ -0,0 +1,122 @@ +/********************************************************************** +** 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 MINDBREAKER_H +#define MINDBREAKER_H + +#include <qwidget.h> +#include <qmainwindow.h> +#include <qimage.h> +#include <qvector.h> +#include <qcanvas.h> +#include <qlabel.h> + +static const int panel_height = 26; +static const int panel_width = 180; + +static const int title_height = 25; +static const int title_width = 180; + +static const int bin_margin = 10; +static const int peg_size = 20; +static const int answerpeg_size = 13; + +static const int first_peg_x_diff = 21; +static const int first_peg_y_diff = ((panel_height - peg_size) >> 1); +static const int peg_spacing = 30; + +static const int answerpegx = 152; +static const int answerpegy = 2; +static const int answerpeg_diff = 9; + +static const int board_height = (title_height + (panel_height * 9)); +static const int board_width = (panel_width + (bin_margin * 2) + peg_size); + +class Peg; +class QToolButton; + +class MindBreakerBoard : public QCanvasView // QWidget +{ + Q_OBJECT +public: + MindBreakerBoard(QCanvas &c, QWidget *parent=0, const char *name=0, int wFlags=0 ); + ~MindBreakerBoard(); + + void getScore(int *, int *); +signals: + void scoreChanged(int, int); + +public slots: + void clear(); + void resetScore(); + +protected: + void contentsMousePressEvent(QMouseEvent *); + void contentsMouseMoveEvent(QMouseEvent *); + void contentsMouseReleaseEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); + +private: + void drawBackground(); + void checkGuess(); + void checkScores(); + void placeGuessPeg(int pos, int pegId); + + QImage panelImage; + QImage titleImage; + + Peg *moving; + Peg *current_highlight; + QPoint moving_pos; + + // the game stuff + int answer[4]; + int current_guess[4]; + int past_guesses[4*9]; + int current_go; + + int null_press; + QPoint null_point; + bool copy_press; + Peg *copy_peg; + bool game_over; + + int total_turns; + int total_games; +}; + +class MindBreaker : public QMainWindow // QWidget +{ + Q_OBJECT +public: + MindBreaker(QWidget *parent=0, const char *name=0, int wFlags=0 ); + +public slots: + void setScore(int, int); + +private: + QCanvas canvas; + MindBreakerBoard *board; + QToolButton *score; + +}; + + +#endif diff --git a/noncore/games/mindbreaker/mindbreaker.pro b/noncore/games/mindbreaker/mindbreaker.pro new file mode 100644 index 0000000..12944d1 --- a/dev/null +++ b/noncore/games/mindbreaker/mindbreaker.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = mindbreaker.h +SOURCES = main.cpp \ + mindbreaker.cpp +TARGET = mindbreaker +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/mindbreaker.ts diff --git a/noncore/games/mindbreaker/qpe-mindbreaker.control b/noncore/games/mindbreaker/qpe-mindbreaker.control new file mode 100644 index 0000000..3bad93d --- a/dev/null +++ b/noncore/games/mindbreaker/qpe-mindbreaker.control @@ -0,0 +1,9 @@ +Files: bin/mindbreaker apps/Games/mindbreaker.desktop pics/mindbreaker +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: crack the coloured code + A game for the Qtopia environment. diff --git a/noncore/games/minesweep/.cvsignore b/noncore/games/minesweep/.cvsignore new file mode 100644 index 0000000..6fe2396 --- a/dev/null +++ b/noncore/games/minesweep/.cvsignore @@ -0,0 +1,2 @@ +moc_* +Makefile diff --git a/noncore/games/minesweep/Makefile.in b/noncore/games/minesweep/Makefile.in new file mode 100644 index 0000000..9ed6234 --- a/dev/null +++ b/noncore/games/minesweep/Makefile.in @@ -0,0 +1,134 @@ +############################################################################# + +####### 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 = minesweep +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = minefield.h \ + minesweep.h +SOURCES = main.cpp \ + minefield.cpp \ + minesweep.cpp +OBJECTS = main.o \ + minefield.o \ + minesweep.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_minefield.cpp \ + moc_minesweep.cpp +OBJMOC = moc_minefield.o \ + moc_minesweep.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 minesweep.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 \ + minesweep.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +minefield.o: minefield.cpp \ + minefield.h \ + $(QPEDIR)/include/qpe/config.h + +minesweep.o: minesweep.cpp \ + minesweep.h \ + minefield.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +moc_minefield.o: moc_minefield.cpp \ + minefield.h + +moc_minesweep.o: moc_minesweep.cpp \ + minesweep.h + +moc_minefield.cpp: minefield.h + $(MOC) minefield.h -o moc_minefield.cpp + +moc_minesweep.cpp: minesweep.h + $(MOC) minesweep.h -o moc_minesweep.cpp + + diff --git a/noncore/games/minesweep/main.cpp b/noncore/games/minesweep/main.cpp new file mode 100644 index 0000000..83de9a3 --- a/dev/null +++ b/noncore/games/minesweep/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 "minesweep.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char** argv ) +{ + QPEApplication a( argc, argv ); + + MineSweep ms; + QPEApplication::setInputMethodHint( &ms, QPEApplication::AlwaysOff ); + a.showMainWidget( &ms ); + + return a.exec(); +} diff --git a/noncore/games/minesweep/minefield.cpp b/noncore/games/minesweep/minefield.cpp new file mode 100644 index 0000000..be2f9a3 --- a/dev/null +++ b/noncore/games/minesweep/minefield.cpp @@ -0,0 +1,623 @@ +/********************************************************************** +** 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 "minefield.h" + +#include <qpe/config.h> + +#include <qpainter.h> +#include <qdrawutil.h> +#include <qpixmap.h> +#include <qimage.h> +#include <qtimer.h> + +#include <stdlib.h> + +static const char *pix_flag[]={ +"13 13 3 1", +"# c #000000", +"x c #ff0000", +". c None", +".............", +".............", +".....#xxxxxx.", +".....#xxxxxx.", +".....#xxxxxx.", +".....#xxxxxx.", +".....#.......", +".....#.......", +".....#.......", +".....#.......", +"...#####.....", +"..#######....", +"............."}; + +static const char *pix_mine[]={ +"13 13 3 1", +"# c #000000", +". c None", +"a c #ffffff", +"......#......", +"......#......", +"..#.#####.#..", +"...#######...", +"..##aa#####..", +"..##aa#####..", +"#############", +"..#########..", +"..#########..", +"...#######...", +"..#.#####.#..", +"......#......", +"......#......"}; + +class Mine : public QTableItem +{ +public: + enum MineState { + Hidden = 0, + Empty, + Mined, + Flagged, +#ifdef MARK_UNSURE + Unsure, +#endif + Exploded, + Wrong + }; + + Mine( QTable* ); + void paint( QPainter * p, const QColorGroup & cg, const QRect & cr, bool selected ); + EditType editType() const { return Never; } + QSize sizeHint() const { return QSize( 12, 12 ); } + + void activate( bool sure = TRUE ); + void setHint( int ); + + void setState( MineState ); + MineState state() const { return st; } + + bool isMined() const { return mined; } + void setMined( bool m ) { mined = m; } + + static void paletteChange(); + +private: + bool mined; + int hint; + + MineState st; + + static QPixmap* knownField; + static QPixmap* unknownField; + static QPixmap* flag_pix; + static QPixmap* mine_pix; +}; + +QPixmap* Mine::knownField = 0; +QPixmap* Mine::unknownField = 0; +QPixmap* Mine::flag_pix = 0; +QPixmap* Mine::mine_pix = 0; + +Mine::Mine( QTable *t ) +: QTableItem( t, Never, QString::null ) +{ + mined = FALSE; + st = Hidden; + hint = 0; +} + +void Mine::activate( bool sure ) +{ + if ( !sure ) { + switch ( st ) { + case Hidden: + setState( Flagged ); + break; + case Flagged: +#ifdef MARK_UNSURE + setState( Unsure ); + break; + case Unsure: +#endif + setState( Hidden ); + default: + break; + } + } else if ( st == Flagged ) { + return; + } else { + if ( mined ) { + setState( Exploded ); + } else { + setState( Empty ); + } + } +} + +void Mine::setState( MineState s ) +{ + st = s; +} + +void Mine::setHint( int h ) +{ + hint = h; +} + +void Mine::paletteChange() +{ + delete knownField; + knownField = 0; + delete unknownField; + unknownField = 0; + delete mine_pix; + mine_pix = 0; + delete flag_pix; + flag_pix = 0; +} + +void Mine::paint( QPainter* p, const QColorGroup &cg, const QRect& cr, bool ) +{ + if ( !knownField ) { + knownField = new QPixmap( cr.width(), cr.height() ); + QPainter pp( knownField ); + QBrush br( cg.button().dark(115) ); + qDrawWinButton( &pp, QRect(0,0,cr.width(), cr.height())/*cr*/, cg, TRUE, &br ); + } + + const int pmmarg=cr.width()/5; + + if ( !unknownField ) { + unknownField = new QPixmap( cr.width(), cr.height() ); + QPainter pp( unknownField ); + QBrush br( cg.button() ); + qDrawWinButton( &pp, QRect(0,0,cr.width(), cr.height())/*cr*/, cg, FALSE, &br ); + } + + if ( !flag_pix ) { + flag_pix = new QPixmap( cr.width()-pmmarg*2, cr.height()-pmmarg*2 ); + flag_pix->convertFromImage( QImage(pix_flag).smoothScale(cr.width()-pmmarg*2, cr.height()-pmmarg*2) ); + } + + if ( !mine_pix ) { + mine_pix = new QPixmap( cr.width()-pmmarg*2, cr.height()-pmmarg*2 ); + mine_pix->convertFromImage( QImage(pix_mine).smoothScale(cr.width()-pmmarg*2, cr.height()-pmmarg*2) ); + } + + p->save(); + + switch(st) { + case Hidden: + p->drawPixmap( 0, 0, *unknownField ); + break; + case Empty: + p->drawPixmap( 0, 0, *knownField ); + if ( hint > 0 ) { + switch( hint ) { + case 1: + p->setPen( blue ); + break; + case 2: + p->setPen( green ); + case 3: + p->setPen( red ); + break; + default: + p->setPen( darkMagenta ); + break; + } + p->drawText( QRect( 0, 0, cr.width(), cr.height() ), AlignHCenter | AlignVCenter, QString().setNum( hint ) ); + } + break; + case Mined: + p->drawPixmap( 0, 0, *knownField ); + p->drawPixmap( pmmarg, pmmarg, *mine_pix ); + break; + case Exploded: + p->drawPixmap( 0, 0, *knownField ); + p->drawPixmap( pmmarg, pmmarg, *mine_pix ); + p->setPen( red ); + p->drawText( QRect( 0, 0, cr.width(), cr.height() ), AlignHCenter | AlignVCenter, "X" ); + break; + case Flagged: + p->drawPixmap( 0, 0, *unknownField ); + p->drawPixmap( pmmarg, pmmarg, *flag_pix ); + break; +#ifdef MARK_UNSURE + case Unsure: + p->drawPixmap( 0, 0, *unknownField ); + p->drawText( QRect( 0, 0, cr.width(), cr.height() ), AlignHCenter | AlignVCenter, "?" ); + break; +#endif + case Wrong: + p->drawPixmap( 0, 0, *unknownField ); + p->drawPixmap( pmmarg, pmmarg, *flag_pix ); + p->setPen( red ); + p->drawText( QRect( 0, 0, cr.width(), cr.height() ), AlignHCenter | AlignVCenter, "X" ); + break; + } + + p->restore(); +} + +/* + MineField implementation +*/ + +MineField::MineField( QWidget* parent, const char* name ) +: QTable( parent, name ) +{ + setState( GameOver ); + setShowGrid( FALSE ); + horizontalHeader()->hide(); + verticalHeader()->hide(); + setTopMargin( 0 ); + setLeftMargin( 0 ); + + setSizePolicy( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum ) ); + + setSelectionMode( QTable::NoSelection ); + setFocusPolicy( QWidget::NoFocus ); + + setCurrentCell( -1, -1 ); + + connect( this, SIGNAL( pressed( int, int, int, const QPoint& ) ), this, SLOT( cellPressed( int, int ) ) ); + connect( this, SIGNAL( clicked( int, int, int, const QPoint& ) ), this, SLOT( cellClicked( int, int ) ) ); + + holdTimer = new QTimer( this ); + connect( holdTimer, SIGNAL( timeout() ), this, SLOT( held() ) ); + + flagAction = NoAction; + ignoreClick = FALSE; + currRow = currCol = 0; + minecount=0; + mineguess=0; + nonminecount=0; +} + +MineField::~MineField() +{ +} + +void MineField::setState( State st ) +{ + stat = st; +} + + +void MineField::setup( int level ) +{ + lev = level; + setState( Waiting ); + viewport()->setUpdatesEnabled( FALSE ); + + int cellsize; + + int x; + int y; + for ( x = 0; x < numCols(); x++ ) + for ( y = 0; y < numRows(); y++ ) + clearCell( y, x ); + + switch( lev ) { + case 1: + setNumRows( 9 ); + setNumCols( 9 ); + minecount = 12; + cellsize = 21; + break; + case 2: + setNumRows( 16 ); + setNumCols( 16 ); + minecount = 45; + cellsize = 14; + break; + case 3: + setNumRows( 18 ); + setNumCols( 18 ); + minecount = 66 ; + cellsize = 12; + break; + } + nonminecount = numRows()*numCols() - minecount; + mineguess = minecount; + emit mineCount( mineguess ); + Mine::paletteChange(); + + for ( y = 0; y < numRows(); y++ ) + setRowHeight( y, cellsize ); + for ( x = 0; x < numCols(); x++ ) + setColumnWidth( x, cellsize ); + for ( x = 0; x < numCols(); x++ ) + for ( y = 0; y < numRows(); y++ ) + setItem( y, x, new Mine( this ) ); + + updateGeometry(); + viewport()->setUpdatesEnabled( TRUE ); + viewport()->repaint( TRUE ); +} + + +void MineField::placeMines() +{ + int mines = minecount; + while ( mines ) { + int col = int((double(rand()) / double(RAND_MAX)) * numCols()); + int row = int((double(rand()) / double(RAND_MAX)) * numRows()); + + Mine* mine = (Mine*)item( row, col ); + + if ( mine && !mine->isMined() && mine->state() == Mine::Hidden ) { + mine->setMined( TRUE ); + mines--; + } + } +} + +void MineField::paintFocus( QPainter*, const QRect& ) +{ +} + +void MineField::viewportMousePressEvent( QMouseEvent* e ) +{ + QTable::viewportMousePressEvent( e ); +} + +void MineField::viewportMouseReleaseEvent( QMouseEvent* e ) +{ + QTable::viewportMouseReleaseEvent( e ); + if ( flagAction == FlagNext ) { + flagAction = NoAction; + } +} + +void MineField::keyPressEvent( QKeyEvent* e ) +{ +#if defined(Q_WS_QWS) || defined(_WS_QWS_) + flagAction = ( e->key() == Key_Up ) ? FlagOn : NoAction; +#else + flagAction = ( ( e->state() & ShiftButton ) == ShiftButton ) ? FlagOn : NoAction; +#endif +} + +void MineField::keyReleaseEvent( QKeyEvent* ) +{ + flagAction = NoAction; +} + +int MineField::getHint( int row, int col ) +{ + int hint = 0; + for ( int c = col-1; c <= col+1; c++ ) + for ( int r = row-1; r <= row+1; r++ ) { + Mine* mine = (Mine*)item( r, c ); + if ( mine && mine->isMined() ) + hint++; + } + + return hint; +} + +void MineField::setHint( Mine* mine ) +{ + if ( !mine ) + return; + + int row = mine->row(); + int col = mine->col(); + int hint = getHint( row, col ); + + if ( !hint ) { + for ( int c = col-1; c <= col+1; c++ ) + for ( int r = row-1; r <= row+1; r++ ) { + Mine* mine = (Mine*)item( r, c ); + if ( mine && mine->state() == Mine::Hidden ) { + mine->activate( TRUE ); + nonminecount--; + setHint( mine ); + updateCell( r, c ); + } + } + } + + mine->setHint( hint ); + updateCell( row, col ); +} + +/* + state == Waiting means no "hold" + + +*/ +void MineField::cellPressed( int row, int col ) +{ + if ( state() == GameOver ) + return; + currRow = row; + currCol = col; + if ( state() == Playing ) + holdTimer->start( 150, TRUE ); +} + +void MineField::held() +{ + flagAction = FlagNext; + updateMine( currRow, currCol ); + ignoreClick = TRUE; +} + +/* + Only place mines after first click, since it is pointless to + kill the player before the game has started. +*/ + +void MineField::cellClicked( int row, int col ) +{ + if ( state() == GameOver ) + return; + if ( state() == Waiting ) { + Mine* mine = (Mine*)item( row, col ); + if ( !mine ) + return; + mine->setState( Mine::Empty ); + nonminecount--; + placeMines(); + setState( Playing ); + emit gameStarted(); + updateMine( row, col ); + } else { // state() == Playing + holdTimer->stop(); + if ( ignoreClick ) + ignoreClick = FALSE; + else + updateMine( row, col ); + } +} + +void MineField::updateMine( int row, int col ) +{ + Mine* mine = (Mine*)item( row, col ); + if ( !mine ) + return; + + bool wasFlagged = mine->state() == Mine::Flagged; + bool wasEmpty = mine->state() == Mine::Empty; + + mine->activate( flagAction == NoAction ); + + if ( mine->state() == Mine::Exploded ) { + emit gameOver( FALSE ); + setState( GameOver ); + return; + } else if ( mine->state() == Mine::Empty ) { + setHint( mine ); + if ( !wasEmpty ) + nonminecount--; + } + + if ( flagAction != NoAction ) { + if ( mine->state() == Mine::Flagged ) { + --mineguess; + emit mineCount( mineguess ); + if ( mine->isMined() ) + --minecount; + } else if ( wasFlagged ) { + ++mineguess; + emit mineCount( mineguess ); + if ( mine->isMined() ) + ++minecount; + } + } + + updateCell( row, col ); + + if ( !minecount && !mineguess || !nonminecount ) { + emit gameOver( TRUE ); + setState( GameOver ); + } +} + +void MineField::showMines() +{ + for ( int c = 0; c < numCols(); c++ ) + for ( int r = 0; r < numRows(); r++ ) { + Mine* mine = (Mine*)item( r, c ); + if ( !mine ) + continue; + if ( mine->isMined() && mine->state() == Mine::Hidden ) + mine->setState( Mine::Mined ); + if ( !mine->isMined() && mine->state() == Mine::Flagged ) + mine->setState( Mine::Wrong ); + + updateCell( r, c ); + } +} + +void MineField::paletteChange( const QPalette &o ) +{ + Mine::paletteChange(); + QTable::paletteChange( o ); +} + +void MineField::writeConfig(Config& cfg) const +{ + cfg.setGroup("Field"); + cfg.writeEntry("Level",lev); + QString grid=""; + if ( stat == Playing ) { + for ( int x = 0; x < numCols(); x++ ) + for ( int y = 0; y < numRows(); y++ ) { + char code='A'+(x*17+y*101)%21; // Reduce the urge to cheat + Mine* mine = (Mine*)item( y, x ); + int st = (int)mine->state(); if ( mine->isMined() ) st+=5; + grid += code + st; + } + } + cfg.writeEntry("Grid",grid); +} + +void MineField::readConfig(Config& cfg) +{ + cfg.setGroup("Field"); + lev = cfg.readNumEntry("Level",1); + setup(lev); + flagAction = NoAction; + ignoreClick = FALSE; + currRow = currCol = 0; + QString grid = cfg.readEntry("Grid"); + if ( !grid.isEmpty() ) { + int i=0; + minecount=0; + mineguess=0; + for ( int x = 0; x < numCols(); x++ ) { + for ( int y = 0; y < numRows(); y++ ) { + char code='A'+(x*17+y*101)%21; // Reduce the urge to cheat + int st = (char)(QChar)grid[i++]-code; + Mine* mine = (Mine*)item( y, x ); + if ( st >= 5 ) { + st-=5; + mine->setMined(TRUE); + minecount++; + mineguess++; + } + mine->setState((Mine::MineState)st); + switch ( mine->state() ) { + case Mine::Flagged: + if (mine->isMined()) + minecount--; + mineguess--; + break; + case Mine::Empty: + --nonminecount; + } + } + } + for ( int x = 0; x < numCols(); x++ ) { + for ( int y = 0; y < numRows(); y++ ) { + Mine* mine = (Mine*)item( y, x ); + if ( mine->state() == Mine::Empty ) + mine->setHint(getHint(y,x)); + } + } + } + setState( Playing ); + emit mineCount( mineguess ); +} + diff --git a/noncore/games/minesweep/minefield.h b/noncore/games/minesweep/minefield.h new file mode 100644 index 0000000..4ede435 --- a/dev/null +++ b/noncore/games/minesweep/minefield.h @@ -0,0 +1,87 @@ +/********************************************************************** +** 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 MINEFIELD_H +#define MINEFIELD_H + +#include <qtable.h> + +class Mine; +class Config; + +class MineField : public QTable +{ + Q_OBJECT +public: + MineField( QWidget* parent = 0, const char* name = 0 ); + ~MineField(); + + enum State { Waiting, Playing, GameOver }; + + State state() const { return stat; } + + void readConfig(Config&); + void writeConfig(Config&) const; + + int level() const { return lev; } + +public slots: + void setup( int level ); + + void showMines(); + +signals: + void gameOver( bool won ); + void gameStarted(); + void mineCount( int ); + +protected: + void paintFocus( QPainter*, const QRect& ); + void viewportMousePressEvent( QMouseEvent* ); + void viewportMouseReleaseEvent( QMouseEvent* ); + void keyPressEvent( QKeyEvent* ); + void keyReleaseEvent( QKeyEvent* ); + + int getHint( int row, int col ); + void setHint( Mine* ); + void updateMine( int row, int col ); + void paletteChange( const QPalette & ); + +protected slots: + void cellPressed( int row, int col ); + void cellClicked( int row, int col ); + void held(); + +private: + State stat; + void MineField::setState( State st ); + void MineField::placeMines(); + enum FlagAction { NoAction, FlagOn, FlagNext }; + FlagAction flagAction; + bool ignoreClick; + int currRow; + int currCol; + int minecount; + int mineguess; + int nonminecount; + int lev; + QTimer *holdTimer; +}; + +#endif // MINEFIELD_H diff --git a/noncore/games/minesweep/minesweep.cpp b/noncore/games/minesweep/minesweep.cpp new file mode 100644 index 0000000..6492462 --- a/dev/null +++ b/noncore/games/minesweep/minesweep.cpp @@ -0,0 +1,390 @@ +/********************************************************************** +** 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 "minesweep.h" +#include "minefield.h" + +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qpe/qpetoolbar.h> +#include <qpe/qpemenubar.h> +#include <qpopupmenu.h> +#include <qpushbutton.h> +#include <qlcdnumber.h> +#include <qmessagebox.h> +#include <qtimer.h> +#include <qpalette.h> +#include <qapplication.h> +#include <qlayout.h> +#include <qlabel.h> + +#include <stdlib.h> +#include <time.h> + + + + +static const char *pix_new[]={ +"20 20 3 1", +" c None", +"# c #00FF00", +". c #000000", +" ", +" ...... ", +" ..######.. ", +" .##########. ", +" .############. ", +" .##############. ", +" .##############. ", +" .################. ", +" .################. ", +" .################. ", +" .################. ", +" .################. ", +" .################. ", +" .##############. ", +" .##############. ", +" .############. ", +" .##########. ", +" ..######.. ", +" ...... ", +" "}; + + +/* XPM */ +static const char * happy_xpm[] = { +"20 20 3 1", +" c None", +". c #ffff3f ", +"# c #000000", +" ", +" ###### ", +" ##......## ", +" #..........# ", +" #............# ", +" #..............# ", +" #..............# ", +" #....##....##....# ", +" #....##....##....# ", +" #................# ", +" #................# ", +" #................# ", +" #...#........#...# ", +" #.##........##.# ", +" #...########...# ", +" #...######...# ", +" #..........# ", +" ##......## ", +" ###### ", +" "}; + + +/* XPM */ +static const char * worried_xpm[] = { +"20 20 3 1", +" c None", +". c #ffff3f", +"# c #000000", +" ", +" ###### ", +" ##......## ", +" #..........# ", +" #............# ", +" #..............# ", +" #..............# ", +" #....##....##....# ", +" #....##....##....# ", +" #................# ", +" #................# ", +" #................# ", +" #................# ", +" #....######....# ", +" #..............# ", +" #............# ", +" #..........# ", +" ##......## ", +" ###### ", +" "}; + + +/* XPM */ +static const char * dead_xpm[] = { +"20 20 3 1", +" c None", +". c #ffff3f", +"# c #000000", +" ", +" ###### ", +" ##......## ", +" #..........# ", +" #............# ", +" #..............# ", +" #..#.#...#.#...# ", +" #....#.....#.....# ", +" #...#.#...#.#....# ", +" #................# ", +" #................# ", +" #................# ", +" #......####......# ", +" #....# #....# ", +" #...#......#...# ", +" #............# ", +" #..........# ", +" ##......## ", +" ###### ", +" "}; + + +class ResultIndicator : private QLabel +{ +public: + static void showResult( QWidget *ref, bool won ); +private: + ResultIndicator( QWidget *parent, const char *name, WFlags f) + :QLabel( parent, name, f ) {} + + void timerEvent( QTimerEvent *); + void center(); + bool twoStage; + int timerId; +}; + +void ResultIndicator::showResult( QWidget *ref, bool won ) +{ + ResultIndicator *r = new ResultIndicator( ref, 0, WStyle_Customize | WStyle_Tool | WType_TopLevel ); + + r->setAlignment( AlignCenter ); + r->setFrameStyle( Sunken|StyledPanel ); + if ( won ) { + r->setText( MineSweep::tr("You won!") ); + r->center(); + r->show(); + r->twoStage = FALSE; + r->timerId = r->startTimer(1500); + } else { + QPalette p( red ); + r->setPalette( p ); + r->setText( MineSweep::tr("You exploded!") ); + r->resize( ref->size() ); + r->move( ref->mapToGlobal(QPoint(0,0)) ); + r->show(); + r->twoStage = TRUE; + r->timerId =r->startTimer(200); + } +} + +void ResultIndicator::center() +{ + QWidget *w = parentWidget(); + + QPoint pp = w->mapToGlobal( QPoint(0,0) ); + QSize s = sizeHint()*3; + pp = QPoint( pp.x() + w->width()/2 - s.width()/2, + pp.y() + w->height()/ 2 - s.height()/2 ); + + setGeometry( QRect(pp, s) ); + +} + +void ResultIndicator::timerEvent( QTimerEvent *te ) +{ + if ( te->timerId() != timerId ) + return; + killTimer( timerId ); + if ( twoStage ) { + center(); + twoStage = FALSE; + timerId = startTimer( 1000 ); + } else { + delete this; + } +} + + +MineSweep::MineSweep( QWidget* parent, const char* name, WFlags f ) +: QMainWindow( parent, name, f ) +{ + srand(::time(0)); + setCaption( tr("Mine Hunt") ); + setIcon( Resource::loadPixmap( "minesweep_icon" ) ); + + QPEToolBar *menuToolBar = new QPEToolBar( this ); + QPEMenuBar *menuBar = new QPEMenuBar( menuToolBar ); + + QPopupMenu *gameMenu = new QPopupMenu( this ); + gameMenu->insertItem( tr("Beginner"), this, SLOT( beginner() ) ); + gameMenu->insertItem( tr("Advanced"), this, SLOT( advanced() ) ); + gameMenu->insertItem( tr("Expert"), this, SLOT( expert() ) ); + + menuBar->insertItem( tr("Game"), gameMenu ); + + QPEToolBar *toolBar = new QPEToolBar( this ); + toolBar->setHorizontalStretchable( TRUE ); + + guessLCD = new QLCDNumber( toolBar ); + toolBar->setStretchableWidget( guessLCD ); + + QPalette lcdPal( red ); + lcdPal.setColor( QColorGroup::Background, QApplication::palette().active().background() ); + lcdPal.setColor( QColorGroup::Button, QApplication::palette().active().button() ); + +// guessLCD->setPalette( lcdPal ); + guessLCD->setSegmentStyle( QLCDNumber::Flat ); + guessLCD->setFrameStyle( QFrame::NoFrame ); + guessLCD->setNumDigits( 2 ); + guessLCD->setBackgroundMode( PaletteButton ); + newGameButton = new QPushButton( toolBar ); + newGameButton->setPixmap( QPixmap( pix_new ) ); + newGameButton->setFocusPolicy(QWidget::NoFocus); + connect( newGameButton, SIGNAL(clicked()), this, SLOT(newGame()) ); + + timeLCD = new QLCDNumber( toolBar ); +// timeLCD->setPalette( lcdPal ); + timeLCD->setSegmentStyle( QLCDNumber::Flat ); + timeLCD->setFrameStyle( QFrame::NoFrame ); + timeLCD->setNumDigits( 5 ); // "mm:ss" + timeLCD->setBackgroundMode( PaletteButton ); + + setToolBarsMovable ( FALSE ); + + addToolBar( menuToolBar ); + addToolBar( toolBar ); + + QFrame *mainframe = new QFrame( this ); + mainframe->setFrameShape( QFrame::Box ); + mainframe->setFrameShadow( QFrame::Raised ); + mainframe->setMargin(5); + mainframe->setLineWidth(2); + QBoxLayout *box = new QVBoxLayout( mainframe ); + field = new MineField( mainframe ); + box->addWidget( field, 0, AlignCenter ); + QFont fnt = field->font(); + fnt.setBold( TRUE ); + field->setFont( QFont( fnt ) ); + field->setFocus(); + setCentralWidget( mainframe ); + + connect( field, SIGNAL( gameOver( bool ) ), this, SLOT( gameOver( bool ) ) ); + connect( field, SIGNAL( mineCount( int ) ), this, SLOT( setCounter( int ) ) ); + connect( field, SIGNAL( gameStarted()), this, SLOT( startPlaying() ) ); + + timer = new QTimer( this ); + + connect( timer, SIGNAL( timeout() ), this, SLOT( updateTime() ) ); + + readConfig(); +} + +MineSweep::~MineSweep() +{ + writeConfig(); +} + +void MineSweep::gameOver( bool won ) +{ + field->showMines(); + if ( won ) { + newGameButton->setPixmap( QPixmap( happy_xpm ) ); + } else { + newGameButton->setPixmap( QPixmap( dead_xpm ) ); + } + ResultIndicator::showResult( this, won ); + timer->stop(); +} + +void MineSweep::newGame() +{ + newGame(field->level()); +} + +void MineSweep::newGame(int level) +{ + timeLCD->display( "0:00" ); + field->setup( level ); + newGameButton->setPixmap( QPixmap( pix_new ) ); + timer->stop(); +} + +void MineSweep::startPlaying() +{ + newGameButton->setPixmap( QPixmap( worried_xpm ) ); + starttime = QDateTime::currentDateTime(); + timer->start( 1000 ); +} + +void MineSweep::beginner() +{ + newGame(1); +} + +void MineSweep::advanced() +{ + newGame(2); +} + +void MineSweep::expert() +{ + newGame(3); +} + +void MineSweep::setCounter( int c ) +{ + if ( !guessLCD ) + return; + + guessLCD->display( c ); +} + +void MineSweep::updateTime() +{ + if ( !timeLCD ) + return; + + int s = starttime.secsTo(QDateTime::currentDateTime()); + if ( s/60 > 99 ) + timeLCD->display( "-----" ); + else + timeLCD->display( QString().sprintf("%2d:%02d",s/60,s%60) ); +} + +void MineSweep::writeConfig() const +{ + Config cfg("MineSweep"); + cfg.setGroup("Panel"); + cfg.writeEntry("Time", + timer->isActive() ? starttime.secsTo(QDateTime::currentDateTime()) : -1); + field->writeConfig(cfg); +} + +void MineSweep::readConfig() +{ + Config cfg("MineSweep"); + field->readConfig(cfg); + cfg.setGroup("Panel"); + int s = cfg.readNumEntry("Time",-1); + if ( s<0 ) { + newGame(); + } else { + startPlaying(); + starttime = QDateTime::currentDateTime().addSecs(-s); + updateTime(); + } +} diff --git a/noncore/games/minesweep/minesweep.h b/noncore/games/minesweep/minesweep.h new file mode 100644 index 0000000..e860573 --- a/dev/null +++ b/noncore/games/minesweep/minesweep.h @@ -0,0 +1,67 @@ +/********************************************************************** +** 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 MINESWEEP_H +#define MINESWEEP_H + +#include <qmainwindow.h> +#include <qdatetime.h> + +class MineField; +class QLCDNumber; +class QPushButton; + +class MineSweep : public QMainWindow +{ + Q_OBJECT +public: + MineSweep( QWidget* parent = 0, const char* name = 0, WFlags f = 0 ); + ~MineSweep(); + +public slots: + void gameOver( bool won ); + void newGame(); + +protected slots: + void setCounter( int ); + void updateTime(); + + void beginner(); + void advanced(); + void expert(); + +private slots: + void startPlaying(); + +private: + void readConfig(); + void writeConfig() const; + + void newGame(int); + MineField* field; + QLCDNumber* guessLCD; + QLCDNumber* timeLCD; + QPushButton* newGameButton; + + QDateTime starttime; + QTimer* timer; +}; + +#endif // MINESWEEP_H + diff --git a/noncore/games/minesweep/minesweep.pro b/noncore/games/minesweep/minesweep.pro new file mode 100644 index 0000000..87484bc --- a/dev/null +++ b/noncore/games/minesweep/minesweep.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = minefield.h \ + minesweep.h +SOURCES = main.cpp \ + minefield.cpp \ + minesweep.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +INTERFACES = + +TRANSLATIONS = ../i18n/de/minesweep.ts diff --git a/noncore/games/minesweep/qpe-minesweep.control b/noncore/games/minesweep/qpe-minesweep.control new file mode 100644 index 0000000..36bc221 --- a/dev/null +++ b/noncore/games/minesweep/qpe-minesweep.control @@ -0,0 +1,9 @@ +Files: bin/minesweep apps/Games/minesweep.desktop +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: find the mines + A game for the Qtopia environment. diff --git a/noncore/games/parashoot/.cvsignore b/noncore/games/parashoot/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/noncore/games/parashoot/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/noncore/games/parashoot/Makefile.in b/noncore/games/parashoot/Makefile.in new file mode 100644 index 0000000..ff7397e --- a/dev/null +++ b/noncore/games/parashoot/Makefile.in @@ -0,0 +1,203 @@ +############################################################################# + +####### 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 = parashoot +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = interface.h \ + man.h \ + cannon.h \ + base.h \ + bullet.h \ + helicopter.h +SOURCES = main.cpp \ + interface.cpp \ + man.cpp \ + cannon.cpp \ + base.cpp \ + bullet.cpp \ + helicopter.cpp +OBJECTS = main.o \ + interface.o \ + man.o \ + cannon.o \ + base.o \ + bullet.o \ + helicopter.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_interface.cpp \ + moc_cannon.cpp \ + moc_bullet.cpp +OBJMOC = moc_interface.o \ + moc_cannon.o \ + moc_bullet.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 parashoot.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 \ + interface.h \ + cannon.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h \ + base.h \ + helicopter.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +interface.o: interface.cpp \ + interface.h \ + cannon.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h \ + base.h \ + helicopter.h \ + man.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +man.o: man.cpp \ + codes.h \ + man.h \ + $(QPEDIR)/include/qpe/sound.h \ + base.h \ + $(QPEDIR)/include/qpe/resource.h + +cannon.o: cannon.cpp \ + $(QPEDIR)/include/qpe/resource.h \ + codes.h \ + cannon.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h + +base.o: base.cpp \ + codes.h \ + base.h \ + $(QPEDIR)/include/qpe/sound.h \ + man.h \ + $(QPEDIR)/include/qpe/resource.h + +bullet.o: bullet.cpp \ + codes.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h \ + man.h \ + helicopter.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qmath.h + +helicopter.o: helicopter.cpp \ + helicopter.h \ + $(QPEDIR)/include/qpe/sound.h \ + man.h \ + codes.h \ + $(QPEDIR)/include/qpe/resource.h + +moc_interface.o: moc_interface.cpp \ + interface.h \ + cannon.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h \ + base.h \ + helicopter.h + +moc_cannon.o: moc_cannon.cpp \ + cannon.h \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h + +moc_bullet.o: moc_bullet.cpp \ + bullet.h \ + $(QPEDIR)/include/qpe/sound.h + +moc_interface.cpp: interface.h + $(MOC) interface.h -o moc_interface.cpp + +moc_cannon.cpp: cannon.h + $(MOC) cannon.h -o moc_cannon.cpp + +moc_bullet.cpp: bullet.h + $(MOC) bullet.h -o moc_bullet.cpp + + diff --git a/noncore/games/parashoot/base.cpp b/noncore/games/parashoot/base.cpp new file mode 100644 index 0000000..c03802f --- a/dev/null +++ b/noncore/games/parashoot/base.cpp @@ -0,0 +1,71 @@ +/********************************************************************** +** 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 "codes.h" +#include "base.h" +#include "man.h" + +#include <qpe/resource.h> + +#include <qregexp.h> + +int damage; + +Base::Base(QCanvas* canvas) : + QCanvasSprite(0, canvas), + kaboom("landmine"), + ohdear("crmble01") +{ + basearray = new QCanvasPixmapArray(); + QString b0 = Resource::findPixmap("parashoot/b0001"); + b0.replace(QRegExp("0001"),"%1"); + basearray->readPixmaps(b0, 4); + setSequence(basearray); + setFrame(0); + move(2, canvas->height()-50); + setZ(10); + show(); + damage = 0; +} + +void Base::damageBase() +{ + damage++; + + switch(damage) { + case 1: setFrame(1); ohdear.play(); break; + case 2: setFrame(2); ohdear.play(); break; + case 3: setFrame(3); kaboom.play(); break; + } + show(); +} + +bool Base::baseDestroyed() +{ + return (damage >= 3); +} + +Base::~Base() +{ +} + +int Base::rtti() const +{ + return base_rtti; +} diff --git a/noncore/games/parashoot/base.h b/noncore/games/parashoot/base.h new file mode 100644 index 0000000..ee7f166 --- a/dev/null +++ b/noncore/games/parashoot/base.h @@ -0,0 +1,38 @@ +/********************************************************************** +** 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 <qpe/sound.h> + +#include <qcanvas.h> + +class Base : public QCanvasSprite +{ + +public: + Base(QCanvas*); + ~Base(); + void damageBase(); + int rtti() const; + static bool baseDestroyed(); + +private: + QCanvasPixmapArray* basearray; + Sound kaboom, ohdear; +}; diff --git a/noncore/games/parashoot/bullet.cpp b/noncore/games/parashoot/bullet.cpp new file mode 100644 index 0000000..584f564 --- a/dev/null +++ b/noncore/games/parashoot/bullet.cpp @@ -0,0 +1,142 @@ +/********************************************************************** +** 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 "codes.h" +#include "bullet.h" +#include "man.h" +#include "helicopter.h" + +#include <qpe/resource.h> +#include <qpe/qmath.h> + + +int limit; +int shotcount; +int nobullets; + +Bullet::Bullet(QCanvas* canvas, double angle, int cannonx, int cannony) : + QCanvasSprite(0, canvas), + bang("collide01") +{ + QCanvasPixmapArray* bulletarray = new QCanvasPixmapArray(Resource::findPixmap("parashoot/bullet")); + setSequence(bulletarray); + if (nobullets < limit) { + nobullets++; + move(cannonx, cannony); + dy = 0; + dx = 0; + show(); + setXY(angle); + setVelocity(-dx, -dy); + bang.play(); + } else + return; +} + +void Bullet::setXY(double angle) +{ + double ang = angle; + if ( (y() < 0) || (x() < 0) || (y() > canvas()->height()) || + (x() > canvas()->width()) ) + delete this; + else { + double radians = 0; + radians = ang * 3.14159265/180; + dx = (qCos(radians)) *7; + dy = (qSin(radians)) *7; + } +} + +void Bullet::setLimit(int amount) +{ + limit = amount; +} + +void Bullet::setNobullets(int amount) +{ + nobullets = amount; +} + +void Bullet::checkCollision() +{ + QCanvasItem* item; + QCanvasItemList l=collisions(FALSE); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + item = *it; + if ( (item->rtti()== 1500) && (item->collidesWith(this)) ) { + Man* deadman = (Man*)item; + if (deadman->frame() != 5) return; + deadman->done(); + emit score(10); + setShotCount(shotcount+1); + setAnimated(false); + nobullets--; + delete this; + return; + } + else if ( (item->rtti()==1900) && (item->collidesWith(this)) ) { + Helicopter* deadchopper = (Helicopter*) item; + deadchopper->done(); + emit score(50); + setAnimated(false); + nobullets--; + delete this; + return; + } + } + //check shot is not out of bounds + if ( (y() < 0) || (x() < 0) || + (y() > canvas()->height()) || + ( x() > canvas()->width())) { + setAnimated(false); + nobullets--; + delete this; + return; + } +} + +void Bullet::advance(int phase) +{ + QCanvasSprite::advance(phase); + + if (phase == 0) + checkCollision(); + +} + +int Bullet::getShotCount() +{ + return shotcount; +} + +void Bullet::setShotCount(int amount) +{ + shotcount = amount; +} + +Bullet::~Bullet() +{ + +} + +int Bullet::rtti() const +{ + return bullet_rtti; +} diff --git a/noncore/games/parashoot/bullet.h b/noncore/games/parashoot/bullet.h new file mode 100644 index 0000000..7d15899 --- a/dev/null +++ b/noncore/games/parashoot/bullet.h @@ -0,0 +1,51 @@ +/********************************************************************** +** 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 <qpe/sound.h> + +#include <qtimer.h> +#include <qcanvas.h> + +#include <math.h> + +class Bullet : public QObject, public QCanvasSprite +{ + Q_OBJECT +public: + Bullet(QCanvas*, double angle, int cannonx, int cannony); + ~Bullet(); + void setXY(double angle); + void checkCollision(); + void advance(int phase); + int rtti() const; + static int getShotCount(); + static void setShotCount(int amount); + static void setLimit(int amount); + static void setNobullets(int amount); + +signals: + void score(int); + +private: + double dx; + double dy; + int damage; + Sound bang; +}; diff --git a/noncore/games/parashoot/cannon.cpp b/noncore/games/parashoot/cannon.cpp new file mode 100644 index 0000000..3c0a5fe --- a/dev/null +++ b/noncore/games/parashoot/cannon.cpp @@ -0,0 +1,140 @@ +/********************************************************************** +** 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 <qpe/resource.h> + +#include <qregexp.h> + +#include "codes.h" +#include "cannon.h" + +Cannon::Cannon(QCanvas* canvas) : + QCanvasSprite(0, canvas) +{ +shotsfired=0; + index = 8; + cannonx = 0; + cannony = 0; + cannonarray = new QCanvasPixmapArray(); + QString c0 = Resource::findPixmap("parashoot/can0001"); + c0.replace(QRegExp("0001"),"%1"); + cannonarray->readPixmaps(c0,17); + setSequence(cannonarray); + setFrame(index); + move(canvas->width()/2-20, canvas->height()-32); + // co ords for barrel of cannon when upright + barrelypos = canvas->height()-32; + barrelxpos = canvas->width()/2; + movedir = NoDir; + moveDelay = 0; + setAnimated(TRUE); + show(); +} + +void Cannon::advance(int stage) +{ + if ( stage == 1 && moveDelay-- == 0 ) { + if (movedir == Left) { + if (index > 0) { + setFrame(index-1); + index--; + } + } + if (movedir == Right) { + if (index < 16) { + setFrame(index+1); + index++; + } + } + moveDelay = 0; + } +} + +void Cannon::pointCannon(Direction dir) +{ + movedir = dir; + moveDelay = 0; + advance(1); + moveDelay = 1; +} + +void Cannon::setCoords() +{ + switch(index) { + case 0: cannonx = barrelxpos-29; cannony = barrelypos-8; break; + case 1: cannonx = barrelxpos-27; cannony = barrelypos-8; break; + case 2: cannonx = barrelxpos-25; cannony = barrelypos-6; break; + case 3: cannonx = barrelxpos-23; cannony = barrelypos-4; break; + case 4: cannonx = barrelxpos-21; cannony = barrelypos-2; break; + case 5: cannonx = barrelxpos-19; cannony = barrelypos; break; + case 6: cannonx = barrelxpos-15; cannony = barrelypos; break; + case 7: cannonx = barrelxpos-10; cannony = barrelypos; break; + case 8: cannonx = barrelxpos; cannony = barrelypos; break; + case 9: cannonx = barrelxpos+2; cannony = barrelypos; break; + case 10: cannonx = barrelxpos+6; cannony = barrelypos; break; + case 11: cannonx = barrelxpos+8; cannony = barrelypos; break; + case 12: cannonx = barrelxpos+12; cannony = barrelypos-2; break; + case 13: cannonx = barrelxpos+18; cannony = barrelypos-4; break; + case 14: cannonx = barrelxpos+22; cannony = barrelypos-6; break; + case 15: cannonx = barrelxpos+26; cannony = barrelypos-8; break; + case 16: cannonx = barrelxpos+28; cannony = barrelypos-8; break; + } +} + +double Cannon::shootAngle() +{ + switch(index) { + case 0: return 30.0; + case 1: return 37.5; + case 2: return 45.0; + case 3: return 52.5; + case 4: return 60.0; + case 5: return 67.5; + case 6: return 75.0; + case 7: return 82.5; + case 8: return 90.0; + case 9: return 97.5; + case 10: return 105.0; + case 11: return 112.5; + case 12: return 120.0; + case 13: return 127.5; + case 14: return 135.0; + case 15: return 142.5; + case 16: return 150.0; + } + return 0; +} + +void Cannon::shoot() +{ + setCoords(); + Bullet* bullet = new Bullet(canvas(), shootAngle(), cannonx, cannony); + connect(bullet, SIGNAL(score(int)), this, SIGNAL(score(int))); + shotsfired++; +} + +Cannon::~Cannon() +{ +} + +int Cannon::rtti() const +{ + return cannon_rtti; +} diff --git a/noncore/games/parashoot/cannon.h b/noncore/games/parashoot/cannon.h new file mode 100644 index 0000000..44d0c65 --- a/dev/null +++ b/noncore/games/parashoot/cannon.h @@ -0,0 +1,58 @@ +/********************************************************************** +** 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 <qcanvas.h> + +#include "bullet.h" + +class Cannon : public QObject, public QCanvasSprite +{ + Q_OBJECT + +public: + Cannon(QCanvas*); //create cannon + ~Cannon(); //destroy cannon + + enum Direction{ Left, Right, NoDir }; + + void pointCannon(Direction dir); + void setCoords(); + double shootAngle(); + void shoot(); + int rtti() const; + +int shotsFired() { return shotsfired; }; + +protected: + void advance(int stage); + +signals: + void score(int); + +private: + QCanvasPixmapArray* cannonarray; + int index; + int cannonx; + int cannony; + int barrelxpos; + int barrelypos; + int moveDelay; + Direction movedir; + int shotsfired; +}; diff --git a/noncore/games/parashoot/codes.h b/noncore/games/parashoot/codes.h new file mode 100644 index 0000000..68acb3f --- a/dev/null +++ b/noncore/games/parashoot/codes.h @@ -0,0 +1,25 @@ +/********************************************************************** +** 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. +** +**********************************************************************/ + +const int man_rtti = 1500; +const int bullet_rtti = 1600; +const int cannon_rtti = 1700; +const int base_rtti = 1800; +const int helicopter_rtti = 1900; diff --git a/noncore/games/parashoot/helicopter.cpp b/noncore/games/parashoot/helicopter.cpp new file mode 100644 index 0000000..0923124 --- a/dev/null +++ b/noncore/games/parashoot/helicopter.cpp @@ -0,0 +1,114 @@ +/********************************************************************** +** 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 "helicopter.h" +#include "man.h" +#include "codes.h" + +#include <qpe/resource.h> + +#include <qregexp.h> + +static QList<Helicopter> all; + +Helicopter::Helicopter(QCanvas* canvas) : + QCanvasSprite(0, canvas), + chikachika("aland01") +{ + all.append(this); + hits = 0; + QCanvasPixmapArray* helicopterarray = new QCanvasPixmapArray(); + QString h0 = Resource::findPixmap("parashoot/helicopter0001"); + h0.replace(QRegExp("0001"),"%1"); + helicopterarray->readPixmaps(h0,3 ); + setSequence(helicopterarray); + setAnimated(true); + move(canvas->width(), 5); + setVelocity(-2, 0); + chikachika.playLoop(); + show(); +} + +Helicopter::~Helicopter() +{ + all.remove(this); +} + +int fr = 0; + +void Helicopter::advance(int phase) +{ + QCanvasSprite::advance(phase); + if (phase == 0) { + setFrame(fr%3); + fr++; + checkCollision(); + } +} + +void Helicopter::checkCollision() +{ + if (x() == 6) { + setAnimated(false); //setVelocity(0, 0); + dropman(); + } + if (x() < 0) + done(); +} + +void Helicopter::dropman() +{ + (void)new Man(canvas(), 15, 25); + (void)new Man(canvas(), 35, 25); + takeOff(); +} + +void Helicopter::done() +{ + hits++; + if (hits >= 2) { + setAnimated(false); + delete this; + } +} + +void Helicopter::takeOff() +{ + setVelocity(-1, 0); +} + +int Helicopter::rtti() const +{ + return helicopter_rtti; +} + +void Helicopter::silenceAll() +{ + for (Helicopter* h = all.first(); h; h = all.next()) + h->chikachika.stop(); +} + +void Helicopter::deleteAll() +{ + Helicopter* h; + while ((h = all.first())) + delete h; +} + diff --git a/noncore/games/parashoot/helicopter.h b/noncore/games/parashoot/helicopter.h new file mode 100644 index 0000000..5cb92de --- a/dev/null +++ b/noncore/games/parashoot/helicopter.h @@ -0,0 +1,45 @@ +/********************************************************************** +** 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 <qpe/sound.h> + +#include <qcanvas.h> + +class Helicopter : public QCanvasSprite +{ + +public: + Helicopter(QCanvas*); + ~Helicopter(); + void advance(int phase); + void checkCollision(); + void dropman(); + void takeOff(); + void done(); + + static void silenceAll(); + static void deleteAll(); + + int rtti() const; + +private: + int hits; + Sound chikachika; +}; diff --git a/noncore/games/parashoot/interface.cpp b/noncore/games/parashoot/interface.cpp new file mode 100644 index 0000000..84e5e60 --- a/dev/null +++ b/noncore/games/parashoot/interface.cpp @@ -0,0 +1,247 @@ +/********************************************************************** +** 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 "interface.h" +#include "man.h" + +#include <qpe/resource.h> + +#include <qlabel.h> +#include <qmessagebox.h> +#include <qapplication.h> +#include <qstyle.h> +#include <qpe/qpetoolbar.h> +#include <qtoolbutton.h> + +ParaShoot::ParaShoot(QWidget* parent, const char* name, WFlags f) : + QMainWindow(parent,name,f), + canvas(232, 258), + fanfare("level_up"), + score(0) +{ + canvas.setAdvancePeriod(80); + QPixmap bg = Resource::loadPixmap("parashoot/sky"); + canvas.setBackgroundPixmap(bg); + + pb = new QCanvasView(&canvas, this); + pb->setFocus(); + + setToolBarsMovable( FALSE ); + + QPEToolBar* toolbar = new QPEToolBar(this); + toolbar->setHorizontalStretchable( TRUE ); + + setCaption( tr("ParaShoot") ); + QPixmap newicon = Resource::loadPixmap("parashoot/manicon"); + setIcon(newicon); + new QToolButton(newicon, tr("New Game"), 0, + this, SLOT(newGame()), toolbar, "New Game"); + + levelscore = new QLabel(toolbar); + levelscore->setBackgroundMode( PaletteButton ); + levelscore->setAlignment( AlignRight | AlignVCenter | ExpandTabs ); + toolbar->setStretchableWidget( levelscore ); + showScore(0,0); + + setCentralWidget(pb); + + autoDropTimer = new QTimer(this); + connect (autoDropTimer, SIGNAL(timeout()), this, SLOT(play()) ); + + pauseTimer = new QTimer(this); + connect(pauseTimer, SIGNAL(timeout()), this, SLOT(wait()) ); + + setFocusPolicy(StrongFocus); + + newGame(); +} + + +void ParaShoot::resizeEvent(QResizeEvent *) +{ + QSize s = centralWidget()->size(); + int fw = style().defaultFrameWidth(); + canvas.resize( s.width() - fw - 2, s.height() - fw - 2); +} + + +void ParaShoot::showScore( int score, int level ) +{ + levelscore->setText(tr(" Level: %1 Score: %2 ").arg(score).arg(level) ); +} + + +void ParaShoot::newGame() +{ + clear(); + if (pauseTimer->isActive()) + pauseTimer->stop(); + clear(); + Man::setManCount(0); + score = 0; + Bullet::setShotCount(0); + Bullet::setNobullets(0); + nomen = 2; + Bullet::setLimit(nomen); + level = 0; + updatespeed = 80; + showScore(0,0); + gamestopped = false; + Helicopter::deleteAll(); + waitover = true; + base = new Base(&canvas); + cannon = new Cannon(&canvas); + connect( cannon, SIGNAL(score(int)), this, SLOT(increaseScore(int))); + autoDropTimer->start(100); +} + + +void ParaShoot::clear() +{ + autoDropTimer->stop(); +// QCanvasItem* item; + QCanvasItemList l = canvas.allItems(); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + delete *it; + } +} + +void ParaShoot::gameOver() +{ + QCanvasItem* item; + QCanvasItemList l = canvas.allItems(); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + item = *it; + if ((item->rtti()==1500) || (item->rtti()==1600) || item->rtti()==1900) + item->setAnimated(false); + } + autoDropTimer->stop(); + Helicopter::silenceAll(); + + int shots = Bullet::getShotCount(); + + int shotsFired = cannon->shotsFired(); + if ( shotsFired == 0 ) + shotsFired = 1; + QCanvasText* gameover = new QCanvasText( + tr( " GAME OVER!\n" + " Your Score: %1\n" + " Parachuters Killed: %2\n" + " Accuracy: %3% " ).arg(score).arg(shots).arg(shots * 100 / shotsFired ), + &canvas); + gameover->setColor(red); + gameover->setFont( QFont("times", 18, QFont::Bold) ); + gameover->move(canvas.width()/2 -110, canvas.height()/2 -50); + gameover->setZ(500); + gameover->show(); + gamestopped = true; + waitover = false; + pauseTimer->start(3000); +} + +void ParaShoot::wait() +{ + waitover = true; + pauseTimer->stop(); +} + +void ParaShoot::play() +{ + if (Man::getManCount() < nomen ) { + new Man(&canvas); + } + if (Base::baseDestroyed()) { + gameOver(); + return; + } +} + +void ParaShoot::increaseScore(int x) +{ + score += x; + if ( score / 150 != (score-x) / 150 ) + levelUp(); + showScore(level,score); +} + +void ParaShoot::levelUp() +{ + level++; + int stage = level % 3; + switch(stage) { + case 0: + nomen++; + Bullet::setLimit(nomen); + fanfare.play(); + break; + case 1: + new Helicopter(&canvas); + break; + case 2: + moveFaster(); + fanfare.play(); + break; + default: return; + } +} + +void ParaShoot::moveFaster() +{ + if (updatespeed > 50) + updatespeed = updatespeed-5; + else + updatespeed = updatespeed-3; + canvas.setAdvancePeriod(updatespeed); +} + +void ParaShoot::keyPressEvent(QKeyEvent* event) +{ + if (gamestopped) { + if (waitover) + newGame(); + else + return; + } else { + switch(event->key()) { + case Key_Up: + case Key_F1: + case Key_F9: + case Key_Space: + cannon->shoot(); + break; + case Key_Left: + cannon->pointCannon(Cannon::Left); + lastcannonkey=Key_Left; + break; + case Key_Right: + cannon->pointCannon(Cannon::Right); + lastcannonkey=Key_Right; + break; + default: + return; + } + } +} + +void ParaShoot::keyReleaseEvent(QKeyEvent* event) +{ + if ( lastcannonkey == event->key() ) + cannon->pointCannon(Cannon::NoDir); +} diff --git a/noncore/games/parashoot/interface.h b/noncore/games/parashoot/interface.h new file mode 100644 index 0000000..3f36d0b --- a/dev/null +++ b/noncore/games/parashoot/interface.h @@ -0,0 +1,79 @@ +/********************************************************************** +** 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 "cannon.h" +#include "base.h" +#include "helicopter.h" + +#include <qpe/sound.h> + +#include <qmainwindow.h> +#include <qtimer.h> +#include <qlabel.h> + +class QCanvas; +class Helicopter; + +//enum Direction{ +// left, right, up, down }; + +class ParaShoot : public QMainWindow { + Q_OBJECT + +public: + ParaShoot(QWidget* parent=0, const char* name=0, WFlags f=0); + + void clear(); + void gameOver(); + int mancount; + void levelUp(); + void moveFaster(); + +protected: + virtual void keyPressEvent(QKeyEvent*); + virtual void keyReleaseEvent(QKeyEvent*); + virtual void resizeEvent(QResizeEvent *e); + +private slots: + void increaseScore(int); + void newGame(); + void play(); + void wait(); + +private: + void showScore( int score, int level ); + QCanvasView* pb; + QCanvas canvas; + Cannon* cannon; + Base* base; + QCanvasText* gameover; + QLabel* levelscore; + int nomen; + int level; + int oldscore; + int updatespeed; + QTimer* autoDropTimer; + QTimer* pauseTimer; + bool gamestopped; + bool waitover; + Sound fanfare; + int score; + int lastcannonkey; +}; diff --git a/noncore/games/parashoot/main.cpp b/noncore/games/parashoot/main.cpp new file mode 100644 index 0000000..60eea18 --- a/dev/null +++ b/noncore/games/parashoot/main.cpp @@ -0,0 +1,36 @@ +/********************************************************************** +** 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 "interface.h" + +#include <qpe/qpeapplication.h> + +int main(int argc, char **argv) +{ + QPEApplication app(argc,argv); + + QPEApplication::grabKeyboard(); + + ParaShoot m; + QPEApplication::setInputMethodHint( &m, QPEApplication::AlwaysOff ); + app.showMainWidget(&m); + + return app.exec(); +} diff --git a/noncore/games/parashoot/man.cpp b/noncore/games/parashoot/man.cpp new file mode 100644 index 0000000..8435572 --- a/dev/null +++ b/noncore/games/parashoot/man.cpp @@ -0,0 +1,174 @@ +/********************************************************************** +** 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 "codes.h" +#include "man.h" +#include "base.h" + +#include <qpe/resource.h> + +#include <qregexp.h> + +int mancount; + +Man::Man(QCanvas* canvas) : + QCanvasSprite(0, canvas), + splat("lose") +{ + manarray = new QCanvasPixmapArray(); + QString m0 = Resource::findPixmap("parashoot/man0001"); + m0.replace(QRegExp("0001"),"%1"); + manarray->readPixmaps(m0, 7); + setSequence(manarray); + setAnimated(true); + mancount++; + dead = false; + start(); +} + +Man::Man(QCanvas* canvas, int x, int y) : + QCanvasSprite(0, canvas), + splat("bang") +{ + manarray = new QCanvasPixmapArray(); + QString m0 = Resource::findPixmap("parashoot/man0001"); + m0.replace(QString("0001"),"%1"); + manarray->readPixmaps(m0, 7); + setSequence(manarray); + move(x, y); + setFrame(5); + setZ(300); + show(); + + static bool first_time = TRUE; + if (first_time) { + first_time = FALSE; + QTime midnight(0, 0, 0); + srand(midnight.secsTo(QTime::currentTime()) ); + } + int yfallspeed = 0; + yfallspeed = (rand() % 3) + 1; + setVelocity(0, yfallspeed); + + mancount++; + dead = false; +} +int f = 0; + +void Man::advance(int phase) +{ + QCanvasSprite::advance(phase); + if (phase == 0) { + checkCollision(); + if (dead) { + if (count < 10) { + setFrame(6); + setVelocity(0,0); + count++; + } else { + delete this; + return; + } + } + if (y() > canvas()->height()-43) { + setFrame(f%5); + f++; + move(x(), canvas()->height()-26); + setVelocity(-2, 0); + } + } +} + +void Man::setInitialCoords() +{ + static bool first_time = TRUE; + if (first_time) { + first_time = FALSE; + QTime midnight(0, 0, 0); + srand(midnight.secsTo(QTime::currentTime()) ); + } + dx = rand() % (canvas()->width()-16); + dy = -43; //height of a man off the screen +} + +//check if man has reached the base +void Man::checkCollision() +{ + if ( (x() < 23) && (y() == canvas()->height()-26)) { + QCanvasItem* item; + QCanvasItemList l=collisions(FALSE); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + item = *it; + if ( (item->rtti()== 1800) && (item->collidesWith(this)) ) { + Base* base = (Base*) item; + base->damageBase(); + start(); + } + } + } +} + +void Man::start() +{ + setInitialCoords(); + move(dx, dy); + setFrame(5); + setZ(300); + show(); + + static bool first_time = TRUE; + if (first_time) { + first_time = FALSE; + QTime midnight(0, 0, 0); + srand(midnight.secsTo(QTime::currentTime()) ); + } + int yfallspeed = 0; + yfallspeed = (rand() % 3) + 1; + setVelocity(0, yfallspeed); +} + +void Man::done() +{ + splat.play(); + count = 0; + dead = true; + setFrame(6); +} + +int Man::getManCount() +{ + return mancount; +} + +void Man::setManCount(int count) +{ + mancount = count; +} + + +int Man::rtti() const +{ + return man_rtti; +} + +Man::~Man() +{ + mancount--; +} diff --git a/noncore/games/parashoot/man.h b/noncore/games/parashoot/man.h new file mode 100644 index 0000000..e48fc20 --- a/dev/null +++ b/noncore/games/parashoot/man.h @@ -0,0 +1,52 @@ +/********************************************************************** +** 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 <qpe/sound.h> + +#include <qcanvas.h> +#include <qdatetime.h> + +#include <stdlib.h> + +class Man : public QCanvasSprite +{ + +public: + Man (QCanvas*); + Man (QCanvas*, int x, int y); + ~Man(); + void advance(int phase); + void setInitialCoords(); + void checkCollision(); + void start(); + void done(); + static int getManCount(); + static void setManCount(int count); + int rtti() const; +// int mancount; + +private: + QCanvasPixmapArray* manarray; + int dx; + int dy; + bool dead; + int count; + Sound splat; +}; diff --git a/noncore/games/parashoot/parashoot.pro b/noncore/games/parashoot/parashoot.pro new file mode 100644 index 0000000..631560b --- a/dev/null +++ b/noncore/games/parashoot/parashoot.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = interface.h man.h cannon.h base.h bullet.h helicopter.h +SOURCES = main.cpp interface.cpp man.cpp cannon.cpp base.cpp bullet.cpp helicopter.cpp +TARGET = parashoot +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/parashoot.ts diff --git a/noncore/games/parashoot/qpe-parashoot.control b/noncore/games/parashoot/qpe-parashoot.control new file mode 100644 index 0000000..82e9421 --- a/dev/null +++ b/noncore/games/parashoot/qpe-parashoot.control @@ -0,0 +1,9 @@ +Files: bin/parashoot apps/Games/parashoot.desktop pics/parashoot +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: shoot the parachutists + A game for the Qtopia environment. diff --git a/noncore/games/qasteroids/.cvsignore b/noncore/games/qasteroids/.cvsignore new file mode 100644 index 0000000..c152c55 --- a/dev/null +++ b/noncore/games/qasteroids/.cvsignore @@ -0,0 +1,2 @@ +moc_*.cpp +Makefile diff --git a/noncore/games/qasteroids/Makefile.in b/noncore/games/qasteroids/Makefile.in new file mode 100644 index 0000000..7312743 --- a/dev/null +++ b/noncore/games/qasteroids/Makefile.in @@ -0,0 +1,155 @@ +############################################################################# + +####### 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 = qasteroids +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = ledmeter.h \ + sprites.h \ + toplevel.h \ + view.h +SOURCES = ledmeter.cpp \ + toplevel.cpp \ + view.cpp \ + main.cpp +OBJECTS = ledmeter.o \ + toplevel.o \ + view.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_ledmeter.cpp \ + moc_toplevel.cpp \ + moc_view.cpp +OBJMOC = moc_ledmeter.o \ + moc_toplevel.o \ + moc_view.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 qasteroids.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 + +ledmeter.o: ledmeter.cpp \ + ledmeter.h + +toplevel.o: toplevel.cpp \ + toplevel.h \ + view.h \ + sprites.h \ + ledmeter.h \ + $(QPEDIR)/include/qpe/qpeapplication.h \ + $(QPEDIR)/include/qpe/resource.h + +view.o: view.cpp \ + view.h \ + sprites.h \ + $(QPEDIR)/include/qpe/resource.h + +main.o: main.cpp \ + toplevel.h \ + view.h \ + sprites.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_ledmeter.o: moc_ledmeter.cpp \ + ledmeter.h + +moc_toplevel.o: moc_toplevel.cpp \ + toplevel.h \ + view.h \ + sprites.h + +moc_view.o: moc_view.cpp \ + view.h \ + sprites.h + +moc_ledmeter.cpp: ledmeter.h + $(MOC) ledmeter.h -o moc_ledmeter.cpp + +moc_toplevel.cpp: toplevel.h + $(MOC) toplevel.h -o moc_toplevel.cpp + +moc_view.cpp: view.h + $(MOC) view.h -o moc_view.cpp + + diff --git a/noncore/games/qasteroids/ledmeter.cpp b/noncore/games/qasteroids/ledmeter.cpp new file mode 100644 index 0000000..f4d4d1a --- a/dev/null +++ b/noncore/games/qasteroids/ledmeter.cpp @@ -0,0 +1,135 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#include <qpainter.h> +#include "ledmeter.h" + +KALedMeter::KALedMeter( QWidget *parent ) : QFrame( parent ) +{ + mCRanges.setAutoDelete( TRUE ); + mRange = 100; + mCount = 20; + mCurrentCount = 0; + mValue = 0; + setMinimumWidth( mCount * 2 + frameWidth() ); +} + +void KALedMeter::setRange( int r ) +{ + mRange = r; + if ( mRange < 1 ) + mRange = 1; + setValue( mValue ); + update(); +} + +void KALedMeter::setCount( int c ) +{ + mCount = c; + if ( mCount < 1 ) + mCount = 1; + setMinimumWidth( mCount * 2 + frameWidth() ); + calcColorRanges(); + setValue( mValue ); + update(); +} + +void KALedMeter::setValue( int v ) +{ + mValue = v; + if ( mValue > mRange ) + mValue = mRange; + else if ( mValue < 0 ) + mValue = 0; + int c = ( mValue + mRange / mCount - 1 ) * mCount / mRange; + if ( c != mCurrentCount ) + { + mCurrentCount = c; + update(); + } +} + +void KALedMeter::addColorRange( int pc, const QColor &c ) +{ + ColorRange *cr = new ColorRange; + cr->mPc = pc; + cr->mColor = c; + mCRanges.append( cr ); + calcColorRanges(); +} + +void KALedMeter::resizeEvent( QResizeEvent *e ) +{ + QFrame::resizeEvent( e ); + int w = ( width() - frameWidth() - 2 ) / mCount * mCount; + w += frameWidth() + 2; + setFrameRect( QRect( 0, 0, w, height() ) ); +} + +void KALedMeter::drawContents( QPainter *p ) +{ + QRect b = contentsRect(); + + unsigned cidx = 0; + int ncol = mCount; + QColor col = colorGroup().foreground(); + + if ( !mCRanges.isEmpty() ) + { + col = mCRanges.at( cidx )->mColor; + ncol = mCRanges.at( cidx )->mValue; + } + p->setBrush( col ); + p->setPen( col ); + + int lw = b.width() / mCount; + int lx = b.left() + 1; + for ( int i = 0; i < mCurrentCount; i++, lx += lw ) + { + if ( i > ncol ) + { + if ( ++cidx < mCRanges.count() ) + { + col = mCRanges.at( cidx )->mColor; + ncol = mCRanges.at( cidx )->mValue; + p->setBrush( col ); + p->setPen( col ); + } + } + + p->drawRect( lx, b.top() + 1, lw - 1, b.height() - 2 ); + } +} + +void KALedMeter::calcColorRanges() +{ + int prev = 0; + ColorRange *cr; + for ( cr = mCRanges.first(); cr; cr = mCRanges.next() ) + { + cr->mValue = prev + cr->mPc * mCount / 100; + prev = cr->mValue; + } +} + diff --git a/noncore/games/qasteroids/ledmeter.h b/noncore/games/qasteroids/ledmeter.h new file mode 100644 index 0000000..b2f06c1 --- a/dev/null +++ b/noncore/games/qasteroids/ledmeter.h @@ -0,0 +1,72 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#ifndef __LEDMETER_H__ +#define __LEDMETER_H__ + +#include <qframe.h> +#include <qlist.h> + +#define QPtrList QList + +class KALedMeter : public QFrame +{ + Q_OBJECT +public: + KALedMeter( QWidget *parent ); + + int range() const { return mRange; } + void setRange( int r ); + + int count() const { return mCount; } + void setCount( int c ); + + int value () const { return mValue; } + + void addColorRange( int pc, const QColor &c ); + +public slots: + void setValue( int v ); + +protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void drawContents( QPainter * ); + void calcColorRanges(); + +protected: + struct ColorRange + { + int mPc; + int mValue; + QColor mColor; + }; + + int mRange; + int mCount; + int mCurrentCount; + int mValue; + QPtrList<ColorRange> mCRanges; +}; + +#endif diff --git a/noncore/games/qasteroids/main.cpp b/noncore/games/qasteroids/main.cpp new file mode 100644 index 0000000..7d1682c --- a/dev/null +++ b/noncore/games/qasteroids/main.cpp @@ -0,0 +1,36 @@ +/********************************************************************** +** 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 "toplevel.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char *argv[] ) +{ + QPEApplication app( argc, argv ); + + QPEApplication::grabKeyboard(); + + KAstTopLevel *mainWidget = new KAstTopLevel(); + app.showMainWidget( mainWidget ); + + app.exec(); +} + diff --git a/noncore/games/qasteroids/qasteroids.pro b/noncore/games/qasteroids/qasteroids.pro new file mode 100644 index 0000000..14a0901 --- a/dev/null +++ b/noncore/games/qasteroids/qasteroids.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = ledmeter.h sprites.h toplevel.h view.h +SOURCES = ledmeter.cpp toplevel.cpp view.cpp main.cpp +TARGET = qasteroids +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/qasteroids.ts diff --git a/noncore/games/qasteroids/qpe-qasteroids.control b/noncore/games/qasteroids/qpe-qasteroids.control new file mode 100644 index 0000000..c1b328e --- a/dev/null +++ b/noncore/games/qasteroids/qpe-qasteroids.control @@ -0,0 +1,9 @@ +Files: bin/qasteroids apps/Games/qasteroids.desktop pics/qasteroids pics/Asteroids.png +Priority: optional +Section: qpe/games +Maintainer: Martin Jones <mjones@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: shoot the asteroids + A game for the Qtopia environment. diff --git a/noncore/games/qasteroids/sprites.h b/noncore/games/qasteroids/sprites.h new file mode 100644 index 0000000..0827821 --- a/dev/null +++ b/noncore/games/qasteroids/sprites.h @@ -0,0 +1,147 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#ifndef __SPRITES_H__ +#define __SPRITES_H__ + +#include <qcanvas.h> + +#define ID_ROCK_LARGE 1024 +#define ID_ROCK_MEDIUM 1025 +#define ID_ROCK_SMALL 1026 + +#define ID_MISSILE 1030 + +#define ID_BIT 1040 +#define ID_EXHAUST 1041 + +#define ID_ENERGY_POWERUP 1310 +#define ID_TELEPORT_POWERUP 1311 +#define ID_BRAKE_POWERUP 1312 +#define ID_SHIELD_POWERUP 1313 +#define ID_SHOOT_POWERUP 1314 + +#define ID_SHIP 1350 +#define ID_SHIELD 1351 + +#define MAX_SHIELD_AGE 350 +#define MAX_POWERUP_AGE 500 +#define MAX_MISSILE_AGE 20 + +class KMissile : public QCanvasSprite +{ +public: + KMissile( QCanvasPixmapArray *s, QCanvas *c ) : QCanvasSprite( s, c ) + { myAge = 0; } + + virtual int rtti() const { return ID_MISSILE; } + + void growOlder() { myAge++; } + bool expired() { return myAge > MAX_MISSILE_AGE; } + +private: + int myAge; +}; + +class KBit : public QCanvasSprite +{ +public: + KBit( QCanvasPixmapArray *s, QCanvas *c ) : QCanvasSprite( s, c ) + { death = 7; } + + virtual int rtti() const { return ID_BIT; } + + void setDeath( int d ) { death = d; } + void growOlder() { death--; } + bool expired() { return death <= 0; } + +private: + int death; +}; + +class KExhaust : public QCanvasSprite +{ +public: + KExhaust( QCanvasPixmapArray *s, QCanvas *c ) : QCanvasSprite( s, c ) + { death = 1; } + + virtual int rtti() const { return ID_EXHAUST; } + + void setDeath( int d ) { death = d; } + void growOlder() { death--; } + bool expired() { return death <= 0; } + +private: + int death; +}; + +class KPowerup : public QCanvasSprite +{ +public: + KPowerup( QCanvasPixmapArray *s, QCanvas *c, int t ) : QCanvasSprite( s, c ), + myAge( 0 ), type(t) { } + + virtual int rtti() const { return type; } + + void growOlder() { myAge++; } + bool expired() const { return myAge > MAX_POWERUP_AGE; } + +protected: + int myAge; + int type; +}; + +class KRock : public QCanvasSprite +{ +public: + KRock (QCanvasPixmapArray *s, QCanvas *c, int t, int sk, int st) : QCanvasSprite( s, c ) + { type = t; skip = cskip = sk; step = st; } + + void nextFrame() + { + if (cskip-- <= 0) { + setFrame( (frame()+step+frameCount())%frameCount() ); + cskip = QABS(skip); + } + } + + virtual int rtti() const { return type; } + +private: + int type; + int skip; + int cskip; + int step; +}; + +class KShield : public QCanvasSprite +{ +public: + KShield( QCanvasPixmapArray *s, QCanvas *c ) + : QCanvasSprite( s, c ) {} + + virtual int rtti() const { return ID_SHIELD; } +}; + +#endif diff --git a/noncore/games/qasteroids/toplevel.cpp b/noncore/games/qasteroids/toplevel.cpp new file mode 100644 index 0000000..57242a0 --- a/dev/null +++ b/noncore/games/qasteroids/toplevel.cpp @@ -0,0 +1,514 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ +// --- toplevel.cpp --- + +#include "toplevel.h" +#include "ledmeter.h" + +#include <qpe/qpeapplication.h> +#include <qpe/resource.h> + +#include <qaccel.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlcdnumber.h> +#include <qpushbutton.h> + + +#define SB_SCORE 1 +#define SB_LEVEL 2 +#define SB_SHIPS 3 + +struct SLevel +{ + int nrocks; + double rockSpeed; +}; + +#define MAX_LEVELS 16 + +SLevel levels[MAX_LEVELS] = +{ + { 1, 0.4 }, + { 1, 0.6 }, + { 2, 0.5 }, + { 2, 0.7 }, + { 2, 0.8 }, + { 3, 0.6 }, + { 3, 0.7 }, + { 3, 0.8 }, + { 4, 0.6 }, + { 4, 0.7 }, + { 4, 0.8 }, + { 5, 0.7 }, + { 5, 0.8 }, + { 5, 0.9 }, + { 5, 1.0 } +}; + +const char *soundEvents[] = +{ + "ShipDestroyed", + "RockDestroyed", + 0 +}; + +const char *soundDefaults[] = +{ + "Explosion.wav", + "ploop.wav", + 0 +}; + + +KAstTopLevel::KAstTopLevel( QWidget *parent, const char *name ) + : QMainWindow( parent, name ) +{ + setCaption( tr("Asteroids") ); + QWidget *border = new QWidget( this ); + border->setBackgroundColor( black ); + setCentralWidget( border ); + + QVBoxLayout *borderLayout = new QVBoxLayout( border ); + + QWidget *mainWin = new QWidget( border ); + borderLayout->addWidget( mainWin, 2, AlignHCenter ); + + view = new KAsteroidsView( mainWin ); + connect( view, SIGNAL( shipKilled() ), SLOT( slotShipKilled() ) ); + connect( view, SIGNAL( rockHit(int) ), SLOT( slotRockHit(int) ) ); + connect( view, SIGNAL( rocksRemoved() ), SLOT( slotRocksRemoved() ) ); + connect( view, SIGNAL( updateVitals() ), SLOT( slotUpdateVitals() ) ); + + QVBoxLayout *vb = new QVBoxLayout( mainWin ); + QHBoxLayout *hb = new QHBoxLayout; + QHBoxLayout *hbd = new QHBoxLayout; + vb->addLayout( hb ); + + QFont labelFont( "helvetica", 12 ); + QColorGroup grp( darkGreen, black, QColor( 128, 128, 128 ), + QColor( 64, 64, 64 ), black, darkGreen, black ); + QPalette pal( grp, grp, grp ); + + mainWin->setPalette( pal ); + + QLabel *label; + label = new QLabel( tr("Score"), mainWin ); + label->setFont( labelFont ); + label->setPalette( pal ); +// label->setFixedWidth( label->sizeHint().width() ); + hb->addWidget( label ); + + scoreLCD = new QLCDNumber( 5, mainWin ); + scoreLCD->setFrameStyle( QFrame::NoFrame ); + scoreLCD->setSegmentStyle( QLCDNumber::Flat ); + scoreLCD->setFixedHeight( 16 ); + scoreLCD->setPalette( pal ); + hb->addWidget( scoreLCD ); + hb->addStretch( 1 ); + + label = new QLabel( tr("Level"), mainWin ); + label->setFont( labelFont ); + label->setPalette( pal ); +// label->setFixedWidth( label->sizeHint().width() ); + hb->addWidget( label ); + + levelLCD = new QLCDNumber( 2, mainWin ); + levelLCD->setFrameStyle( QFrame::NoFrame ); + levelLCD->setSegmentStyle( QLCDNumber::Flat ); + levelLCD->setFixedHeight( 16 ); + levelLCD->setPalette( pal ); + hb->addWidget( levelLCD ); + hb->addStretch( 1 ); + + label = new QLabel( tr("Ships"), mainWin ); + label->setFont( labelFont ); +// label->setFixedWidth( label->sizeHint().width() ); + label->setPalette( pal ); + hb->addWidget( label ); + + shipsLCD = new QLCDNumber( 1, mainWin ); + shipsLCD->setFrameStyle( QFrame::NoFrame ); + shipsLCD->setSegmentStyle( QLCDNumber::Flat ); + shipsLCD->setFixedHeight( 16 ); + shipsLCD->setPalette( pal ); + hb->addWidget( shipsLCD ); + +// hb->addStrut( 14 ); + + vb->addWidget( view, 10 ); + +// -- bottom layout: + vb->addLayout( hbd ); + + QFont smallFont( "helvetica", 12 ); + hbd->addSpacing( 5 ); + +/* + label = new QLabel( tr( "T" ), mainWin ); + label->setFont( smallFont ); + label->setFixedWidth( label->sizeHint().width() ); + label->setPalette( pal ); + hbd->addWidget( label ); + + teleportsLCD = new QLCDNumber( 1, mainWin ); + teleportsLCD->setFrameStyle( QFrame::NoFrame ); + teleportsLCD->setSegmentStyle( QLCDNumber::Flat ); + teleportsLCD->setPalette( pal ); + teleportsLCD->setFixedHeight( 18 ); + hbd->addWidget( teleportsLCD ); + + hbd->addSpacing( 10 ); +*/ + label = new QLabel( mainWin ); + label->setPixmap( Resource::loadPixmap("qasteroids/powerups/brake.png") ); + label->setFixedWidth( 16 ); + label->setPalette( pal ); + hbd->addWidget( label ); + + brakesLCD = new QLCDNumber( 1, mainWin ); + brakesLCD->setFrameStyle( QFrame::NoFrame ); + brakesLCD->setSegmentStyle( QLCDNumber::Flat ); + brakesLCD->setPalette( pal ); + brakesLCD->setFixedHeight( 16 ); + hbd->addWidget( brakesLCD ); + + hbd->addSpacing( 5 ); + + label = new QLabel( mainWin ); + label->setPixmap( Resource::loadPixmap("qasteroids/powerups/shield.png") ); + label->setFixedWidth( 16 ); + label->setPalette( pal ); + hbd->addWidget( label ); + + shieldLCD = new QLCDNumber( 1, mainWin ); + shieldLCD->setFrameStyle( QFrame::NoFrame ); + shieldLCD->setSegmentStyle( QLCDNumber::Flat ); + shieldLCD->setPalette( pal ); + shieldLCD->setFixedHeight( 16 ); + hbd->addWidget( shieldLCD ); + + hbd->addSpacing( 5 ); + + label = new QLabel( mainWin ); + label->setPixmap( Resource::loadPixmap("qasteroids/powerups/shoot.png") ); + label->setFixedWidth( 16 ); + label->setPalette( pal ); + hbd->addWidget( label ); + + shootLCD = new QLCDNumber( 1, mainWin ); + shootLCD->setFrameStyle( QFrame::NoFrame ); + shootLCD->setSegmentStyle( QLCDNumber::Flat ); + shootLCD->setPalette( pal ); + shootLCD->setFixedHeight( 16 ); + hbd->addWidget( shootLCD ); + + hbd->addStretch( 1 ); + + label = new QLabel( tr( "Fuel" ), mainWin ); + label->setFont( smallFont ); + label->setFixedWidth( label->sizeHint().width() + 5 ); + label->setPalette( pal ); + hbd->addWidget( label ); + + powerMeter = new KALedMeter( mainWin ); + powerMeter->setFrameStyle( QFrame::Box | QFrame::Plain ); + powerMeter->setRange( MAX_POWER_LEVEL ); + powerMeter->addColorRange( 10, darkRed ); + powerMeter->addColorRange( 20, QColor(160, 96, 0) ); + powerMeter->addColorRange( 70, darkGreen ); + powerMeter->setCount( 15 ); + powerMeter->setPalette( pal ); + powerMeter->setFixedSize( 60, 12 ); + hbd->addWidget( powerMeter ); + + shipsRemain = 3; + showHiscores = FALSE; + + actions.insert( Qt::Key_Up, Thrust ); + actions.insert( Qt::Key_Left, RotateLeft ); + actions.insert( Qt::Key_Right, RotateRight ); + actions.insert( Qt::Key_Enter, Shoot ); + actions.insert( Qt::Key_Z, Teleport ); + actions.insert( Qt::Key_Down, Brake ); + actions.insert( Qt::Key_P, Pause ); + actions.insert( Key_F12, Launch ); + actions.insert( Key_F11, Shield ); + actions.insert( Key_F9, NewGame ); + +// actions.insert( Qt::Key_S, Shield ); +// actions.insert( Qt::Key_X, Brake ); +// actions.insert( Qt::Key_L, Launch ); + actions.insert( Qt::Key_Space, Shoot ); + + view->showText( tr( "Press Calendar to start playing" ), yellow ); + + setFocusPolicy( StrongFocus ); + + slotNewGame(); +} + +KAstTopLevel::~KAstTopLevel() +{ +} + +void KAstTopLevel::playSound( const char * ) +{ +} + +void KAstTopLevel::keyPressEvent( QKeyEvent *event ) +{ + if ( event->isAutoRepeat() || !actions.contains( event->key() ) ) + { + event->ignore(); + return; + } + + Action a = actions[ event->key() ]; + + switch ( a ) + { + case RotateLeft: + view->rotateLeft( TRUE ); + break; + + case RotateRight: + view->rotateRight( TRUE ); + break; + + case Thrust: + view->thrust( TRUE ); + break; + + case Shoot: + view->shoot( TRUE ); + break; + + case Shield: + view->setShield( TRUE ); + break; + + case Teleport: + view->teleport( TRUE ); + break; + + case Brake: + view->brake( TRUE ); + break; + + default: + event->ignore(); + return; + } + event->accept(); +} + +void KAstTopLevel::keyReleaseEvent( QKeyEvent *event ) +{ + if ( event->isAutoRepeat() || !actions.contains( event->key() ) ) + { + event->ignore(); + return; + } + + Action a = actions[ event->key() ]; + + switch ( a ) + { + case RotateLeft: + view->rotateLeft( FALSE ); + break; + + case RotateRight: + view->rotateRight( FALSE ); + break; + + case Thrust: + view->thrust( FALSE ); + break; + + case Shoot: + view->shoot( FALSE ); + break; + + case Brake: + view->brake( FALSE ); + break; + + case Shield: + view->setShield( FALSE ); + break; + + case Teleport: + view->teleport( FALSE ); + break; + + case Launch: + if ( waitShip ) + { + view->newShip(); + waitShip = FALSE; + view->hideText(); + } + else + { + event->ignore(); + return; + } + break; + + case NewGame: + slotNewGame(); + break; +/* + case Pause: + { + view->pause( TRUE ); + QMessageBox::information( this, + tr("KAsteroids is paused"), + tr("Paused") ); + view->pause( FALSE ); + } + break; +*/ + default: + event->ignore(); + return; + } + + event->accept(); +} + +void KAstTopLevel::showEvent( QShowEvent *e ) +{ + QMainWindow::showEvent( e ); + view->pause( FALSE ); + setFocus(); +} + +void KAstTopLevel::hideEvent( QHideEvent *e ) +{ + QMainWindow::hideEvent( e ); + view->pause( TRUE ); +} + +void KAstTopLevel::focusInEvent( QFocusEvent * ) +{ + view->pause( FALSE ); + setFocus(); +} + +void KAstTopLevel::focusOutEvent( QFocusEvent * ) +{ + view->pause( TRUE ); +} + +void KAstTopLevel::slotNewGame() +{ + shipsRemain = 3; + score = 0; + scoreLCD->display( 0 ); + level = 0; + levelLCD->display( level+1 ); + shipsLCD->display( shipsRemain-1 ); + view->newGame(); + view->setRockSpeed( levels[0].rockSpeed ); + view->addRocks( levels[0].nrocks ); + view->newShip(); + waitShip = FALSE; + view->hideText(); + isPaused = FALSE; +} + +void KAstTopLevel::slotShipKilled() +{ + shipsRemain--; + shipsLCD->display( shipsRemain-1 ); + + playSound( "ShipDestroyed" ); + + if ( shipsRemain > 0 ) + { + waitShip = TRUE; + view->showText( tr( "Ship Destroyed.\nPress Launch/Home key."), yellow ); + } + else + { + view->endGame(); + doStats(); + } +} + +void KAstTopLevel::slotRockHit( int size ) +{ + switch ( size ) + { + case 0: + score += 10; + break; + + case 1: + score += 20; + break; + + default: + score += 40; + } + + playSound( "RockDestroyed" ); + + scoreLCD->display( score ); +} + +void KAstTopLevel::slotRocksRemoved() +{ + level++; + + if ( level >= MAX_LEVELS ) + level = MAX_LEVELS - 1; + + view->setRockSpeed( levels[level-1].rockSpeed ); + view->addRocks( levels[level-1].nrocks ); + + levelLCD->display( level+1 ); +} + +void KAstTopLevel::doStats() +{ + QString r( "0.00" ); + if ( view->shots() ) + r = QString::number( (double)view->hits() / view->shots() * 100.0, + 'g', 2 ); + + view->showText( tr( "Game Over.\nPress Calendar for a new game." ), yellow, FALSE ); +} + +void KAstTopLevel::slotUpdateVitals() +{ + brakesLCD->display( view->brakeCount() ); + shieldLCD->display( view->shieldCount() ); + shootLCD->display( view->shootCount() ); +// teleportsLCD->display( view->teleportCount() ); + powerMeter->setValue( view->power() ); +} diff --git a/noncore/games/qasteroids/toplevel.h b/noncore/games/qasteroids/toplevel.h new file mode 100644 index 0000000..4e1ac9c --- a/dev/null +++ b/noncore/games/qasteroids/toplevel.h @@ -0,0 +1,99 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#ifndef __KAST_TOPLEVEL_H__ +#define __KAST_TOPLEVEL_H__ + +#include <qmainwindow.h> +#include <qdict.h> +#include <qmap.h> + +#include "view.h" + + +class KALedMeter; +class QLCDNumber; + +class KAstTopLevel : public QMainWindow +{ + Q_OBJECT +public: + KAstTopLevel( QWidget *parent=0, const char *name=0 ); + virtual ~KAstTopLevel(); + +private: + void playSound( const char *snd ); + void readSoundMapping(); + void doStats(); + +protected: + virtual void showEvent( QShowEvent * ); + virtual void hideEvent( QHideEvent * ); + virtual void keyPressEvent( QKeyEvent *event ); + virtual void keyReleaseEvent( QKeyEvent *event ); + virtual void focusInEvent( QFocusEvent *event ); + virtual void focusOutEvent( QFocusEvent *event ); + +private slots: + void slotNewGame(); + + void slotShipKilled(); + void slotRockHit( int size ); + void slotRocksRemoved(); + + void slotUpdateVitals(); + +private: + KAsteroidsView *view; + QLCDNumber *scoreLCD; + QLCDNumber *levelLCD; + QLCDNumber *shipsLCD; + + QLCDNumber *teleportsLCD; +// QLCDNumber *bombsLCD; + QLCDNumber *brakesLCD; + QLCDNumber *shieldLCD; + QLCDNumber *shootLCD; + KALedMeter *powerMeter; + + bool sound; + QDict<QString> soundDict; + + // waiting for user to press Enter to launch a ship + bool waitShip; + bool isPaused; + + int shipsRemain; + int score; + int level; + bool showHiscores; + + enum Action { Launch, Thrust, RotateLeft, RotateRight, Shoot, Teleport, + Brake, Shield, Pause, NewGame }; + + QMap<int,Action> actions; +}; + +#endif + diff --git a/noncore/games/qasteroids/view.cpp b/noncore/games/qasteroids/view.cpp new file mode 100644 index 0000000..ef08343 --- a/dev/null +++ b/noncore/games/qasteroids/view.cpp @@ -0,0 +1,884 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#include "view.h" + +#include <qpe/resource.h> + +#include <qapplication.h> +#include <qkeycode.h> +#include <qaccel.h> + +#include <stdlib.h> +#include <math.h> + +#define IMG_BACKGROUND "qasteroids/bg.png" + +#define REFRESH_DELAY 33 +#define SHIP_SPEED 0.3 +#define MISSILE_SPEED 10.0 +#define SHIP_STEPS 64 +#define ROTATE_RATE 2 +#define SHIELD_ON_COST 1 +#define SHIELD_HIT_COST 30 +#define BRAKE_ON_COST 4 + +#define MAX_ROCK_SPEED 2.5 +#define MAX_POWERUP_SPEED 1.5 +#define MAX_SHIP_SPEED 8 +#define MAX_BRAKES 5 +#define MAX_SHIELDS 5 +#define MAX_FIREPOWER 5 + +#define TEXT_SPEED 4 + +#define PI_X_2 6.283185307 +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +struct +{ + int id; + const char *path; + int frames; +} +kas_animations [] = +{ +// { ID_ROCK_LARGE, "rock1/rock1\%1.png", 32 }, + { ID_ROCK_MEDIUM, "rock2/rock2\%1.png", 32 }, + { ID_ROCK_SMALL, "rock3/rock3\%1.png", 32 }, + { ID_SHIP, "ship/ship\%1.png", 32 }, + { ID_MISSILE, "missile/missile.png", 1 }, + { ID_BIT, "bits/bits\%1.png", 16 }, + { ID_EXHAUST, "exhaust/exhaust.png", 1 }, + { ID_ENERGY_POWERUP, "powerups/energy.png", 1 }, +// { ID_TELEPORT_POWERUP, "powerups/teleport%1.png", 12 }, + { ID_BRAKE_POWERUP, "powerups/brake.png", 1 }, + { ID_SHIELD_POWERUP, "powerups/shield.png", 1 }, + { ID_SHOOT_POWERUP, "powerups/shoot.png", 1 }, + { ID_SHIELD, "shield/shield\%1.png", 6 }, + { 0, 0, 0 } +}; + + + +KAsteroidsView::KAsteroidsView( QWidget *parent, const char *name ) + : QWidget( parent, name ), + field(200, 200), + view(&field,this) +{ + view.setVScrollBarMode( QScrollView::AlwaysOff ); + view.setHScrollBarMode( QScrollView::AlwaysOff ); + rocks.setAutoDelete( TRUE ); + missiles.setAutoDelete( TRUE ); + bits.setAutoDelete( TRUE ); + powerups.setAutoDelete( TRUE ); + exhaust.setAutoDelete( TRUE ); + + QPixmap pm( Resource::loadPixmap(IMG_BACKGROUND) ); + field.setBackgroundPixmap( pm ); + + textSprite = new QCanvasText( &field ); + QFont font( "helvetica", 14 ); + textSprite->setFont( font ); + + shield = 0; + shieldOn = FALSE; + refreshRate = REFRESH_DELAY; + + readSprites(); + + shieldTimer = new QTimer( this ); + connect( shieldTimer, SIGNAL(timeout()), this, SLOT(hideShield()) ); + mTimerId = -1; + + shipPower = MAX_POWER_LEVEL; + vitalsChanged = TRUE; + can_destroy_powerups = FALSE; + + mPaused = TRUE; +} + +// - - - + +KAsteroidsView::~KAsteroidsView() +{ +} + +// - - - + +void KAsteroidsView::reset() +{ + rocks.clear(); + missiles.clear(); + bits.clear(); + powerups.clear(); + exhaust.clear(); + + shotsFired = 0; + shotsHit = 0; + + rockSpeed = 1.0; + powerupSpeed = 1.0; + mFrameNum = 0; + mPaused = FALSE; + + ship->hide(); + shield->hide(); +/* + if ( mTimerId >= 0 ) { + killTimer( mTimerId ); + mTimerId = -1; + } +*/ +} + +// - -- + +void KAsteroidsView::newGame() +{ + if ( shieldOn ) + { + shield->hide(); + shieldOn = FALSE; + } + reset(); + if ( mTimerId < 0 ) + mTimerId = startTimer( REFRESH_DELAY ); + emit updateVitals(); +} + +// - - - + +void KAsteroidsView::endGame() +{ +} + +void KAsteroidsView::pause( bool p ) +{ + if ( !mPaused && p ) { + if ( mTimerId >= 0 ) { + killTimer( mTimerId ); + mTimerId = -1; + } + } else if ( mPaused && !p ) + mTimerId = startTimer( REFRESH_DELAY ); + mPaused = p; +} + +// - - - + +void KAsteroidsView::newShip() +{ + ship->move( field.width()/2, field.height()/2, 0 ); + shield->move( field.width()/2, field.height()/2, 0 ); + ship->setVelocity( 0.0, 0.0 ); + shipDx = 0; + shipDy = 0; + shipAngle = 0; + rotateL = FALSE; + rotateR = FALSE; + thrustShip = FALSE; + shootShip = FALSE; + brakeShip = FALSE; + teleportShip = FALSE; + shieldOn = TRUE; + shootDelay = 0; + shipPower = MAX_POWER_LEVEL; + rotateRate = ROTATE_RATE; + rotateSlow = 0; + + mBrakeCount = 0; + mTeleportCount = 0; + mShootCount = 0; + + ship->show(); + shield->show(); + mShieldCount = 1; // just in case the ship appears on a rock. + shieldTimer->start( 1000, TRUE ); +} + +void KAsteroidsView::setShield( bool s ) +{ + if ( shieldTimer->isActive() && !s ) { + shieldTimer->stop(); + hideShield(); + } else { + shieldOn = s && mShieldCount; + } +} + +void KAsteroidsView::brake( bool b ) +{ + if ( mBrakeCount ) + { + if ( brakeShip && !b ) + { + rotateL = FALSE; + rotateR = FALSE; + thrustShip = FALSE; + rotateRate = ROTATE_RATE; + } + + brakeShip = b; + } +} + +// - - - + +void KAsteroidsView::readSprites() +{ + QString sprites_prefix = Resource::findPixmap( IMG_BACKGROUND ); + int sep = sprites_prefix.findRev( "/" ); + + sprites_prefix.truncate( sep ); + + int i = 0; + while ( kas_animations[i].id ) + { + animation.insert( kas_animations[i].id, + new QCanvasPixmapArray( sprites_prefix + "/" + kas_animations[i].path, + kas_animations[i].frames ) ); + i++; + } + + ship = new QCanvasSprite( animation[ID_SHIP], &field ); + ship->hide(); + + shield = new KShield( animation[ID_SHIELD], &field ); + shield->hide(); +} + +// - - - + +void KAsteroidsView::addRocks( int num ) +{ + for ( int i = 0; i < num; i++ ) + { + KRock *rock = new KRock( animation[ID_ROCK_MEDIUM], &field, + ID_ROCK_MEDIUM, randInt(2), randInt(2) ? -1 : 1 ); + double dx = (2.0 - randDouble()*4.0) * rockSpeed; + double dy = (2.0 - randDouble()*4.0) * rockSpeed; + rock->setVelocity( dx, dy ); + rock->setFrame( randInt( rock->frameCount() ) ); + if ( dx > 0 ) + { + if ( dy > 0 ) + rock->move( 5, 5, 0 ); + else + rock->move( 5, field.height() - 25, 0 ); + } + else + { + if ( dy > 0 ) + rock->move( field.width() - 25, 5, 0 ); + else + rock->move( field.width() - 25, field.height() - 25, 0 ); + } + rock->show( ); + rocks.append( rock ); + } +} + +// - - - + +void KAsteroidsView::showText( const QString &text, const QColor &color, bool scroll ) +{ + textSprite->setTextFlags( AlignLeft | AlignVCenter ); + textSprite->setText( text ); + textSprite->setColor( color ); + + if ( scroll ) { + textSprite->move( (field.width()-textSprite->boundingRect().width()) / 2, + -textSprite->boundingRect().height() ); + textDy = TEXT_SPEED; + } else { + textSprite->move( (field.width()-textSprite->boundingRect().width()) / 2, + (field.height()-textSprite->boundingRect().height()) / 2 ); + textDy = 0; + } + textSprite->show(); +} + +// - - - + +void KAsteroidsView::hideText() +{ + textDy = -TEXT_SPEED; +} + +// - - - + +void KAsteroidsView::resizeEvent(QResizeEvent* event) +{ + QWidget::resizeEvent(event); + field.resize(width()-4, height()-4); + view.resize(width(),height()); +} + +// - - - + +void KAsteroidsView::timerEvent( QTimerEvent * ) +{ + field.advance(); + + QCanvasSprite *rock; + + // move rocks forward + for ( rock = rocks.first(); rock; rock = rocks.next() ) { + ((KRock *)rock)->nextFrame(); + wrapSprite( rock ); + } + + wrapSprite( ship ); + + // check for missile collision with rocks. + processMissiles(); + + // these are generated when a ship explodes + for ( KBit *bit = bits.first(); bit; bit = bits.next() ) + { + if ( bit->expired() ) + { + bits.removeRef( bit ); + } + else + { + bit->growOlder(); + bit->setFrame( ( bit->frame()+1 ) % bit->frameCount() ); + } + } + + for ( KExhaust *e = exhaust.first(); e; e = exhaust.next() ) + exhaust.removeRef( e ); + + // move / rotate ship. + // check for collision with a rock. + processShip(); + + // move powerups and check for collision with player and missiles + processPowerups(); + + if ( textSprite->visible() ) + { + if ( textDy < 0 && + textSprite->boundingRect().y() <= -textSprite->boundingRect().height() ) { + textSprite->hide(); + } else { + textSprite->moveBy( 0, textDy ); + } + if ( textSprite->boundingRect().y() > (field.height()-textSprite->boundingRect().height())/2 ) + textDy = 0; + } + + if ( vitalsChanged && !(mFrameNum % 10) ) { + emit updateVitals(); + vitalsChanged = FALSE; + } + + mFrameNum++; +} + +void KAsteroidsView::wrapSprite( QCanvasItem *s ) +{ + int x = int(s->x() + s->boundingRect().width() / 2); + int y = int(s->y() + s->boundingRect().height() / 2); + + if ( x > field.width() ) + s->move( s->x() - field.width(), s->y() ); + else if ( x < 0 ) + s->move( field.width() + s->x(), s->y() ); + + if ( y > field.height() ) + s->move( s->x(), s->y() - field.height() ); + else if ( y < 0 ) + s->move( s->x(), field.height() + s->y() ); +} + +// - - - + +void KAsteroidsView::rockHit( QCanvasItem *hit ) +{ + KPowerup *nPup = 0; + int rnd = static_cast<int>(randDouble()*30.0) % 30; + switch( rnd ) + { + case 4: + case 5: + nPup = new KPowerup( animation[ID_ENERGY_POWERUP], &field, + ID_ENERGY_POWERUP ); + break; + case 10: +// nPup = new KPowerup( animation[ID_TELEPORT_POWERUP], &field, +// ID_TELEPORT_POWERUP ); + break; + case 15: + nPup = new KPowerup( animation[ID_BRAKE_POWERUP], &field, + ID_BRAKE_POWERUP ); + break; + case 20: + nPup = new KPowerup( animation[ID_SHIELD_POWERUP], &field, + ID_SHIELD_POWERUP ); + break; + case 24: + case 25: + nPup = new KPowerup( animation[ID_SHOOT_POWERUP], &field, + ID_SHOOT_POWERUP ); + break; + } + if ( nPup ) + { + double r = 0.5 - randDouble(); + nPup->move( hit->x(), hit->y(), 0 ); + nPup->setVelocity( hit->xVelocity() + r, hit->yVelocity() + r ); + nPup->show( ); + powerups.append( nPup ); + } + + if ( hit->rtti() == ID_ROCK_LARGE || hit->rtti() == ID_ROCK_MEDIUM ) + { + // break into smaller rocks + double addx[4] = { 1.0, 1.0, -1.0, -1.0 }; + double addy[4] = { -1.0, 1.0, -1.0, 1.0 }; + + double dx = hit->xVelocity(); + double dy = hit->yVelocity(); + + double maxRockSpeed = MAX_ROCK_SPEED * rockSpeed; + if ( dx > maxRockSpeed ) + dx = maxRockSpeed; + else if ( dx < -maxRockSpeed ) + dx = -maxRockSpeed; + if ( dy > maxRockSpeed ) + dy = maxRockSpeed; + else if ( dy < -maxRockSpeed ) + dy = -maxRockSpeed; + + QCanvasSprite *nrock; + + for ( int i = 0; i < 4; i++ ) + { + double r = rockSpeed/2 - randDouble()*rockSpeed; + if ( hit->rtti() == ID_ROCK_LARGE ) + { + nrock = new KRock( animation[ID_ROCK_MEDIUM], &field, + ID_ROCK_MEDIUM, randInt(2), randInt(2) ? -1 : 1 ); + emit rockHit( 0 ); + } + else + { + nrock = new KRock( animation[ID_ROCK_SMALL], &field, + ID_ROCK_SMALL, randInt(2), randInt(2) ? -1 : 1 ); + emit rockHit( 1 ); + } + + nrock->move( hit->x(), hit->y(), 0 ); + nrock->setVelocity( dx+addx[i]*rockSpeed+r, dy+addy[i]*rockSpeed+r ); + nrock->setFrame( randInt( nrock->frameCount() ) ); + nrock->show( ); + rocks.append( nrock ); + } + } + else if ( hit->rtti() == ID_ROCK_SMALL ) + emit rockHit( 2 ); + rocks.removeRef( (QCanvasSprite *)hit ); + if ( rocks.count() == 0 ) + emit rocksRemoved(); +} + +void KAsteroidsView::reducePower( int val ) +{ + shipPower -= val; + if ( shipPower <= 0 ) + { + shipPower = 0; + thrustShip = FALSE; + if ( shieldOn ) + { + shieldOn = FALSE; + shield->hide(); + } + } + vitalsChanged = TRUE; +} + +void KAsteroidsView::addExhaust( double x, double y, double dx, + double dy, int count ) +{ + for ( int i = 0; i < count; i++ ) + { + KExhaust *e = new KExhaust( animation[ID_EXHAUST], &field ); + e->move( x + 2 - randDouble()*4, y + 2 - randDouble()*4 ); + e->setVelocity( dx, dy ); + e->show( ); + exhaust.append( e ); + } +} + +void KAsteroidsView::processMissiles() +{ + KMissile *missile; + + // if a missile has hit a rock, remove missile and break rock into smaller + // rocks or remove completely. + QPtrListIterator<KMissile> it(missiles); + + for ( ; it.current(); ++it ) + { + missile = it.current(); + missile->growOlder(); + + if ( missile->expired() ) + { + missiles.removeRef( missile ); + continue; + } + + wrapSprite( missile ); + + QCanvasItemList hits = missile->collisions( TRUE ); + QCanvasItemList::Iterator hit; + for ( hit = hits.begin(); hit != hits.end(); ++hit ) + { + if ( (*hit)->rtti() >= ID_ROCK_LARGE && + (*hit)->rtti() <= ID_ROCK_SMALL ) + { + shotsHit++; + rockHit( *hit ); + missiles.removeRef( missile ); + break; + } + } + } +} + +// - - - + +void KAsteroidsView::processShip() +{ + if ( ship->visible() ) + { + if ( shieldOn ) + { + shield->show(); + reducePower( SHIELD_ON_COST ); + static int sf = 0; + sf++; + + if ( sf % 2 ) + shield->setFrame( (shield->frame()+1) % shield->frameCount() ); + shield->move( ship->x() - 5, ship->y() - 5 ); + + QCanvasItemList hits = shield->collisions( TRUE ); + QCanvasItemList::Iterator it; + for ( it = hits.begin(); it != hits.end(); ++it ) + { + if ( (*it)->rtti() >= ID_ROCK_LARGE && + (*it)->rtti() <= ID_ROCK_SMALL ) + { + int factor; + switch ( (*it)->rtti() ) + { + case ID_ROCK_LARGE: + factor = 3; + break; + + case ID_ROCK_MEDIUM: + factor = 2; + break; + + default: + factor = 1; + } + + if ( factor > mShieldCount ) + { + // shield not strong enough + shieldOn = FALSE; + break; + } + rockHit( *it ); + // the more shields we have the less costly + reducePower( factor * (SHIELD_HIT_COST - mShieldCount*2) ); + } + } + } + + if ( !shieldOn ) + { + shield->hide(); + QCanvasItemList hits = ship->collisions( TRUE ); + QCanvasItemList::Iterator it; + for ( it = hits.begin(); it != hits.end(); ++it ) + { + if ( (*it)->rtti() >= ID_ROCK_LARGE && + (*it)->rtti() <= ID_ROCK_SMALL ) + { + KBit *bit; + for ( int i = 0; i < 8; i++ ) + { + bit = new KBit( animation[ID_BIT], &field ); + bit->move( ship->x() + 5 - randDouble() * 10, + ship->y() + 5 - randDouble() * 10, + randInt(bit->frameCount()) ); + bit->setVelocity( 1-randDouble()*2, + 1-randDouble()*2 ); + bit->setDeath( 60 + randInt(60) ); + bit->show( ); + bits.append( bit ); + } + ship->hide(); + shield->hide(); + emit shipKilled(); + break; + } + } + } + + + if ( rotateSlow ) + rotateSlow--; + + if ( rotateL ) + { + shipAngle -= rotateSlow ? 1 : rotateRate; + if ( shipAngle < 0 ) + shipAngle += SHIP_STEPS; + } + + if ( rotateR ) + { + shipAngle += rotateSlow ? 1 : rotateRate; + if ( shipAngle >= SHIP_STEPS ) + shipAngle -= SHIP_STEPS; + } + + double angle = shipAngle * PI_X_2 / SHIP_STEPS; + double cosangle = cos( angle ); + double sinangle = sin( angle ); + + if ( brakeShip ) + { + thrustShip = FALSE; + rotateL = FALSE; + rotateR = FALSE; + rotateRate = ROTATE_RATE; + if ( fabs(shipDx) < 2.5 && fabs(shipDy) < 2.5 ) + { + shipDx = 0.0; + shipDy = 0.0; + ship->setVelocity( shipDx, shipDy ); + brakeShip = FALSE; + } + else + { + double motionAngle = atan2( -shipDy, -shipDx ); + if ( angle > M_PI ) + angle -= PI_X_2; + double angleDiff = angle - motionAngle; + if ( angleDiff > M_PI ) + angleDiff = PI_X_2 - angleDiff; + else if ( angleDiff < -M_PI ) + angleDiff = PI_X_2 + angleDiff; + double fdiff = fabs( angleDiff ); + if ( fdiff > 0.08 ) + { + if ( angleDiff > 0 ) + rotateL = TRUE; + else if ( angleDiff < 0 ) + rotateR = TRUE; + if ( fdiff > 0.6 ) + rotateRate = mBrakeCount + 1; + else if ( fdiff > 0.4 ) + rotateRate = 2; + else + rotateRate = 1; + + if ( rotateRate > 5 ) + rotateRate = 5; + } + else if ( fabs(shipDx) > 1 || fabs(shipDy) > 1 ) + { + thrustShip = TRUE; + // we'll make braking a bit faster + shipDx += cosangle/6 * (mBrakeCount - 1); + shipDy += sinangle/6 * (mBrakeCount - 1); + reducePower( BRAKE_ON_COST ); + addExhaust( ship->x() + 10 - cosangle*11, + ship->y() + 10 - sinangle*11, + shipDx-cosangle, shipDy-sinangle, + mBrakeCount+1 ); + } + } + } + + if ( thrustShip ) + { + // The ship has a terminal velocity, but trying to go faster + // still uses fuel (can go faster diagonally - don't care). + double thrustx = cosangle/8; + double thrusty = sinangle/8; + if ( fabs(shipDx + thrustx) < MAX_SHIP_SPEED ) + shipDx += thrustx; + if ( fabs(shipDy + thrusty) < MAX_SHIP_SPEED ) + shipDy += thrusty; + ship->setVelocity( shipDx, shipDy ); + reducePower( 1 ); + addExhaust( ship->x() + 10 - cosangle*10, + ship->y() + 10 - sinangle*10, + shipDx-cosangle, shipDy-sinangle, 3 ); + } + + ship->setFrame( shipAngle >> 1 ); + + if ( shootShip ) + { + if ( !shootDelay && (int)missiles.count() < mShootCount + 2 ) + { + KMissile *missile = new KMissile( animation[ID_MISSILE], &field ); + missile->move( 11+ship->x()+cosangle*11, + 11+ship->y()+sinangle*11, 0 ); + missile->setVelocity( shipDx + cosangle*MISSILE_SPEED, + shipDy + sinangle*MISSILE_SPEED ); + missile->show( ); + missiles.append( missile ); + shotsFired++; + reducePower( 1 ); + + shootDelay = 5; + } + + if ( shootDelay ) + shootDelay--; + } + + if ( teleportShip ) + { + int ra = rand() % 10; + if( ra == 0 ) + ra += rand() % 20; + int xra = ra * 60 + ( (rand() % 20) * (rand() % 20) ); + int yra = ra * 50 - ( (rand() % 20) * (rand() % 20) ); + ship->move( xra, yra ); + } + + vitalsChanged = TRUE; + } +} + +// - - - + +void KAsteroidsView::processPowerups() +{ + if ( !powerups.isEmpty() ) + { + // if player gets the powerup remove it from the screen, if option + // "Can destroy powerups" is enabled and a missile hits the powerup + // destroy it + + KPowerup *pup; + QPtrListIterator<KPowerup> it( powerups ); + + for( ; it.current(); ++it ) + { + pup = it.current(); + pup->growOlder(); + + if( pup->expired() ) + { + powerups.removeRef( pup ); + continue; + } + + wrapSprite( pup ); + + QCanvasItemList hits = pup->collisions( TRUE ); + QCanvasItemList::Iterator it; + for ( it = hits.begin(); it != hits.end(); ++it ) + { + if ( (*it) == ship ) + { + switch( pup->rtti() ) + { + case ID_ENERGY_POWERUP: + shipPower += 150; + if ( shipPower > MAX_POWER_LEVEL ) + shipPower = MAX_POWER_LEVEL; + break; + case ID_TELEPORT_POWERUP: + mTeleportCount++; + break; + case ID_BRAKE_POWERUP: + if ( mBrakeCount < MAX_BRAKES ) + mBrakeCount++; + break; + case ID_SHIELD_POWERUP: + if ( mShieldCount < MAX_SHIELDS ) + mShieldCount++; + break; + case ID_SHOOT_POWERUP: + if ( mShootCount < MAX_FIREPOWER ) + mShootCount++; + break; + } + + powerups.removeRef( pup ); + vitalsChanged = TRUE; + } + else if ( (*it) == shield ) + { + powerups.removeRef( pup ); + } + else if ( (*it)->rtti() == ID_MISSILE ) + { + if ( can_destroy_powerups ) + { + powerups.removeRef( pup ); + } + } + } + } + } // -- if( powerups.isEmpty() ) +} + +// - - - + +void KAsteroidsView::hideShield() +{ + shield->hide(); + mShieldCount = 0; + shieldOn = FALSE; +} + +double KAsteroidsView::randDouble() +{ + int v = rand(); + return (double)v / (double)RAND_MAX; +} + +int KAsteroidsView::randInt( int range ) +{ + return rand() % range; +} diff --git a/noncore/games/qasteroids/view.h b/noncore/games/qasteroids/view.h new file mode 100644 index 0000000..0a7902b --- a/dev/null +++ b/noncore/games/qasteroids/view.h @@ -0,0 +1,156 @@ +/********************************************************************** +** 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. +** +**********************************************************************//* + * KAsteroids - Copyright (c) Martin R. Jones 1997 + * + * Part of the KDE project + */ + +#ifndef __AST_VIEW_H__ +#define __AST_VIEW_H__ + +#include <qwidget.h> +#include <qlist.h> +#include <qintdict.h> +#include <qtimer.h> +#include <qcanvas.h> +#include "sprites.h" + +#define QPtrList QList +#define QPtrListIterator QListIterator + +#define MAX_POWER_LEVEL 1000 + +class KAsteroidsView : public QWidget +{ + Q_OBJECT +public: + KAsteroidsView( QWidget *parent = 0, const char *name = 0 ); + virtual ~KAsteroidsView(); + + int refreshRate; + + void reset(); + void setRockSpeed( double rs ) { rockSpeed = rs; } + void addRocks( int num ); + void newGame(); + void endGame(); + void newShip(); + + void rotateLeft( bool r ) { rotateL = r; rotateSlow = 5; } + void rotateRight( bool r ) { rotateR = r; rotateSlow = 5; } + void thrust( bool t ) { thrustShip = t && shipPower > 0; } + void shoot( bool s ) { shootShip = s; shootDelay = 0; } + void setShield( bool s ); + void teleport( bool te) { teleportShip = te && mTeleportCount; } + void brake( bool b ); + void pause( bool p); + + void showText( const QString &text, const QColor &color, bool scroll=TRUE ); + void hideText(); + + int shots() const { return shotsFired; } + int hits() const { return shotsHit; } + int power() const { return shipPower; } + + int teleportCount() const { return mTeleportCount; } + int brakeCount() const { return mBrakeCount; } + int shieldCount() const { return mShieldCount; } + int shootCount() const { return mShootCount; } + +signals: + void shipKilled(); + void rockHit( int size ); + void rocksRemoved(); + void updateVitals(); + +private slots: + void hideShield(); + +protected: + void readSprites(); + void wrapSprite( QCanvasItem * ); + void rockHit( QCanvasItem * ); + void reducePower( int val ); + void addExhaust( double x, double y, double dx, double dy, int count ); + void processMissiles(); + void processShip(); + void processPowerups(); + void processShield(); + double randDouble(); + int randInt( int range ); + + virtual void resizeEvent( QResizeEvent *event ); + virtual void timerEvent( QTimerEvent * ); + +private: + QCanvas field; + QCanvasView view; + QIntDict<QCanvasPixmapArray> animation; + QPtrList<QCanvasSprite> rocks; + QPtrList<KMissile> missiles; + QPtrList<KBit> bits; + QPtrList<KExhaust> exhaust; + QPtrList<KPowerup> powerups; + KShield *shield; + QCanvasSprite *ship; + QCanvasText *textSprite; + + bool rotateL; + bool rotateR; + bool thrustShip; + bool shootShip; + bool teleportShip; + bool brakeShip; + bool pauseShip; + bool shieldOn; + + bool vitalsChanged; + + int shipAngle; + int rotateSlow; + int rotateRate; + int shipPower; + + int shotsFired; + int shotsHit; + int shootDelay; + + int mBrakeCount; + int mShieldCount; + int mTeleportCount; + int mShootCount; + + double shipDx; + double shipDy; + + int textDy; + int mFrameNum; + bool mPaused; + int mTimerId; + + double rockSpeed; + double powerupSpeed; + + bool can_destroy_powerups; + + QTimer *shieldTimer; +}; + +#endif diff --git a/noncore/games/snake/.cvsignore b/noncore/games/snake/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/noncore/games/snake/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/noncore/games/snake/Makefile.in b/noncore/games/snake/Makefile.in new file mode 100644 index 0000000..8179b6f --- a/dev/null +++ b/noncore/games/snake/Makefile.in @@ -0,0 +1,159 @@ +############################################################################# + +####### 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 = snake +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = snake.h \ + target.h \ + obstacle.h \ + interface.h \ + codes.h +SOURCES = snake.cpp \ + target.cpp \ + obstacle.cpp \ + interface.cpp \ + main.cpp +OBJECTS = snake.o \ + target.o \ + obstacle.o \ + interface.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_snake.cpp \ + moc_interface.cpp +OBJMOC = moc_snake.o \ + moc_interface.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 snake.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 + +snake.o: snake.cpp \ + snake.h \ + target.h \ + codes.h \ + $(QPEDIR)/include/qpe/resource.h + +target.o: target.cpp \ + target.h \ + codes.h \ + $(QPEDIR)/include/qpe/resource.h + +obstacle.o: obstacle.cpp \ + obstacle.h \ + codes.h \ + $(QPEDIR)/include/qpe/resource.h + +interface.o: interface.cpp \ + interface.h \ + snake.h \ + target.h \ + obstacle.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/qpetoolbar.h + +main.o: main.cpp \ + interface.h \ + snake.h \ + target.h \ + obstacle.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_snake.o: moc_snake.cpp \ + snake.h + +moc_interface.o: moc_interface.cpp \ + interface.h \ + snake.h \ + target.h \ + obstacle.h + +moc_snake.cpp: snake.h + $(MOC) snake.h -o moc_snake.cpp + +moc_interface.cpp: interface.h + $(MOC) interface.h -o moc_interface.cpp + + diff --git a/noncore/games/snake/codes.h b/noncore/games/snake/codes.h new file mode 100644 index 0000000..3b5e4d0 --- a/dev/null +++ b/noncore/games/snake/codes.h @@ -0,0 +1,20 @@ +/********************************************************************** +** 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. +** +**********************************************************************/const int target_rtti = 1500; +const int obstacle_rtti = 1600; diff --git a/noncore/games/snake/interface.cpp b/noncore/games/snake/interface.cpp new file mode 100644 index 0000000..c9b4931 --- a/dev/null +++ b/noncore/games/snake/interface.cpp @@ -0,0 +1,224 @@ +/********************************************************************** +** 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 "interface.h" + +#include <qpe/resource.h> + +#include <qpe/qpetoolbar.h> +#include <qtoolbutton.h> +#include <qstyle.h> +#include <qapplication.h> +#include <qmessagebox.h> + +SnakeGame::SnakeGame(QWidget* parent, const char* name, WFlags f) : + QMainWindow(parent,name,f), + canvas(232, 258) +{ + setCaption( tr("Snake") ); + QPixmap bg = Resource::loadPixmap("grass"); + canvas.setBackgroundPixmap(bg); + canvas.setUpdatePeriod(100); + snake = 0; + + cv = new QCanvasView(&canvas, this); + + pauseTimer = new QTimer(this); + connect(pauseTimer, SIGNAL(timeout()), this, SLOT(wait()) ); + + setToolBarsMovable( FALSE ); + + QPEToolBar* toolbar = new QPEToolBar( this); + toolbar->setHorizontalStretchable( TRUE ); + + QPixmap newicon = Resource::loadPixmap("ksnake"); + setIcon(newicon); + (void)new QToolButton(newicon, tr("New Game"), 0, + this, SLOT(newGame()), toolbar, "New Game"); + + scorelabel = new QLabel(toolbar); + showScore(0); + scorelabel->setBackgroundMode( PaletteButton ); + scorelabel->setAlignment( AlignRight | AlignVCenter | ExpandTabs ); + toolbar->setStretchableWidget( scorelabel ); + + setFocusPolicy(StrongFocus); + + setCentralWidget(cv); + + welcomescreen(); + gamestopped = true; + waitover = true; +} + +SnakeGame::~SnakeGame() +{ + delete snake; +} + +void SnakeGame::resizeEvent(QResizeEvent *) +{ + QSize s = centralWidget()->size(); + int fw = style().defaultFrameWidth(); + canvas.resize( s.width() - fw - 2, s.height() - fw - 2); +} + +void SnakeGame::welcomescreen() +{ + QCanvasText* title = new QCanvasText(tr("SNAKE!"), &canvas); + title->setColor(yellow); + title->setFont( QFont("times", 18, QFont::Bold) ); + int w = title->boundingRect().width(); + title->move(canvas.width()/2 -w/2, canvas.height()/2-110); + title->show(); + QCanvasPixmapArray* titlearray = new QCanvasPixmapArray(Resource::findPixmap("title")); + QCanvasSprite* titlepic = new QCanvasSprite(titlearray, &canvas); + titlepic->move(canvas.width()/2 - 33, canvas.height()/2-85); + titlepic->show(); + QCanvasText* instr = new QCanvasText(tr("Use the arrow keys to guide the\n" + "snake to eat the mouse. You must not\n" + "crash into the walls, edges or its tail."), + &canvas); + w = instr->boundingRect().width(); + instr->move(canvas.width()/2-w/2, canvas.height()/2-20); + instr->setColor(white); + instr->show(); + QCanvasText* cont = new QCanvasText(tr("Press Any Key To Start"), &canvas); + w = cont->boundingRect().width(); + cont->move(canvas.width()/2-w/2, canvas.height()/2+80); + cont->setColor(yellow); + cont->show(); + +} + +void SnakeGame::newGame() +{ + clear(); + snake = new Snake(&canvas); + connect(snake, SIGNAL(dead()), this, SLOT(gameOver()) ); + connect(snake, SIGNAL(targethit()), this, SLOT(levelUp()) ); + connect(snake, SIGNAL(scorechanged()), this, SLOT(scoreInc()) ); + connect(this, SIGNAL(moveFaster()), snake, SLOT(increaseSpeed()) ); + last = 0; + targetamount = 1; + notargets = 1; + level = 1; + stage = 1; + showScore(0); + gamestopped = false; + waitover = true; + int x = canvas.width()/2 - 70; + x = x - x % 16; + int y = canvas.height()-50; + y = y - y % 16; + (void)new Obstacle(&canvas, x, 32); + (void)new Obstacle(&canvas, x, y); + createTargets(); +} + + +void SnakeGame::showScore(int score) +{ + scorelabel->setText(tr(" Score : %1 ").arg(score) ); +} + + +void SnakeGame::scoreInc() +{ + showScore( snake->getScore() ); +} + +void SnakeGame::levelUp() +{ + notargets--; + if (notargets == 0) { + stage++; + if (stage == 3) { + level++; + emit moveFaster(); + targetamount++; + stage = 0; + } + createTargets(); + } +} + +void SnakeGame::createTargets() +{ + for (int i = 0; i < targetamount; i++) + (void)new Target(&canvas); + notargets = targetamount; +} + +void SnakeGame::clear() +{ + delete snake; + snake = 0; + QCanvasItemList l = canvas.allItems(); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + delete *it; + } +} + +void SnakeGame::gameOver() +{ + int score = snake->getScore(); + QString scoreoutput=""; + scoreoutput.setNum(score); + QCanvasText* gameover = new QCanvasText(tr("GAME OVER!\n Your Score: %1").arg( scoreoutput), &canvas); + + gameover->setZ(100); + gameover->setColor(yellow); + gameover->setFont( QFont("times", 18, QFont::Bold) ); + int w = gameover->boundingRect().width(); + gameover->move(canvas.width()/2 -w/2, canvas.height()/2 -50); + gameover->show(); + gamestopped = true; + waitover = false; + pauseTimer->start(2500); +} + +void SnakeGame::wait() +{ + waitover = true; + pauseTimer->stop(); + QCanvasText* cont = new QCanvasText(tr("Press Any Key to Begin a New Game."), + &canvas); + cont->setZ(100); + cont->setColor(white); + int w = cont->boundingRect().width(); + cont->move(canvas.width()/2 -w/2, canvas.height()/2); + cont->show(); +} + +void SnakeGame::keyPressEvent(QKeyEvent* event) +{ + if (gamestopped) { + if (waitover) + newGame(); + else + return; + } + else { + int newkey = event->key(); + snake->go(newkey); + } +} + diff --git a/noncore/games/snake/interface.h b/noncore/games/snake/interface.h new file mode 100644 index 0000000..30c7f84 --- a/dev/null +++ b/noncore/games/snake/interface.h @@ -0,0 +1,69 @@ +/********************************************************************** +** 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 <qmainwindow.h> +#include <qcanvas.h> +#include <qlabel.h> + +#include "snake.h" +#include "target.h" +#include "obstacle.h" + +// class QCanvas; + +class SnakeGame : public QMainWindow { + Q_OBJECT + +public: + SnakeGame(QWidget* parent=0, const char* name=0, WFlags f=0); + ~SnakeGame(); + + void clear(); + void createTargets(); + void welcomescreen(); + +protected: + virtual void keyPressEvent(QKeyEvent*); + virtual void resizeEvent(QResizeEvent *e); + +signals: + void moveFaster(); + +private slots: + void newGame(); + void gameOver(); + void wait(); + void levelUp(); + void scoreInc(); + +private: + void showScore(int); + QCanvasView* cv; + QLabel* scorelabel; + QCanvas canvas; + QTimer* pauseTimer; + Snake* snake; + int last; + int level; + int stage; + int targetamount; + int notargets; + bool waitover; + bool gamestopped; +}; diff --git a/noncore/games/snake/main.cpp b/noncore/games/snake/main.cpp new file mode 100644 index 0000000..90a93b7 --- a/dev/null +++ b/noncore/games/snake/main.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** 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 "interface.h" + +#include <qpe/qpeapplication.h> + + +int main(int argc, char **argv) +{ + QPEApplication app(argc,argv); + + SnakeGame* m = new SnakeGame; + QPEApplication::setInputMethodHint( m, QPEApplication::AlwaysOff ); + app.showMainWidget(m); + + return app.exec(); +} diff --git a/noncore/games/snake/obstacle.cpp b/noncore/games/snake/obstacle.cpp new file mode 100644 index 0000000..2d07fe7 --- a/dev/null +++ b/noncore/games/snake/obstacle.cpp @@ -0,0 +1,51 @@ +/********************************************************************** +** 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 "obstacle.h" +#include "codes.h" + +#include <qpe/resource.h> + +Obstacle::Obstacle(QCanvas* canvas, int x, int y) + : QCanvasSprite(0, canvas) +{ + newObstacle(x, y); +} + +void Obstacle::newObstacle(int x, int y) +{ + QCanvasPixmapArray* obstaclearray = new QCanvasPixmapArray(Resource::findPixmap("snake/wall.png")); + + setSequence(obstaclearray); + + move(x, y); + + show(); + canvas()->update(); +} + +int Obstacle::rtti() const +{ + return obstacle_rtti; +} + +Obstacle::~Obstacle() +{ +} diff --git a/noncore/games/snake/obstacle.h b/noncore/games/snake/obstacle.h new file mode 100644 index 0000000..838917f --- a/dev/null +++ b/noncore/games/snake/obstacle.h @@ -0,0 +1,30 @@ +/********************************************************************** +** 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 <qcanvas.h> + +class Obstacle : public QCanvasSprite +{ + +public: + Obstacle(QCanvas*, int x, int y); + ~Obstacle(); + void newObstacle(int x, int y); + int rtti() const; +}; diff --git a/noncore/games/snake/qpe-snake.control b/noncore/games/snake/qpe-snake.control new file mode 100644 index 0000000..489e642 --- a/dev/null +++ b/noncore/games/snake/qpe-snake.control @@ -0,0 +1,9 @@ +Files: bin/snake apps/Games/snake.desktop pics/snake +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: control the snake + A game for the Qtopia environment. diff --git a/noncore/games/snake/snake.cpp b/noncore/games/snake/snake.cpp new file mode 100644 index 0000000..9f19841 --- a/dev/null +++ b/noncore/games/snake/snake.cpp @@ -0,0 +1,246 @@ +/********************************************************************** +** 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 "snake.h" +#include "target.h" +#include "codes.h" + +#include <qpe/resource.h> + +#include <qregexp.h> + +static int Piecekey[4][4] = { {6, 0, 4, 3 }, {0, 6, 2, 1 }, { 1, 3, 5, 0 }, {2, 4, 0, 5 } }; + +Snake::Snake(QCanvas* c) +{ + canvas = c; + score = 0; + snakelist.setAutoDelete(true); + autoMoveTimer = new QTimer(this); + connect( autoMoveTimer, SIGNAL(timeout()), this, SLOT(moveSnake()) ); + createSnake(); +} + +void Snake::createSnake() +{ + snakeparts = new QCanvasPixmapArray(); + QString s0 = Resource::findPixmap("snake/s0001"); + s0.replace(QRegExp("0001"),"%1"); + snakeparts->readPixmaps(s0, 15); + + grow = 0; + last = Key_Right; + + QCanvasSprite* head = new QCanvasSprite(snakeparts, canvas ); + head->setFrame(7); + snakelist.insert(0, head); + head->show(); + head->move(34, 16); + + QCanvasSprite* body = new QCanvasSprite(snakeparts, canvas ); + body->setFrame(6); + snakelist.append( body ); + body->show(); + body->move(18, 16); + + QCanvasSprite* end = new QCanvasSprite(snakeparts, canvas ); + end->setFrame(11); + snakelist.append( end ); + end->show(); + end->move(2, 16); + + currentdir = right; + speed = 250; + autoMoveTimer->start(speed); + moveSnake(); +} + +void Snake::increaseSpeed() +{ + if (speed > 150) + speed = speed - 5; + autoMoveTimer->start(speed); +} + +void Snake::go(int newkey) +{ + // check key is a direction + if (!( (newkey == Key_Up) || (newkey == Key_Left) || + (newkey == Key_Right) || (newkey == Key_Down) )) + return; + // check move is possible + if ( ((currentdir == left) && ((newkey == Key_Right) || (newkey == Key_Left)) ) || + ((currentdir == right) && ((newkey == Key_Left) || (newkey == Key_Right)) ) || + ((currentdir == up) && ((newkey == Key_Down) || (newkey == Key_Up)) ) || + ((currentdir == down) && ((newkey == Key_Up) || (newkey == Key_Down)) ) ) + return; + else { + Snake::changeHead(newkey); + Snake::moveSnake(); + } +} + +void Snake::move(Direction dir) +{ + autoMoveTimer->start(speed); + int x = 0; + int y = 0; + newdir = dir; + switch (dir) { + case right: x = 16; break; + case left: x = -16; break; + case down: y = 16; break; + case up: y = -16; break; + } + int index = lookUpPiece(currentdir, newdir); + QCanvasSprite* sprite = new QCanvasSprite(snakeparts, canvas ); + sprite->setFrame(index); + snakelist.insert(1, sprite); + sprite->move(snakelist.first()->x(), snakelist.first()->y() ); + + snakelist.first()->moveBy(x, y); + if (grow <= 0) + changeTail(); + else + grow--; + sprite->show(); + + currentdir = dir; +} + +void Snake::changeTail() +{ + snakelist.removeLast(); + + double lastx = snakelist.last()->x(); + double prevx = snakelist.prev()->x(); + int index = 0; + + if ( prevx == lastx ) { //vertical + if ( snakelist.prev()->y() > snakelist.last()->y() ) + index = 13; + else + index = 14; + } else { //horizontal + if (snakelist.prev()->x() > snakelist.last()->x() ) + index = 11; + else + index = 12; + } + + snakelist.last()->setFrame(index); +} + +void Snake::changeHead(int lastkey) +{ + int index = 0; + last = lastkey; + + switch (last) + { + case Key_Up: index = 10; break; + case Key_Left: index = 8; break; + case Key_Right: index = 7; break; + case Key_Down: index = 9; break; + } + + if (index) { + snakelist.first()->setFrame(index); + } +} + +// returns an integer corresponding to a particular type of snake piece +int Snake::lookUpPiece(Direction currentdir, Direction newdir) +{ + return Piecekey[currentdir][newdir]; +} + +void Snake::extendSnake() +{ + grow++; +} + +void Snake::moveSnake() +{ + switch (last) + { + case Key_Up: move(up); break; + case Key_Left: move(left); break; + case Key_Right: move(right); break; + case Key_Down: move(down); break; + } + detectCrash(); +} + +void Snake::detectCrash() +{ + QCanvasSprite* head = snakelist.first(); + QCanvasItem* item; + QCanvasItemList l=head->collisions(FALSE); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + item = *it; + // check if snake hit target + if ( (item->rtti()== 1500 ) && (item->collidesWith(head)) ) { + Target* target = (Target*) item; + target->done(); + emit targethit(); + extendSnake(); + setScore(5); + return; + } + // check if snake hit obstacles + if ( (item->rtti()==1600) && (item->collidesWith(head)) ) { + emit dead(); + autoMoveTimer->stop(); + return; + } + } + //check if snake hit itself + for (uint i = 3; i < snakelist.count(); i++) { + if (head->collidesWith(snakelist.at(i)) ) { + emit dead(); + autoMoveTimer->stop(); + return; + } + } + //check if snake hit edge + if ( (head->x() > canvas->width()-5) || (head->y() > canvas->height()-10) + || (head->x() <2) || (head->y() <-5) ) { + emit dead(); + autoMoveTimer->stop(); + return; + } +} + +void Snake::setScore(int amount) +{ + score = score + amount; + emit scorechanged(); +} + +int Snake::getScore() +{ + return score; +} + +Snake::~Snake() +{ + autoMoveTimer->stop(); +} diff --git a/noncore/games/snake/snake.h b/noncore/games/snake/snake.h new file mode 100644 index 0000000..5725343 --- a/dev/null +++ b/noncore/games/snake/snake.h @@ -0,0 +1,64 @@ +/********************************************************************** +** 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 <qcanvas.h> +#include <qtimer.h> + +class Snake : public QObject +{ + Q_OBJECT + +public: + enum Direction{ left, right, up, down}; + + Snake(QCanvas*); + ~Snake(); + void go(int newkey); + void move(Direction dir); + void changeHead(int last); + void changeTail(); + void detectCrash(); + void createSnake(); + void extendSnake(); + int lookUpPiece(Direction currentdir, Direction newdir); + void setScore(int amount); + int getScore(); + +signals: + void dead(); + void targethit(); + void scorechanged(); + +private slots: + void moveSnake(); + void increaseSpeed(); + +private: + QCanvasPixmapArray* snakeparts; + QList<QCanvasSprite>snakelist; + QTimer* autoMoveTimer; + QCanvas* canvas; + int grow; + int last; + int speed; + int score; + Direction currentdir; + Direction newdir; +}; + diff --git a/noncore/games/snake/snake.pro b/noncore/games/snake/snake.pro new file mode 100644 index 0000000..6dacdbd --- a/dev/null +++ b/noncore/games/snake/snake.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin +HEADERS = snake.h target.h obstacle.h interface.h codes.h +SOURCES = snake.cpp target.cpp obstacle.cpp interface.cpp main.cpp +TARGET = snake +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +TRANSLATIONS = ../i18n/de/snake.ts diff --git a/noncore/games/snake/target.cpp b/noncore/games/snake/target.cpp new file mode 100644 index 0000000..a09af69 --- a/dev/null +++ b/noncore/games/snake/target.cpp @@ -0,0 +1,77 @@ +/********************************************************************** +** 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 "target.h" +#include "codes.h" + +#include <qpe/resource.h> + +#include <stdlib.h> + +Target::Target(QCanvas* canvas) + : QCanvasSprite(0, canvas) +{ + mouse = new QCanvasPixmapArray(Resource::findPixmap("snake/mouse")); + setSequence(mouse); + newTarget(); +} + +void Target::newTarget() +{ + static bool first_time = TRUE; + if (first_time) { + first_time = FALSE; + QTime midnight(0, 0, 0); + srand(midnight.secsTo(QTime::currentTime()) ); + } + do { + int x = rand() % (canvas()->width()-10); + x = x - (x % 16) + 2; + int y = rand() % (canvas()->height()-10); + y = y - (y % 16) + 2; + move(x, y); + } while (onTop()); + show(); +} + +bool Target::onTop() +{ + QCanvasItem* item; + QCanvasItemList l= canvas()->allItems(); //collisions(FALSE); + for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) { + item = *it; + if (item != this && item->collidesWith(this)) return true; + } + return false; +} + +void Target::done() +{ + delete this; +} + +int Target::rtti() const +{ + return target_rtti; +} + +Target::~Target() +{ +} diff --git a/noncore/games/snake/target.h b/noncore/games/snake/target.h new file mode 100644 index 0000000..a6da37c --- a/dev/null +++ b/noncore/games/snake/target.h @@ -0,0 +1,37 @@ +/********************************************************************** +** 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 <qcanvas.h> +#include <qdatetime.h> + +class Target : public QCanvasSprite +{ + +public: + Target(QCanvas*); + ~Target(); + void newTarget(); + void done(); + void createMouse(); + bool onTop(); + int rtti() const; + +private: + QCanvasPixmapArray* mouse; +}; diff --git a/noncore/games/solitaire/.cvsignore b/noncore/games/solitaire/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/noncore/games/solitaire/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/noncore/games/solitaire/Makefile.in b/noncore/games/solitaire/Makefile.in new file mode 100644 index 0000000..3c50345 --- a/dev/null +++ b/noncore/games/solitaire/Makefile.in @@ -0,0 +1,235 @@ +############################################################################# + +####### 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 = patience +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = canvascard.h \ + canvasshapes.h \ + cardgame.h \ + cardgamelayout.h \ + cardpile.h \ + card.h \ + carddeck.h \ + canvascardgame.h \ + freecellcardgame.h \ + patiencecardgame.h \ + canvascardwindow.h +SOURCES = canvascard.cpp \ + canvasshapes.cpp \ + cardgame.cpp \ + cardgamelayout.cpp \ + cardpile.cpp \ + card.cpp \ + carddeck.cpp \ + canvascardgame.cpp \ + freecellcardgame.cpp \ + patiencecardgame.cpp \ + canvascardwindow.cpp \ + main.cpp +OBJECTS = canvascard.o \ + canvasshapes.o \ + cardgame.o \ + cardgamelayout.o \ + cardpile.o \ + card.o \ + carddeck.o \ + canvascardgame.o \ + freecellcardgame.o \ + patiencecardgame.o \ + canvascardwindow.o \ + main.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_canvascardwindow.cpp +OBJMOC = moc_canvascardwindow.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 solitaire.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=patience + +####### Sub-libraries + + +###### Combined headers + + + +####### Compile + +canvascard.o: canvascard.cpp \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h \ + canvascard.h \ + $(QPEDIR)/include/qpe/resource.h + +canvasshapes.o: canvasshapes.cpp \ + canvasshapes.h + +cardgame.o: cardgame.cpp \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h + +cardgamelayout.o: cardgamelayout.cpp \ + cardgamelayout.h \ + cardpile.h + +cardpile.o: cardpile.cpp \ + cardpile.h \ + card.h \ + $(QPEDIR)/include/qpe/config.h + +card.o: card.cpp \ + card.h \ + $(QPEDIR)/include/qpe/config.h + +carddeck.o: carddeck.cpp \ + card.h \ + carddeck.h + +canvascardgame.o: canvascardgame.cpp \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h \ + canvasshapes.h \ + canvascard.h \ + canvascardgame.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +freecellcardgame.o: freecellcardgame.cpp \ + freecellcardgame.h \ + patiencecardgame.h \ + canvascardgame.h \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h \ + canvasshapes.h \ + canvascard.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +patiencecardgame.o: patiencecardgame.cpp \ + patiencecardgame.h \ + canvascardgame.h \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h \ + canvasshapes.h \ + canvascard.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpemenubar.h + +canvascardwindow.o: canvascardwindow.cpp \ + canvascardwindow.h \ + patiencecardgame.h \ + canvascardgame.h \ + cardgame.h \ + card.h \ + cardpile.h \ + carddeck.h \ + cardgamelayout.h \ + canvasshapes.h \ + canvascard.h \ + $(QPEDIR)/include/qpe/resource.h \ + $(QPEDIR)/include/qpe/config.h \ + $(QPEDIR)/include/qpe/qpemenubar.h \ + freecellcardgame.h + +main.o: main.cpp \ + canvascardwindow.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +moc_canvascardwindow.o: moc_canvascardwindow.cpp \ + canvascardwindow.h + +moc_canvascardwindow.cpp: canvascardwindow.h + $(MOC) canvascardwindow.h -o moc_canvascardwindow.cpp + + diff --git a/noncore/games/solitaire/canvascard.cpp b/noncore/games/solitaire/canvascard.cpp new file mode 100644 index 0000000..ae3c859 --- a/dev/null +++ b/noncore/games/solitaire/canvascard.cpp @@ -0,0 +1,282 @@ +/********************************************************************** +** 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 "cardgame.h" +#include "canvascard.h" + +#include <qpe/resource.h> + +#include <qpainter.h> +#include <qimage.h> +#include <qpaintdevice.h> +#include <qbitmap.h> + +#include <math.h> + +#if defined( QT_QWS_CASSIOPEIA ) +#define SLOW_HARDWARE +#endif + +// Seems to be fast enough to me even without Transformations in the library +//#if defined( QT_NO_TRANSFORMATIONS ) && defined( QT_QWS_IPAQ ) +//#define SLOW_HARDWARE +//#endif + + +QBitmap *Create180RotatedBitmap(QBitmap *srcBitmap) +{ +#ifdef QT_NO_TRANSFORMATIONS + int w = srcBitmap->width(); + int h = srcBitmap->height(); + QBitmap *dstBitmap = new QBitmap( w, h ); + // ### this is very poorly implemented and probably could be much faster + for (int i = 0; i < w; i++) + for (int j = 0; j < h; j++) + bitBlt( dstBitmap, i, j, srcBitmap, w - i - 1, h - j - 1, 1, 1 ); + return dstBitmap; +#else + QWMatrix m; + m.rotate( 180.0 ); + return new QBitmap( srcBitmap->xForm( m ) ); +#endif +} + + +QPixmap *CreateScaledPixmap(QPixmap *srcPixmap, double scaleX, double scaleY) +{ +#ifdef QT_NO_TRANSFORMATIONS + int w = srcPixmap->width(); + int h = srcPixmap->height(); + int newW = (int)(w * scaleX); + int newH = (int)(h * scaleY); + QPixmap *dstPixmap = new QPixmap( newW, newH ); + // ### this is very poorly implemented and probably could be much faster + for (int i = 0; i < newW; i++) { + int srcX = w * i / newW; + if (newH == h) { + // Optimise for scaleing in the X-axis only + bitBlt( dstPixmap, i, 0, srcPixmap, srcX, 0, 1, h ); + } else { + for (int j = 0; j < newH; j++) { + int srcY = h * j / newH; + bitBlt( dstPixmap, i, j, srcPixmap, srcX, srcY, 1, 1 ); + } + } + } + return dstPixmap; +#else + QWMatrix s; + s.scale( scaleX, scaleY ); + return new QPixmap( srcPixmap->xForm( s ) ); +#endif +} + + +// Initialise static member variables to NULL +QPixmap *CanvasCard::cardsFaces = NULL; +QPixmap *CanvasCard::cardsBacks = NULL; +QBitmap *CanvasCard::cardsChars = NULL; +QBitmap *CanvasCard::cardsSuits = NULL; +QBitmap *CanvasCard::cardsCharsUpsideDown = NULL; +QBitmap *CanvasCard::cardsSuitsUpsideDown = NULL; + + +CanvasCard::CanvasCard( eValue v, eSuit s, bool f, QCanvas *canvas ) : + Card(v, s, f), QCanvasRectangle( 0, 0, 1, 1, canvas ), cardBack(1), scaleX(1.0), scaleY(1.0) +{ + if ( !cardsFaces ) { + cardsFaces = new QPixmap( Resource::loadPixmap( "cards/card_face" ) ); + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0001" ) ); + cardsChars = new QBitmap( Resource::loadBitmap( "cards/card_chars" ) ); + cardsSuits = new QBitmap( Resource::loadBitmap( "cards/card_suits" ) ); + cardsCharsUpsideDown = Create180RotatedBitmap( cardsChars ); + cardsSuitsUpsideDown = Create180RotatedBitmap( cardsSuits ); + } + xOff = cardsFaces->width() / 2; + yOff = cardsFaces->height() / 2; + setSize( cardsFaces->width(), cardsFaces->height() ); + setPen( NoPen ); + flipping = FALSE; +} + + +void CanvasCard::setCardBack(int b) +{ + if ( cardBack != b ) { + + cardBack = b; + + if ( cardsBacks ) + delete cardsBacks; + + switch (cardBack) { + case 0: + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0001" ) ); break; + case 1: + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0002" ) ); break; + case 2: + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0003" ) ); break; + case 3: + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0004" ) ); break; + case 4: + cardsBacks = new QPixmap( Resource::loadPixmap( "cards/card_back0005" ) ); break; + } + + if ( !isFacing() ) + redraw(); + } +} + + +void CanvasCard::draw(QPainter &painter) +{ + int ix = (int)x(), iy = (int)y(); + + QPainter *p = &painter; + QPixmap *unscaledCard = NULL; + + if ((scaleX <= 0.98) || (scaleY <= 0.98)) + { + p = new QPainter(); + unscaledCard = new QPixmap( cardsFaces->width(), cardsFaces->height() ); + p->begin(unscaledCard); + ix = 0; + iy = 0; + } + + if ( isFacing() ) { + +/* + // Now add the joker and card backs to the list of pixmaps + QPixmap *CardsBack = new QPixmap( Resource::loadPixmap( "cards/card_joker.png" ) ); + QPoint *newBackHotspot = new QPoint( 0, 0 ); + pixmaps->append((const QPixmap *)CardsBack); + hotspots->append((const QPoint *)newBackHotspot); +*/ + + int w = cardsFaces->width(), h = cardsFaces->height(); + +// p->setBrush( NoBrush ); + p->setBrush( QColor( 0xFF, 0xFF, 0xFF ) ); + + if ( isRed() == TRUE ) + p->setPen( QColor( 0xFF, 0, 0 ) ); + else + p->setPen( QColor( 0, 0, 0 ) ); + + p->drawPixmap( ix + 0, iy + 0, *cardsFaces ); + p->drawPixmap( ix + 4, iy + 4, *cardsChars, 7*(getValue()-1), 0, 7, 7 ); + p->drawPixmap( ix + 12, iy + 4, *cardsSuits, 7*(getSuit()-1), 0, 7, 8 ); + p->drawPixmap( ix + w-4-7, iy + h-4-7, *cardsCharsUpsideDown, 7*(12-getValue()+1), 0, 7, 7 ); + p->drawPixmap( ix + w-12-7, iy + h-5-7, *cardsSuitsUpsideDown, 7*(3-getSuit()+1), 0, 7, 8 ); + + } else { + + p->drawPixmap( ix, iy, *cardsBacks ); + + } + + if (p != &painter) + { + p->end(); + QPixmap *scaledCard = CreateScaledPixmap( unscaledCard, scaleX, scaleY ); + int xoff = scaledCard->width() / 2; + int yoff = scaledCard->height() / 2; + painter.drawPixmap( (int)x() + xOff - xoff, (int)y() + yOff - yoff, *scaledCard ); + delete p; + delete unscaledCard; + delete scaledCard; + } +} + + +static const double flipLift = 1.5; + + +void CanvasCard::flipTo(int x2, int y2, int steps) +{ + flipSteps = steps; + +#ifdef SLOW_HARDWARE + move(x2,y2); + Card::flipTo(x2,y2,steps); +#else + int x1 = (int)x(); + int y1 = (int)y(); + double dx = x2 - x1; + double dy = y2 - y1; + + flipping = TRUE; + destX = x2; + destY = y2; + animSteps = flipSteps; + setVelocity(dx/animSteps, dy/animSteps-flipLift); + setAnimated(TRUE); +#endif +} + + +void CanvasCard::advance(int stage) +{ + if ( stage==1 ) { + if ( animSteps-- <= 0 ) { + scaleX = 1.0; + scaleY = 1.0; + flipping = FALSE; + setVelocity(0,0); + setAnimated(FALSE); + move(destX,destY); // exact + } else { + if ( flipping ) { + if ( animSteps > flipSteps / 2 ) { + // animSteps = flipSteps .. flipSteps/2 (flip up) -> 1..0 + scaleX = ((double)animSteps/flipSteps-0.5)*2; + } else { + // animSteps = flipSteps/2 .. 0 (flip down) -> 0..1 + scaleX = 1-((double)animSteps/flipSteps)*2; + } + if ( animSteps == flipSteps / 2-1 ) { + setYVelocity(yVelocity()+flipLift*2); + setFace( !isFacing() ); + } + } + } + } + QCanvasRectangle::advance(stage); +} + + +void CanvasCard::animatedMove(int x2, int y2, int steps) +{ + destX = x2; + destY = y2; + + double x1 = x(), y1 = y(), dx = x2 - x1, dy = y2 - y1; + + // Ensure a good speed + while ( fabs(dx/steps)+fabs(dy/steps) < 5.0 && steps > 4 ) + steps--; + + setAnimated(TRUE); + setVelocity(dx/steps, dy/steps); + + animSteps = steps; +} + diff --git a/noncore/games/solitaire/canvascard.h b/noncore/games/solitaire/canvascard.h new file mode 100644 index 0000000..cd9691f --- a/dev/null +++ b/noncore/games/solitaire/canvascard.h @@ -0,0 +1,82 @@ +/********************************************************************** +** 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 CANVAS_CARD_H +#define CANVAS_CARD_H + + +#include <qpainter.h> +#include <qbitmap.h> +#include <qpixmap.h> +#include <qpoint.h> +#include <qcanvas.h> +#include "cardgame.h" + + +// ### Just made the number up, is that what you do??? +static const int canvasCardId = 2434321; + + +class CanvasCard : public Card, public QCanvasRectangle +{ +public: + CanvasCard( eValue v, eSuit s, bool f, QCanvas *canvas ); + virtual ~CanvasCard() { canvas()->removeItem(this); } + + int rtti () const { return canvasCardId; } + void move(QPoint p) { QCanvasItem::move( p.x(), p.y() ); } + void move(int x, int y) { QCanvasItem::move( x, y ); } + void animatedMove(int x, int y, int steps = 10); + void animatedMove() { animatedMove(savedX, savedY); } + void savePos(void) { savedX = (int)x(); savedY = (int)y(); } + void moveToPile(int p) { Q_UNUSED(p); } + void setCardBack(int b); + + /*virtual*/ void flipTo(int x, int y, int steps = 8); + /*virtual*/ void setPos( int x, int y, int z ) { setX( x ); setY( y ); setZ( z ); } + /*virtual*/ void showCard(void) { show(); } + /*virtual*/ void redraw(void) { hide(); show(); } + /*virtual*/ void draw(QPainter &p); + + void advance(int stage); + +protected: + /*virtual*/ void flip(void) { redraw(); } + +private: + int destX, destY; + int animSteps; + int flipSteps; + bool flipping; + int savedX, savedY; + int cardBack; + int oldCardBack; + double scaleX, scaleY; + int xOff, yOff; + static QPixmap *cardsFaces; + static QPixmap *cardsBacks; + static QBitmap *cardsChars; + static QBitmap *cardsSuits; + static QBitmap *cardsCharsUpsideDown; + static QBitmap *cardsSuitsUpsideDown; +}; + + +#endif + diff --git a/noncore/games/solitaire/canvascardgame.cpp b/noncore/games/solitaire/canvascardgame.cpp new file mode 100644 index 0000000..32635a0 --- a/dev/null +++ b/noncore/games/solitaire/canvascardgame.cpp @@ -0,0 +1,380 @@ +/********************************************************************** +** 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 "cardgame.h" +#include "canvasshapes.h" +#include "canvascard.h" +#include "canvascardgame.h" + +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qmainwindow.h> +#include <qpe/qpemenubar.h> +#include <qpainter.h> + +#include <stdlib.h> +#include <limits.h> +#include <time.h> +#include <math.h> + + +extern int highestZ; + + +class CanvasCardPile : public QCanvasRectangle +{ +public: + CanvasCardPile( CanvasCardGame *ccg, QCanvas *canvas ) : QCanvasRectangle( canvas ), parent( ccg ) { + pile = new QPixmap( 0, 0 ); + pileHeight = 0; + firstCard = NULL; + } + + void addCard( CanvasCard *card ); + void advance(int stage); + void animatedMove() { animatedMove(savedX, savedY); } + void savePos(void) { savedX = (int)x(); savedY = (int)y(); } + void animatedMove(int x2, int y2, int steps = 7 ); + +protected: + virtual void draw( QPainter& p ); + +private: + CanvasCardGame *parent; + QPixmap *pile; + QImage tempImage32; + CanvasCard *firstCard; + int pileHeight; + int destX, destY; + int savedX, savedY; + int animSteps; +}; + + +void CanvasCardPile::addCard( CanvasCard *card ) +{ + if ( !firstCard ) + firstCard = card; + + int height = 36 + pileHeight * 13; + setSize( 23, height ); + pile->resize( 23, height ); + QPainter p( pile ); + p.translate( -card->x(), -card->y() + pileHeight * 13 ); + card->draw( p ); + pileHeight++; + + QImage tempImage; + tempImage = *pile; + tempImage32 = tempImage.convertDepth( 32 ); + tempImage32.setAlphaBuffer( TRUE ); + for ( int i = 0; i < tempImage32.width(); i++ ) + for ( int j = 0; j < tempImage32.height(); j++ ) { + QRgb col = tempImage32.pixel( i, j ); + int a = 255-j*220/tempImage32.height(); + QRgb alpha = qRgba( qRed( col ), qGreen( col ), qBlue( col ), a ); + tempImage32.setPixel( i, j, alpha ); + } + + QRgb alpha = qRgba( 0, 0, 0, 0 ); + tempImage32.setPixel( 1, 0, alpha ); + tempImage32.setPixel( 0, 0, alpha ); + tempImage32.setPixel( 0, 1, alpha ); + + tempImage32.setPixel( 21, 0, alpha ); + tempImage32.setPixel( 22, 0, alpha ); + tempImage32.setPixel( 22, 1, alpha ); + height--; + tempImage32.setPixel( 1, height, alpha ); + tempImage32.setPixel( 0, height - 1, alpha ); + tempImage32.setPixel( 0, height, alpha ); + + tempImage32.setPixel( 21, height, alpha ); + tempImage32.setPixel( 22, height, alpha ); + tempImage32.setPixel( 22, height - 1, alpha ); +} + + +void CanvasCardPile::advance(int stage) +{ + if ( stage==1 ) { + if ( animSteps-- <= 0 ) { + CanvasCard *item = firstCard; + while (item) { + item->show(); + item = (CanvasCard *)item->getCardPile()->cardInfront(item); + } + setVelocity(0,0); + setAnimated(FALSE); + parent->cancelMoving(); + hide(); + move(destX,destY); // exact + } + } + QCanvasRectangle::advance(stage); +} + + +void CanvasCardPile::animatedMove(int x2, int y2, int steps = 7 ) +{ + destX = x2; + destY = y2; + + double x1 = x(), y1 = y(), dx = x2 - x1, dy = y2 - y1; + + // Ensure a good speed + while ( fabs(dx/steps)+fabs(dy/steps) < 5.0 && steps > 4 ) + steps--; + + setAnimated(TRUE); + setVelocity(dx/steps, dy/steps); + + animSteps = steps; +} + + +void CanvasCardPile::draw( QPainter& p ) +{ + int ix = (int)x(), iy = (int)y(); + p.drawImage( ix, iy, tempImage32 ); +} + + +CanvasCardGame::~CanvasCardGame() { + // the deletion stuff should be fixed now and only deletes + // items created by this CardGame. I haven't verified there are zero + // memory leaks yet + if ( alphaCardPile ) + delete alphaCardPile; +} + + +void CanvasCardGame::gameWon() { + + srand(time(NULL)); + + QCanvasItemList list = canvas()->allItems(); + QCanvasItemList::Iterator it = list.begin(); + + for (; it != list.end(); ++it) { + if ( (*it)->rtti() == canvasCardId ) { + // disperse the cards everywhere + int x = 300 - rand() % 1000; + int y = 300 + rand() % 200; + ((CanvasCard *)*it)->animatedMove( x, y, 50 ); + } + } +} + + +void CanvasCardGame::contentsMousePressEvent(QMouseEvent *e) { + + if ( moving ) + return; + + QCanvasItemList l = canvas()->collisions( e->pos() ); + + for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) { + + if ( (*it)->rtti() == canvasCardId ) { + + moving = (CanvasCard *)*it; + + if ( moving->animated() ) + return; + + cardXOff = (int)(e->pos().x() - moving->x()); + cardYOff = (int)(e->pos().y() - moving->y()); + + if ( !mousePressCard( moving, e->pos() ) ) { + CanvasCard *card = moving; + + if ( alphaCardPile ) + delete alphaCardPile; + + alphaCardPile = new CanvasCardPile( this, canvas() ); + alphaCardPile->move( card->x(), card->y() ); + alphaCardPile->savePos(); + alphaCardPile->show(); + + while (card) { + alphaCardPile->addCard( card ); + card->hide(); + card = (CanvasCard *)card->getCardPile()->cardInfront(card); + } + + alphaCardPile->setZ( INT_MAX ); + + moved = TRUE; + } else { + if ( alphaCardPile ) + alphaCardPile->hide(); + } + return; + } + } + + mousePress( e->pos() ); +} + +/* +// +// Should have some intelligent way to make double clicking on a +// card send it to the most appropriate pile +// +void CanvasCardGame::contentsMouseDoubleClickEvent(QMouseEvent *e) { + QCanvasItemList l = canvas()->collisions( e->pos() ); + for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) { + if ( (*it)->rtti() == canvasCardId ) { + CanvasCard *card = (CanvasCard *)*it; + + if ( card->animated() ) + return; + + if ( card->getCardPile()->isAllowedToBeMoved(card) ) { + if (card->getCardPile()->cardInfront(card) == NULL) { + CardPile *pile = first(); + if (pile && pile->isAllowedOnTop(card)) { + // move card to this pile + return; + } + } + } + } + } +} +*/ + +void CanvasCardGame::contentsMouseMoveEvent(QMouseEvent *e) { + + QPoint p = e->pos(); + + if ( moving ) { + + moved = TRUE; + + if (moving->isFacing() != TRUE) + return; + + int tx = (int)p.x() - cardXOff; + int ty = (int)p.y() - cardYOff; + + if (snapOn == TRUE) { + CardPile *pile = closestPile( tx, ty, 50 ); + if ( pile && pile->isAllowedOnTop( moving ) ) { + QPoint p = pile->getHypertheticalNextCardPos(); + if ( alphaCardPile ) + alphaCardPile->move( p.x(), p.y() ); + return; + } + } + + if ( alphaCardPile ) + alphaCardPile->move( tx, ty ); + } + +} + + +void CanvasCardGame::contentsMouseReleaseEvent(QMouseEvent *e) +{ + QPoint p = e->pos(); + + Q_UNUSED(p); + + if ( moving ) { + + CanvasCard *item = moving; + + if ( item->animated() ) + return; + + if ( alphaCardPile ) + if ( moved ) { + + CardPile *pile = closestPile((int)alphaCardPile->x(), (int)alphaCardPile->y(), 30); + + if (pile && pile->isAllowedOnTop(item)) { + CardPile *oldPile = item->getCardPile(); + Card *c = NULL; + if ( oldPile != pile) { + while ( item ) { + item->show(); + if ( oldPile ) { + c = oldPile->cardInfront(item); + oldPile->removeCard(item); + } + pile->addCardToTop(item); + item->setCardPile(pile); + //item->move( pile->getCardPos(item) ); + QPoint p = pile->getCardPos(item); + item->setPos( p.x(), p.y(), highestZ ); + highestZ++; + + if (item->getValue() == king && haveWeWon()) { + alphaCardPile->hide(); + gameWon(); + moving = NULL; + return; + } + + if (oldPile) { + item = (CanvasCard *)c; + } else { + item = NULL; + } + } + alphaCardPile->hide(); + moving = NULL; + return; + } + } + + alphaCardPile->animatedMove(); + } + } + + moved = FALSE; +} + + +void CanvasCardGame::readPile( Config& cfg, CardPile *pile, QString name, int& highestZ ) +{ + cfg.setGroup( name ); + int numberOfCards = cfg.readNumEntry("NumberOfCards", 0); + Card *card = NULL; + for ( int i = 0; i < numberOfCards; i++ ) { + QString cardStr; + cardStr.sprintf( "%i", i ); + int val = cfg.readNumEntry( "Card" + cardStr ); + bool facing = cfg.readBoolEntry( "CardFacing" + cardStr ); + card = cards[ val ]; + card->setFace(facing); + pile->addCardToTop(card); + card->setCardPile(pile); + QPoint p = pile->getCardPos( card ); + card->setPos( p.x(), p.y(), highestZ ); + card->showCard(); + highestZ++; + } +} + + diff --git a/noncore/games/solitaire/canvascardgame.h b/noncore/games/solitaire/canvascardgame.h new file mode 100644 index 0000000..4d32014 --- a/dev/null +++ b/noncore/games/solitaire/canvascardgame.h @@ -0,0 +1,95 @@ +/********************************************************************** +** 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 CANVAS_CARD_GAME_H +#define CANVAS_CARD_GAME_H + +#include "cardgame.h" +#include "canvasshapes.h" +#include "canvascard.h" + +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qmainwindow.h> +#include <qpe/qpemenubar.h> +#include <qpainter.h> + +#include <stdlib.h> +#include <time.h> + + +class CanvasCardPile; + + +class CanvasCardGame : public QCanvasView, public CardGame +{ +public: + CanvasCardGame(QCanvas &c, bool snap, QWidget *parent = 0, const char *name = 0, WFlags f = 0) : + QCanvasView( &c, parent, name, f ), + moved(FALSE), + moving(NULL), + alphaCardPile( NULL ), + cardXOff(0), cardYOff(0), + snapOn(snap), + numberToDraw(1) { } + + virtual ~CanvasCardGame(); + + virtual Card *newCard( eValue v, eSuit s, bool f ) { + return new CanvasCard( v, s, f, canvas() ); + } + + virtual void readConfig( Config& cfg ) { Q_UNUSED( cfg ); } + virtual void writeConfig( Config& cfg ) { Q_UNUSED( cfg ); } + + virtual void gameWon(); + virtual bool haveWeWon() { return FALSE; } + + virtual bool mousePressCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); return FALSE; } + virtual void mouseReleaseCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); } + + void cancelMoving() { moving = NULL; } + void toggleSnap() { snapOn = (snapOn == TRUE) ? FALSE : TRUE; } + void toggleCardsDrawn() { numberToDraw = (numberToDraw == 1) ? 3 : 1; } + int cardsDrawn() { return numberToDraw; } + void setNumberToDraw(int numToDraw) { this->numberToDraw = numToDraw; } + + void readPile( Config& cfg, CardPile *pile, QString name, int& highestZ ); + +protected: + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseReleaseEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + +protected: + // Mouse event state variables + bool moved; + CanvasCard *moving; + CanvasCardPile *alphaCardPile; + int cardXOff, cardYOff; + +private: + bool snapOn; + int numberToDraw; +}; + + +#endif + diff --git a/noncore/games/solitaire/canvascardwindow.cpp b/noncore/games/solitaire/canvascardwindow.cpp new file mode 100644 index 0000000..4c365a5 --- a/dev/null +++ b/noncore/games/solitaire/canvascardwindow.cpp @@ -0,0 +1,227 @@ +/********************************************************************** +** 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 "canvascardwindow.h" +#include "patiencecardgame.h" +#include "freecellcardgame.h" + +#include <qpe/resource.h> + +#include <qmainwindow.h> +#include <qpopupmenu.h> +#include <qstyle.h> + + +CanvasCardWindow::CanvasCardWindow(QWidget* parent, const char* name, WFlags f) : + QMainWindow(parent, name, f), canvas(230, 260), snapOn(TRUE), cardBack(4), gameType(0), + cardGame(NULL) +{ + setIcon( Resource::loadPixmap( "cards" ) ); + + // Create Playing Area for Games + if ( QPixmap::defaultDepth() < 12 ) { +// canvas.setBackgroundColor(QColor(0x51, 0x74, 0x6B)); +// canvas.setBackgroundColor(QColor(0x20, 0xb0, 0x50)); + canvas.setBackgroundColor(QColor(0x08, 0x98, 0x2D)); + } else { + QPixmap bg; + bg.convertFromImage( Resource::loadImage( "table_pattern" ), ThresholdDither ); + canvas.setBackgroundPixmap(bg); + } + +#if defined( QT_QWS_CASSIOPEIA ) + canvas.setAdvancePeriod(70); +#else + canvas.setAdvancePeriod(30); +#endif + + +#ifdef _PATIENCE_USE_ACCELS_ + QPEMenuBar* menu = menuBar(); + + QPopupMenu* file = new QPopupMenu; + file->insertItem(tr("Patience"), this, SLOT(initPatience()), CTRL+Key_F); + file->insertItem(tr("Freecell"), this, SLOT(initFreecell()), CTRL+Key_F); + menu->insertItem(tr("&Game"), file); + + menu->insertSeparator(); + + settings = new QPopupMenu; + settings->insertItem(tr("&Change Card Backs"), this, SLOT(changeCardBacks()), Key_F2); + snap_id = settings->insertItem(tr("&Snap To Position"), this, SLOT(snapToggle()), Key_F3); + settings->setCheckable(TRUE); + menu->insertItem(tr("&Settings"),settings); + + menu->insertSeparator(); + + QPopupMenu* help = new QPopupMenu; + help->insertItem(tr("&About"), this, SLOT(help()), Key_F1); + help->setItemChecked(dbf_id, TRUE); + menu->insertItem(tr("&Help"),help); +#else + QMenuBar* menu = menuBar(); + + QPopupMenu* file = new QPopupMenu; + file->insertItem(tr("Patience"), this, SLOT(initPatience())); + file->insertItem(tr("Freecell"), this, SLOT(initFreecell())); + menu->insertItem(tr("Play"), file); + + menu->insertSeparator(); + + settings = new QPopupMenu; + settings->setCheckable(TRUE); + settings->insertItem(tr("Change Card Backs"), this, SLOT(changeCardBacks())); + snap_id = settings->insertItem(tr("Snap To Position"), this, SLOT(snapToggle())); + QString m; + + drawId = settings->insertItem(tr("Turn One Card"), this, SLOT(drawnToggle())); + menu->insertItem(tr("Settings"),settings); + +#endif + + menu->show(); + + Config cfg( "Patience" ); + cfg.setGroup( "GlobalSettings" ); + snapOn = cfg.readBoolEntry( "SnapOn", TRUE); + settings->setItemChecked(snap_id, snapOn); + gameType = cfg.readNumEntry( "GameType", -1 ); + drawThree = cfg.readBoolEntry( "DrawThree", TRUE); + if ( gameType == 0 ) { + cardGame = new PatienceCardGame( &canvas, snapOn, this ); + cardGame->setNumberToDraw(drawThree ? 3 : 1); + setCaption(tr("Patience")); + setCentralWidget(cardGame); + cardGame->readConfig( cfg ); + setCardBacks(); + } else if ( gameType == 1 ) { + cardGame = new FreecellCardGame( &canvas, snapOn, this ); + setCaption(tr("Freecell")); + setCentralWidget(cardGame); + //cardGame->newGame(); // Until we know how to handle reading freecell config + cardGame->readConfig( cfg ); + setCardBacks(); + } else { + // Probably there isn't a config file or it is broken + // Start a new game + initPatience(); + } + + updateDraw(); +} + + +CanvasCardWindow::~CanvasCardWindow() +{ + if (cardGame) { + Config cfg("Patience"); + cfg.setGroup( "GlobalSettings" ); + cfg.writeEntry( "GameType", gameType ); + cfg.writeEntry( "SnapOn", snapOn ); + cfg.writeEntry( "DrawThree", drawThree); + cardGame->writeConfig( cfg ); + delete cardGame; + } +} + + +void CanvasCardWindow::resizeEvent(QResizeEvent *) +{ + QSize s = centralWidget()->size(); + int fw = style().defaultFrameWidth(); + canvas.resize( s.width() - fw - 2, s.height() - fw - 2); +} + + +void CanvasCardWindow::initPatience() +{ + // Create New Game + if ( cardGame ) + delete cardGame; + cardGame = new PatienceCardGame( &canvas, snapOn, this ); + cardGame->setNumberToDraw(drawThree ? 3 : 1); + gameType = 0; + setCaption(tr("Patience")); + setCentralWidget(cardGame); + cardGame->newGame(); + setCardBacks(); + updateDraw(); +} + + +void CanvasCardWindow::initFreecell() +{ + // Create New Game + if ( cardGame ) { + delete cardGame; + } + cardGame = new FreecellCardGame( &canvas, snapOn, this ); + gameType = 1; + setCaption(tr("Freecell")); + setCentralWidget(cardGame); + cardGame->newGame(); + setCardBacks(); +} + + +void CanvasCardWindow::snapToggle() +{ + snapOn = !snapOn; + settings->setItemChecked(snap_id, snapOn); + cardGame->toggleSnap(); +} + + +void CanvasCardWindow::drawnToggle() +{ + cardGame->toggleCardsDrawn(); + updateDraw(); +} + +void CanvasCardWindow::updateDraw() { + if(cardGame->cardsDrawn() == 3) + settings->changeItem(drawId, tr("Turn One Card")); + else + settings->changeItem(drawId, tr("Turn Three Cards")); +} + + +void CanvasCardWindow::setCardBacks() +{ + QCanvasItemList l = canvas.allItems(); + + for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) { + if ( (*it)->rtti() == canvasCardId ) + ((CanvasCard *)(*it))->setCardBack( cardBack ); + } +} + + +void CanvasCardWindow::changeCardBacks() +{ + cardBack++; + + if (cardBack == 5) + cardBack = 0; + + setCardBacks(); +} + + diff --git a/noncore/games/solitaire/canvascardwindow.h b/noncore/games/solitaire/canvascardwindow.h new file mode 100644 index 0000000..b75d40a --- a/dev/null +++ b/noncore/games/solitaire/canvascardwindow.h @@ -0,0 +1,70 @@ +/********************************************************************** +** 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 CANVAS_CARD_WINDOW_H +#define CANVAS_CARD_WINDOW_H + + +#include <qmainwindow.h> +#include <qcanvas.h> + + +class CanvasCardGame; +class QPopupMenu; + + +class CanvasCardWindow : public QMainWindow { + Q_OBJECT + +public: + CanvasCardWindow(QWidget* parent=0, const char* name=0, WFlags f=0); + virtual ~CanvasCardWindow(); + +public slots: + void setCardBacks(); + void changeCardBacks(); + void snapToggle(); + void drawnToggle(); + +private slots: + void initFreecell(); + void initPatience(); + +protected: + virtual void resizeEvent(QResizeEvent *e); + + void updateDraw(); +private: + QCanvas canvas; + bool snapOn; + bool drawThree; + int drawId; + int cardBack; + int gameType; + CanvasCardGame *cardGame; + + QPopupMenu* options; + QPopupMenu* settings; + int dbf_id; + int snap_id; +}; + + +#endif + diff --git a/noncore/games/solitaire/canvasshapes.cpp b/noncore/games/solitaire/canvasshapes.cpp new file mode 100644 index 0000000..28d0b4e --- a/dev/null +++ b/noncore/games/solitaire/canvasshapes.cpp @@ -0,0 +1,92 @@ +/********************************************************************** +** 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 <qpainter.h> +#include <qcanvas.h> +#include "canvasshapes.h" + + +CanvasRoundRect::CanvasRoundRect(int x, int y, QCanvas *canvas) : + QCanvasRectangle( x, y, 23, 36, canvas) +{ + setZ(0); + show(); +} + + +void CanvasRoundRect::redraw() +{ + hide(); + show(); +} + + +void CanvasRoundRect::drawShape(QPainter &p) +{ + p.drawRoundRect( (int)x(), (int)y(), 23, 36); +} + + +CanvasCircleOrCross::CanvasCircleOrCross(int x, int y, QCanvas *canvas) : + QCanvasRectangle( x, y, 21, 21, canvas), circleShape(TRUE) +{ + show(); +} + + +void CanvasCircleOrCross::redraw() +{ + hide(); + show(); +} + + +void CanvasCircleOrCross::setCircle() +{ + circleShape = TRUE; + redraw(); +} + + +void CanvasCircleOrCross::setCross() +{ + circleShape = FALSE; + redraw(); +} + + +void CanvasCircleOrCross::drawShape(QPainter &p) +{ + int x1 = (int)x(), y1 = (int)y(); + // Green circle + if (circleShape == TRUE) { + p.setPen( QPen( QColor(0x10, 0xE0, 0x10), 1 ) ); + p.drawEllipse( x1 - 1, y1 - 1, 21, 21); + p.drawEllipse( x1 - 1, y1 - 0, 21, 19); + p.drawEllipse( x1 + 0, y1 + 0, 19, 19); + p.drawEllipse( x1 + 1, y1 + 0, 17, 19); + p.drawEllipse( x1 + 1, y1 + 1, 17, 17); + // Red cross + } else { + p.setPen( QPen( QColor(0xE0, 0x10, 0x10), 5 ) ); + p.drawLine( x1, y1, x1 + 20, y1 + 20); + p.drawLine( x1 + 20, y1, x1, y1 + 20); + } +} + diff --git a/noncore/games/solitaire/canvasshapes.h b/noncore/games/solitaire/canvasshapes.h new file mode 100644 index 0000000..72acf6b --- a/dev/null +++ b/noncore/games/solitaire/canvasshapes.h @@ -0,0 +1,55 @@ +/********************************************************************** +** 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 CANVAS_SHAPES_H +#define CANVAS_SHAPES_H + + +#include <qcanvas.h> + + +class QPainter; + + +class CanvasRoundRect : QCanvasRectangle +{ +public: + CanvasRoundRect(int x, int y, QCanvas *canvas); + void redraw(); +protected: + void drawShape(QPainter &p); +}; + + +class CanvasCircleOrCross : QCanvasRectangle +{ +public: + CanvasCircleOrCross(int x, int y, QCanvas *canvas); + void redraw(); + void setCircle(); + void setCross(); +protected: + void drawShape(QPainter &p); +private: + bool circleShape; +}; + + +#endif + diff --git a/noncore/games/solitaire/card.cpp b/noncore/games/solitaire/card.cpp new file mode 100644 index 0000000..609e280 --- a/dev/null +++ b/noncore/games/solitaire/card.cpp @@ -0,0 +1,53 @@ +/********************************************************************** +** 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 "card.h" + +#include <qpe/config.h> + +#include <qpoint.h> +#include <qlist.h> + +/* +Card( eValue v, eSuit s, bool f ) : + val(v), suit(s), faceUp(f), showing(FALSE), ix(0), iy(0), iz(0), cardPile(NULL) { } +virtual ~Card() { } +eValue getValue() { return val; } +eSuit getSuit() { return suit; } +CardPile *getCardPile() { return cardPile; } +bool isFacing() { return faceUp; } +bool isShowing() { return showing; } +bool isRed() { return ((suit == diamonds) || (suit == hearts)); } +int getX(void) { return ix; } +int getY(void) { return iy; } +int getZ(void) { return iz; } +void setCardPile(CardPile *p) { cardPile = p; } +void setFace(bool f) { faceUp = f; } +void flip(void) { flipTo(getX(), getY()); } +virtual void setPos(int x, int y, int z) { ix = x; iy = y; iz = z; } +virtual void move(int x, int y) { ix = x; iy = y; } +virtual void move(QPoint p) { ix = p.x(); iy = p.y(); } +virtual void flipTo(int x, int y, int steps = 8) { ix = x; iy = y; faceUp = !faceUp; redraw(); Q_UNUSED(steps); } +virtual void showCard(void) { showing = TRUE; } +virtual void hideCard(void) { showing = FALSE; } +virtual void redraw(void) { } +*/ + + diff --git a/noncore/games/solitaire/card.h b/noncore/games/solitaire/card.h new file mode 100644 index 0000000..eb30d30 --- a/dev/null +++ b/noncore/games/solitaire/card.h @@ -0,0 +1,84 @@ +/********************************************************************** +** 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 CARD_H +#define CARD_H + + +#include <qpoint.h> + + +class CardPile; + + +enum eSuit { + jokerSuit = 0, clubs, spades, diamonds, hearts +}; + + +enum eValue { + jokerVal = 0, ace, two, three, four, five, + six, seven, eight, nine, ten, jack, queen, king +}; + + +class Card +{ +public: + Card( eValue v, eSuit s, bool f ) : + val(v), suit(s), faceUp(f), showing(FALSE), ix(0), iy(0), iz(0), cardPile(NULL) { } + virtual ~Card() { } + + eValue getValue() { return val; } + eSuit getSuit() { return suit; } + + void setCardPile(CardPile *p) { cardPile = p; } + CardPile *getCardPile() { return cardPile; } + + void setFace(bool f) { faceUp = f; /* flip(); */ } + bool isFacing() { return faceUp; } + + bool isShowing() { return showing; } + bool isRed() { return ((suit == diamonds) || (suit == hearts)); } + + int getX(void) { return ix; } + int getY(void) { return iy; } + int getZ(void) { return iz; } + void flip(void) { flipTo(getX(), getY()); } + + virtual void setPos(int x, int y, int z) { ix = x; iy = y; iz = z; } + virtual void move(int x, int y) { ix = x; iy = y; } + virtual void move(QPoint p) { ix = p.x(); iy = p.y(); } + virtual void flipTo(int x, int y, int steps = 8) { ix = x; iy = y; faceUp = !faceUp; redraw(); Q_UNUSED(steps); } + virtual void showCard(void) { showing = TRUE; } + virtual void hideCard(void) { showing = FALSE; } +protected: + virtual void redraw(void) { } +private: + eValue val; + eSuit suit; + bool faceUp; + bool showing; + int ix, iy, iz; + CardPile *cardPile; +}; + + +#endif + diff --git a/noncore/games/solitaire/carddeck.cpp b/noncore/games/solitaire/carddeck.cpp new file mode 100644 index 0000000..87c043a --- a/dev/null +++ b/noncore/games/solitaire/carddeck.cpp @@ -0,0 +1,81 @@ +/********************************************************************** +** 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 <stdlib.h> +#include <time.h> +#include "card.h" +#include "carddeck.h" + + +CardDeck::CardDeck(int jokers) : numberOfJokers(jokers), deckCreated(FALSE) +{ + cards = new (Card *)[getNumberOfCards()]; +} + + +CardDeck::~CardDeck() +{ + for (int i = 0; i < getNumberOfCards(); i++) + delete cards[i]; + delete cards; +} + + +void CardDeck::createDeck() +{ + if (!deckCreated) { + for (int i = 0; i < 52; i++) + cards[i] = newCard( (eValue)((i % 13) + 1), (eSuit)((i / 13) + 1), FALSE ); + for (int i = 0; i < getNumberOfJokers(); i++) + cards[52 + i] = newCard( jokerVal, jokerSuit, FALSE ); + deckCreated = TRUE; + } +} + + +void CardDeck::shuffle() +{ + srand(time(NULL)); + for (int i = 0; i < getNumberOfCards(); i++) { + int index = rand() % getNumberOfCards(); + Card *tmpCard = cards[i]; + cards[i] = cards[index]; + cards[index] = tmpCard; + } +} + + +int CardDeck::getNumberOfCards() +{ + return 52 + getNumberOfJokers(); +} + + +int CardDeck::getNumberOfJokers() +{ + return numberOfJokers; +} + + +Card *CardDeck::newCard( eValue v, eSuit s, bool f ) +{ + return new Card(v, s, f); +} + + diff --git a/noncore/games/solitaire/carddeck.h b/noncore/games/solitaire/carddeck.h new file mode 100644 index 0000000..9ad35a9 --- a/dev/null +++ b/noncore/games/solitaire/carddeck.h @@ -0,0 +1,49 @@ +/********************************************************************** +** 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 CARD_DECK_H +#define CARD_DECK_H + + +class Card; + + +class CardDeck +{ +public: + CardDeck(int jokers = 0); + virtual ~CardDeck(); + + void createDeck(); + void shuffle(); + int getNumberOfCards(); + int getNumberOfJokers(); + + virtual Card *newCard( eValue v, eSuit s, bool f ); + virtual void deal() { } + + Card **cards; +private: + int numberOfJokers; + bool deckCreated; +}; + + +#endif + diff --git a/noncore/games/solitaire/cardgame.cpp b/noncore/games/solitaire/cardgame.cpp new file mode 100644 index 0000000..b19aeef --- a/dev/null +++ b/noncore/games/solitaire/cardgame.cpp @@ -0,0 +1,35 @@ +/********************************************************************** +** 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 "cardgame.h" + + +void CardGame::newGame() +{ + // Create Cards + createDeck(); + + // Shuffle Cards + shuffle(); + + // Deal Cards + deal(); +} + + diff --git a/noncore/games/solitaire/cardgame.h b/noncore/games/solitaire/cardgame.h new file mode 100644 index 0000000..dd7efab --- a/dev/null +++ b/noncore/games/solitaire/cardgame.h @@ -0,0 +1,45 @@ +/********************************************************************** +** 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 CARD_GAME_H +#define CARD_GAME_H + + +#include <qpoint.h> +#include "card.h" +#include "cardpile.h" +#include "carddeck.h" +#include "cardgamelayout.h" + + +class CardGame : public CardGameLayout, public CardDeck +{ +public: + CardGame(int numOfJokers = 0) : CardGameLayout(), CardDeck(numOfJokers) { } + virtual ~CardGame() { } + virtual void newGame(); + virtual void mousePress(QPoint p) { Q_UNUSED(p); } + virtual void mouseRelease(QPoint p) { Q_UNUSED(p); } + virtual void mouseMove(QPoint p) { Q_UNUSED(p); } +private: +}; + + +#endif + diff --git a/noncore/games/solitaire/cardgamelayout.cpp b/noncore/games/solitaire/cardgamelayout.cpp new file mode 100644 index 0000000..1ceee8d --- a/dev/null +++ b/noncore/games/solitaire/cardgamelayout.cpp @@ -0,0 +1,61 @@ +/********************************************************************** +** 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 "cardgamelayout.h" + + +CardGameLayout::~CardGameLayout() +{ + // Should I just do setAutoDelete( TRUE ); ? + for (CardPile *p = first(); p != NULL; p = next()) + delete p; +} + + +CardPile *CardGameLayout::closestPile(int x, int y, int maxDistance) +{ + int closestDistance = maxDistance * maxDistance; + CardPile *closestPile = NULL; + + for (CardPile *p = first(); p != NULL; p = next()) { + int d = p->distanceFromNextPos(x, y); + if (d < closestDistance) { + closestDistance = d; + closestPile = p; + } + } + + return closestPile; +} + + +void CardGameLayout::beginDealing() +{ + for (CardPile *p = first(); p != NULL; p = next()) + p->beginDealing(); +} + + +void CardGameLayout::endDealing() +{ + for (CardPile *p = first(); p != NULL; p = next()) + p->endDealing(); +} + + diff --git a/noncore/games/solitaire/cardgamelayout.h b/noncore/games/solitaire/cardgamelayout.h new file mode 100644 index 0000000..bb36e6b --- a/dev/null +++ b/noncore/games/solitaire/cardgamelayout.h @@ -0,0 +1,42 @@ +/********************************************************************** +** 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 CARD_GAME_LAYOUT_H +#define CARD_GAME_LAYOUT_H + + +#include <qlist.h> +#include "cardpile.h" + + +class CardGameLayout : public QList<CardPile> +{ +public: + CardGameLayout() { } + virtual ~CardGameLayout(); + + void addCardPile(CardPile *pile) { append((const CardPile *)pile); } + CardPile *closestPile(int x, int y, int maxDistance); + void beginDealing(); + void endDealing(); +}; + + +#endif + diff --git a/noncore/games/solitaire/cardpile.cpp b/noncore/games/solitaire/cardpile.cpp new file mode 100644 index 0000000..0b738d2 --- a/dev/null +++ b/noncore/games/solitaire/cardpile.cpp @@ -0,0 +1,114 @@ +/********************************************************************** +** 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 "cardpile.h" +#include "card.h" + +#include <qpe/config.h> +#include <qpoint.h> + +#include <qlist.h> + + +CardPile::CardPile(int x, int y) : pileX(x), pileY(y), dealing(FALSE) { + pileWidth = 0; + pileHeight = 0; + pileNextX = pileX; + pileNextY = pileY; + pileCenterX = x + pileWidth / 2; + pileCenterY = y + pileHeight / 2; + pileRadius = (pileWidth > pileHeight) ? pileWidth : pileHeight; +} + + +int CardPile::distanceFromPile(int x, int y) { + return (pileCenterX-x)*(pileCenterX-x)+(pileCenterY-y)*(pileCenterY-y); +} + + +int CardPile::distanceFromNextPos(int x, int y) { + return (pileNextX-x)*(pileNextX-x)+(pileNextY-y)*(pileNextY-y); +} + + +Card *CardPile::cardInfront(Card *c) { + CardPile *p = c->getCardPile(); + if (p) { + p->at(p->find(c)); + return p->next(); + } else { + return NULL; + } +} + + +bool CardPile::kingOnTop() { + Card *top = cardOnTop(); + return top && top->getValue() == king; +} + + +bool CardPile::addCardToTop(Card *c) { + if (dealing || isAllowedOnTop(c)) { + append((const Card *)c); + cardAddedToTop(c); + return TRUE; + } + return FALSE; +} + + +bool CardPile::addCardToBottom(Card *c) { + if (dealing || isAllowedOnBottom(c)) { + prepend((const Card *)c); + cardAddedToBottom(c); + return TRUE; + } + return FALSE; +} + + +bool CardPile::removeCard(Card *c) { + if (dealing || isAllowedToBeMoved(c)) { + take(find(c)); + cardRemoved(c); + return TRUE; + } + return FALSE; +} + + +void CardPile::writeConfig( Config& cfg, QString name ) { + int numberOfCards = 0; + cfg.setGroup( name ); + Card *card = cardOnBottom(); + while ( card ) { + QString cardStr; + cardStr.sprintf( "%i", numberOfCards ); + int val = (int)card->getValue() - 1 + ( (int)card->getSuit() - 1 ) * 13; + cfg.writeEntry( "Card" + cardStr, val ); + cfg.writeEntry( "CardFacing" + cardStr, card->isFacing() ); + card = cardInfront( card ); + numberOfCards++; + } + cfg.writeEntry("NumberOfCards", numberOfCards); +} + + diff --git a/noncore/games/solitaire/cardpile.h b/noncore/games/solitaire/cardpile.h new file mode 100644 index 0000000..c515bbc --- a/dev/null +++ b/noncore/games/solitaire/cardpile.h @@ -0,0 +1,101 @@ +/********************************************************************** +** 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 CARD_PILE_H +#define CARD_PILE_H + + +#include <qpoint.h> +#include <qlist.h> + + +enum ePileStackingType { + pileCascades = 0, pileStacks, pileCascadesOrStacks +}; + + +enum ePileFaceingType { + pileFaceUp = 0, pileFaceDown, pileFaceUpOrDown +}; + + +class Card; +class Config; + + +class CardPile : public QList<Card> +{ +public: + CardPile(int x, int y); + virtual ~CardPile() { } + + int getX() { return pileX; } + int getY() { return pileY; } + int getNextX() { return pileNextX; } + int getNextY() { return pileNextY; } + int getWidth() { return pileWidth; } + int getHeight() { return pileHeight; } + + void setX(int x) { pileX = x; } + void setY(int y) { pileY = y; } + void setNextX(int x) { pileNextX = x; } + void setNextY(int y) { pileNextY = y; } + void setWidth(int width) { pileWidth = width; } + void setHeight(int height) { pileHeight = height; } + + void beginDealing() { dealing = TRUE; } + void endDealing() { dealing = FALSE; } + bool isDealing() { return dealing; } + + int distanceFromPile(int x, int y); + int distanceFromNextPos(int x, int y); + + Card *cardOnTop() { return getLast(); } + Card *cardOnBottom() { return getFirst(); } + Card *cardInfront(Card *c); + bool kingOnTop(); + + bool addCardToTop(Card *c); + bool addCardToBottom(Card *c); + bool removeCard(Card *c); + + virtual void cardAddedToTop(Card *) { } + virtual void cardAddedToBottom(Card *) { } + virtual void cardRemoved(Card *) { } + virtual bool isAllowedOnTop(Card *) { return FALSE; } + virtual bool isAllowedOnBottom(Card *) { return FALSE; } + virtual bool isAllowedToBeMoved(Card *) { return FALSE; } + virtual QPoint getCardPos(Card *) { return QPoint(pileX, pileY); } + virtual QPoint getHypertheticalNextCardPos() { return QPoint(pileX, pileY); } + + void writeConfig( Config& cfg, QString name ); + +protected: + int pileX, pileY; + int pileNextX, pileNextY; + int pileWidth, pileHeight; + int pileCenterX, pileCenterY; + int pileRadius; +private: + bool dealing; +}; + + +#endif + diff --git a/noncore/games/solitaire/freecellcardgame.cpp b/noncore/games/solitaire/freecellcardgame.cpp new file mode 100644 index 0000000..e82afd4 --- a/dev/null +++ b/noncore/games/solitaire/freecellcardgame.cpp @@ -0,0 +1,137 @@ +/********************************************************************** +** 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 "freecellcardgame.h" + + +extern int highestZ; +int numberOfFreeCells = 4; + + +FreecellCardGame::FreecellCardGame(QCanvas *c, bool snap, QWidget *parent) : CanvasCardGame(*c, snap, parent) +{ + numberOfFreeCells = 4; + highestZ = 0; + + for (int i = 0; i < 4; i++) { + freecellPiles[i] = new FreecellFreecellPile( 5 + i * 28, 10, canvas() ); + addCardPile(freecellPiles[i]); + } + for (int i = 0; i < 4; i++) { + discardPiles[i] = new FreecellDiscardPile( 125 + i * 28, 10, canvas() ); + addCardPile(discardPiles[i]); + } + for (int i = 0; i < 8; i++) { + workingPiles[i] = new FreecellWorkingPile( 10 + i * 28, 50, canvas() ); + addCardPile(workingPiles[i]); + } +} + + +void FreecellCardGame::deal(void) +{ + highestZ = 1; + + beginDealing(); + + for (int i = 0; i < 52; i++) { + Card *card = cards[i]; + card->setFace( TRUE ); + card->setPos( 0, 0, highestZ ); + card->setCardPile( workingPiles[i%8] ); + workingPiles[i%8]->addCardToTop( card ); + card->move( workingPiles[i%8]->getCardPos( card ) ); + card->showCard(); + highestZ++; + } + + endDealing(); +} + + +bool FreecellCardGame::mousePressCard( Card *c, QPoint p ) +{ + Q_UNUSED(p); + + if ( !c->getCardPile()->isAllowedToBeMoved(c) ) { + moving = NULL; + return TRUE; + } + + return FALSE; +} + + +void FreecellCardGame::readConfig( Config& cfg ) +{ + cfg.setGroup("GameState"); + + // Create Cards, but don't shuffle or deal them yet + createDeck(); + + // Move the cards to their piles (deal them to their previous places) + beginDealing(); + + highestZ = 1; + + for (int k = 0; k < 4; k++) { + QString pile; + pile.sprintf( "FreeCellPile%i", k ); + readPile( cfg, freecellPiles[k], pile, highestZ ); + } + + for (int k = 0; k < 4; k++) { + QString pile; + pile.sprintf( "DiscardPile%i", k ); + readPile( cfg, discardPiles[k], pile, highestZ ); + } + + for (int k = 0; k < 8; k++) { + QString pile; + pile.sprintf( "WorkingPile%i", k ); + readPile( cfg, workingPiles[k], pile, highestZ ); + } + + highestZ++; + + endDealing(); +} + + +void FreecellCardGame::writeConfig( Config& cfg ) +{ + cfg.setGroup("GameState"); + for ( int i = 0; i < 4; i++ ) { + QString pile; + pile.sprintf( "FreeCellPile%i", i ); + freecellPiles[i]->writeConfig( cfg, pile ); + } + for ( int i = 0; i < 4; i++ ) { + QString pile; + pile.sprintf( "DiscardPile%i", i ); + discardPiles[i]->writeConfig( cfg, pile ); + } + for ( int i = 0; i < 8; i++ ) { + QString pile; + pile.sprintf( "WorkingPile%i", i ); + workingPiles[i]->writeConfig( cfg, pile ); + } +} + + diff --git a/noncore/games/solitaire/freecellcardgame.h b/noncore/games/solitaire/freecellcardgame.h new file mode 100644 index 0000000..f1b09ab --- a/dev/null +++ b/noncore/games/solitaire/freecellcardgame.h @@ -0,0 +1,152 @@ +/********************************************************************** +** 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 FREECELL_CARD_GAME_H +#define FREECELL_CARD_GAME_H + + +#include "patiencecardgame.h" + + +extern int numberOfFreeCells; + + +class FreecellDiscardPile : public PatienceDiscardPile +{ +public: + FreecellDiscardPile(int x, int y, QCanvas *canvas) : + PatienceDiscardPile(x, y, canvas) { } + +}; + + +class FreecellWorkingPile : public PatienceWorkingPile +{ +public: + FreecellWorkingPile(int x, int y, QCanvas *canvas) : + PatienceWorkingPile(x, y, canvas) { } + + virtual bool isAllowedOnTop(Card *card) { + if ( cardOnBottom() == NULL ) { + int numberOfCardsBeingMoved = 0; + Card *tempCard = card; + + while ((tempCard != NULL)) { + numberOfCardsBeingMoved++; + tempCard = cardInfront(tempCard); + } + + if (numberOfCardsBeingMoved > numberOfFreeCells) + return FALSE; + } + + if ( card->isFacing() && + cardOnTop() == NULL ) + return TRUE; + return PatienceWorkingPile::isAllowedOnTop( card ); + } + + virtual bool isAllowedToBeMoved(Card *card) { + int nextExpectedValue = (int)card->getValue(); + bool nextExpectedColor = card->isRed(); + int numberOfCardsBeingMoved = 0; + + while ((card != NULL)) { + numberOfCardsBeingMoved++; + if ( (int)card->getValue() != nextExpectedValue ) + return FALSE; + if ( card->isRed() != nextExpectedColor ) + return FALSE; + nextExpectedValue--;; + nextExpectedColor = !nextExpectedColor; + card = cardInfront(card); + } + + if (numberOfCardsBeingMoved <= (numberOfFreeCells + 1)) + return TRUE; + + return FALSE; + } + virtual void cardRemoved(Card *card) { + if ( !isDealing() && !cardOnTop() ) + numberOfFreeCells++; + PatienceWorkingPile::cardRemoved( card ); + } + virtual void cardAddedToTop(Card *card) { + if ( !isDealing() && cardOnBottom() == card ) + numberOfFreeCells--; + PatienceWorkingPile::cardAddedToTop( card ); + } +}; + + +class FreecellFreecellPile : public CardPile, public CanvasRoundRect +{ +public: + FreecellFreecellPile(int x, int y, QCanvas *canvas) + : CardPile(x, y), CanvasRoundRect(x, y, canvas) { } + virtual bool isAllowedOnTop(Card *card) { + if ( ( cardOnTop() == NULL ) && ( card->getCardPile()->cardInfront(card) == NULL ) ) + return TRUE; + return FALSE; + } + virtual bool isAllowedToBeMoved(Card *card) { + Q_UNUSED(card); + return TRUE; + } + virtual void cardAddedToTop(Card *card) { + Q_UNUSED(card); + numberOfFreeCells--; + } + virtual void cardRemoved(Card *card) { + Q_UNUSED(card); + numberOfFreeCells++; + } +}; + + +class FreecellCardGame : public CanvasCardGame +{ +public: + FreecellCardGame(QCanvas *c, bool snap, QWidget *parent = 0); + virtual void deal(void); + virtual bool haveWeWon() { + return ( discardPiles[0]->kingOnTop() && + discardPiles[1]->kingOnTop() && + discardPiles[2]->kingOnTop() && + discardPiles[3]->kingOnTop() ); + } + virtual void mousePress(QPoint p) { Q_UNUSED(p); } + virtual void mouseRelease(QPoint p) { Q_UNUSED(p); } +// virtual void mouseMove(QPoint p); + virtual bool mousePressCard(Card *card, QPoint p); + virtual void mouseReleaseCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); } +// virtual void mouseMoveCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); } + void readConfig( Config& cfg ); + void writeConfig( Config& cfg ); + bool snapOn; +private: + FreecellFreecellPile *freecellPiles[8]; + FreecellWorkingPile *workingPiles[8]; + FreecellDiscardPile *discardPiles[4]; +}; + + +#endif + diff --git a/noncore/games/solitaire/main.cpp b/noncore/games/solitaire/main.cpp new file mode 100644 index 0000000..f81aa3c --- a/dev/null +++ b/noncore/games/solitaire/main.cpp @@ -0,0 +1,36 @@ +/********************************************************************** +** 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 "canvascardwindow.h" + +#include <qpe/qpeapplication.h> + + +int main( int argc, char ** argv ) +{ + QPEApplication a( argc, argv ); + + CanvasCardWindow m; + m.setCaption( CanvasCardWindow::tr("Patience") ); + a.showMainWidget( &m ); + + return a.exec(); +} + diff --git a/noncore/games/solitaire/patiencecardgame.cpp b/noncore/games/solitaire/patiencecardgame.cpp new file mode 100644 index 0000000..5a9326a --- a/dev/null +++ b/noncore/games/solitaire/patiencecardgame.cpp @@ -0,0 +1,234 @@ +/********************************************************************** +** 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 "patiencecardgame.h" + + +int highestZ = 0; + + +PatienceCardGame::PatienceCardGame(QCanvas *c, bool snap, QWidget *parent) : CanvasCardGame(*c, snap, parent) +{ + numberOfTimesThroughDeck = 0; + highestZ = 0; + + circleCross = new CanvasCircleOrCross( 7, 18, canvas() ); + rectangle = new CanvasRoundRect( 35, 10, canvas() ); + + for (int i = 0; i < 4; i++) { + discardPiles[i] = new PatienceDiscardPile( 110 + i * 30, 10, canvas() ); + addCardPile(discardPiles[i]); + } + for (int i = 0; i < 7; i++) { + workingPiles[i] = new PatienceWorkingPile( 10 + i * 30, 50, canvas() ); + addCardPile(workingPiles[i]); + } + faceDownDealingPile = new PatienceFaceDownDeck( 5, 10, canvas() ); + faceUpDealingPile = new PatienceFaceUpDeck( 35, 10, canvas() ); +} + + +PatienceCardGame::~PatienceCardGame() +{ + delete circleCross; + delete rectangle; + delete faceDownDealingPile; + delete faceUpDealingPile; +} + + +void PatienceCardGame::deal(void) +{ + highestZ = 1; + int t = 0; + + beginDealing(); + + for (int i = 0; i < 7; i++) { + cards[t]->setFace(TRUE); + for (int k = i; k < 7; k++, t++) { + Card *card = cards[t]; + workingPiles[k]->addCardToTop(card); + card->setCardPile( workingPiles[k] ); + QPoint p = workingPiles[k]->getCardPos( card ); + card->setPos( p.x(), p.y(), highestZ ); + card->showCard(); + highestZ++; + } + } + + for ( ; t < 52; t++) { + Card *card = cards[t]; + faceDownDealingPile->addCardToTop(card); + card->setCardPile( faceDownDealingPile ); + QPoint p = faceDownDealingPile->getCardPos( card ); + card->setPos( p.x(), p.y(), highestZ ); + card->showCard(); + highestZ++; + } + + endDealing(); +} + + +void PatienceCardGame::readConfig( Config& cfg ) +{ + cfg.setGroup("GameState"); + + // Do we have a config file to read in? + if ( !cfg.hasKey("numberOfTimesThroughDeck") ) { + // if not, create a new game + newGame(); + return; + } + // We have a config file, lets read it in and use it + + // Create Cards, but don't shuffle or deal them yet + createDeck(); + + // How many times through the deck have we been + numberOfTimesThroughDeck = cfg.readNumEntry("NumberOfTimesThroughDeck"); + + // restore state to the circle/cross under the dealing pile + if ( canTurnOverDeck() ) + circleCross->setCircle(); + else + circleCross->setCross(); + + // Move the cards to their piles (deal them to their previous places) + beginDealing(); + + highestZ = 1; + + for (int k = 0; k < 7; k++) { + QString pile; + pile.sprintf( "WorkingPile%i", k ); + readPile( cfg, workingPiles[k], pile, highestZ ); + } + + for (int k = 0; k < 4; k++) { + QString pile; + pile.sprintf( "DiscardPile%i", k ); + readPile( cfg, discardPiles[k], pile, highestZ ); + } + + readPile( cfg, faceDownDealingPile, "FaceDownDealingPile", highestZ ); + readPile( cfg, faceUpDealingPile, "FaceUpDealingPile", highestZ ); + + highestZ++; + + endDealing(); +} + + +void PatienceCardGame::writeConfig( Config& cfg ) +{ + cfg.setGroup("GameState"); + cfg.writeEntry("numberOfTimesThroughDeck", numberOfTimesThroughDeck); + + for ( int i = 0; i < 7; i++ ) { + QString pile; + pile.sprintf( "WorkingPile%i", i ); + workingPiles[i]->writeConfig( cfg, pile ); + } + for ( int i = 0; i < 4; i++ ) { + QString pile; + pile.sprintf( "DiscardPile%i", i ); + discardPiles[i]->writeConfig( cfg, pile ); + } + faceDownDealingPile->writeConfig( cfg, "FaceDownDealingPile" ); + faceUpDealingPile->writeConfig( cfg, "FaceUpDealingPile" ); +} + + +bool PatienceCardGame::mousePressCard( Card *card, QPoint p ) +{ + Q_UNUSED(p); + + CanvasCard *item = (CanvasCard *)card; + if (item->isFacing() != TRUE) { + // From facedown stack + if ((item->x() == 5) && ((int)item->y() == 10)) { + item->setZ(highestZ); + highestZ++; + + // Added Code + faceDownDealingPile->removeCard(item); + faceUpDealingPile->addCardToTop(item); + item->setCardPile( faceUpDealingPile ); + + item->flipTo( 35, (int)item->y() ); + } + moving = NULL; + moved = FALSE; + + // move two other cards if we flip three at a time + int flipped = 1; + QCanvasItemList l = canvas()->collisions( p ); + for (QCanvasItemList::Iterator it = l.begin(); (it != l.end()) && (flipped != cardsDrawn()); ++it) { + if ( (*it)->rtti() == canvasCardId ) { + CanvasCard *item = (CanvasCard *)*it; + if (item->animated()) + continue; + item->setZ(highestZ); + highestZ++; + flipped++; + + // Added Code + faceDownDealingPile->removeCard(item); + faceUpDealingPile->addCardToTop(item); + item->setCardPile( faceUpDealingPile ); + + item->flipTo( 35, (int)item->y(), 8 * flipped ); + } + } + + return TRUE; + } + + return FALSE; +} + + +void PatienceCardGame::mousePress(QPoint p) +{ + if ( canTurnOverDeck() && + (p.x() > 5) && (p.x() < 28) && + (p.y() > 10) && (p.y() < 46) ) { + + beginDealing(); + Card *card = faceUpDealingPile->cardOnTop(); + while ( card ) { + card->setPos( 5, 10, highestZ ); + card->setFace( FALSE ); + faceUpDealingPile->removeCard( card ); + faceDownDealingPile->addCardToTop( card ); + card->setCardPile( faceDownDealingPile ); + card = faceUpDealingPile->cardOnTop(); + highestZ++; + } + endDealing(); + + throughDeck(); + + moved = TRUE; + } +} + + diff --git a/noncore/games/solitaire/patiencecardgame.h b/noncore/games/solitaire/patiencecardgame.h new file mode 100644 index 0000000..c4f6c48 --- a/dev/null +++ b/noncore/games/solitaire/patiencecardgame.h @@ -0,0 +1,206 @@ +/********************************************************************** +** 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 PATIENCE_CARD_GAME_H +#define PATIENCE_CARD_GAME_H + + +#include <qpopupmenu.h> +#include <qmainwindow.h> +#include <qintdict.h> +#include <qcanvas.h> +// #include "canvascardshapes.h" +// #include "canvascard.h" +#include "canvascardgame.h" + + +class PatienceFaceDownDeck : public CardPile, public CanvasRoundRect +{ +public: + PatienceFaceDownDeck(int x, int y, QCanvas *canvas) + : CardPile(x, y), CanvasRoundRect(x, y, canvas) { } + virtual bool isAllowedOnTop(Card *card) { + Q_UNUSED(card); + // Need to check it is from the faceUpDealingPile + return TRUE; + } + virtual bool isAllowedToBeMoved(Card *card) { + Q_UNUSED(card); + //if ( ( !card->isFacing() ) && ( card == cardOnTop() ) ) + if ( card == cardOnTop() ) + return TRUE; + return FALSE; + } +}; + + +class PatienceFaceUpDeck : public CardPile, public CanvasRoundRect +{ +public: + PatienceFaceUpDeck(int x, int y, QCanvas *canvas) + : CardPile(x, y), CanvasRoundRect(x, y, canvas) { } + virtual bool isAllowedOnTop(Card *card) { + Q_UNUSED(card); + // Need to check it is from the faceDownDealingPile + return TRUE; + } + virtual bool isAllowedToBeMoved(Card *card) { + Q_UNUSED(card); + //if ( ( card->isFacing() ) && ( card == cardOnTop() ) ) + if ( card == cardOnTop() ) + return TRUE; + return FALSE; + } +}; + + +class PatienceDiscardPile : public CardPile, public CanvasRoundRect +{ +public: + PatienceDiscardPile(int x, int y, QCanvas *canvas) + : CardPile(x, y), CanvasRoundRect(x, y, canvas) { } + virtual bool isAllowedOnTop(Card *card) { + if ( card->isFacing() && ( card->getCardPile()->cardInfront(card) == NULL ) && + ( ( ( cardOnTop() == NULL ) && ( card->getValue() == ace ) ) || + ( ( cardOnTop() != NULL ) && + ( (int)card->getValue() == (int)cardOnTop()->getValue() + 1 ) && + ( card->getSuit() == cardOnTop()->getSuit() ) ) ) ) + return TRUE; + return FALSE; + } + virtual bool isAllowedToBeMoved(Card *card) { + if ( card->isFacing() && ( card == cardOnTop() ) ) + return TRUE; + return FALSE; + } +}; + + +class PatienceWorkingPile : public CardPile, public CanvasRoundRect +{ +public: + PatienceWorkingPile(int x, int y, QCanvas *canvas) + : CardPile(x, y), CanvasRoundRect(x, y, canvas), top(x, y) { } + virtual bool isAllowedOnTop(Card *card) { + if ( card->isFacing() && + ( ( ( cardOnTop() == NULL ) && (card->getValue() == king) ) || + ( ( cardOnTop() != NULL ) && + ( (int)card->getValue() + 1 == (int)cardOnTop()->getValue() ) && + ( card->isRed() != cardOnTop()->isRed() ) ) ) ) + return TRUE; + return FALSE; + } + virtual bool isAllowedToBeMoved(Card *card) { + if ( card->isFacing() ) + return TRUE; + return FALSE; + } + virtual void cardAddedToTop(Card *card) { + Q_UNUSED(card); + top = getCardPos(NULL); + setNextX( top.x() ); + setNextY( top.y() ); + } + virtual void cardRemoved(Card *card) { + Q_UNUSED(card); + + Card *newTopCard = cardOnTop(); + + if ( !newTopCard ) { + top = QPoint( pileX, pileY ); + setNextX( pileX ); + setNextY( pileY ); + return; + } else { + top = getCardPos(NULL); + if ( newTopCard->isFacing() == FALSE ) { + // correct the position taking in to account the card is not + // yet flipped, but will become flipped + top = QPoint( top.x() - 1, top.y() - 3 ); + newTopCard->flipTo( top.x(), top.y() ); + top = QPoint( top.x(), top.y() + 13 ); + } + setNextX( top.x() ); + setNextY( top.y() ); + } + } + virtual QPoint getCardPos(Card *c) { + int x = pileX, y = pileY; + Card *card = cardOnBottom(); + while ((card != c) && (card != NULL)) { + if (card->isFacing()) { + y += 13; + } else { + x += 1; + y += 3; + } + card = cardInfront(card); + } + return QPoint( x, y ); + } + virtual QPoint getHypertheticalNextCardPos(void) { + return top; + // return QPoint( getNextX(), getNextY() ); + } +private: + QPoint top; + +}; + + +class PatienceCardGame : public CanvasCardGame +{ +public: + PatienceCardGame(QCanvas *c, bool snap, QWidget *parent = 0); + virtual ~PatienceCardGame(); + virtual void deal(void); + virtual bool haveWeWon() { + return ( discardPiles[0]->kingOnTop() && + discardPiles[1]->kingOnTop() && + discardPiles[2]->kingOnTop() && + discardPiles[3]->kingOnTop() );; + } + virtual void mousePress(QPoint p); + virtual void mouseRelease(QPoint p) { Q_UNUSED(p); } +// virtual void mouseMove(QPoint p); + virtual bool mousePressCard(Card *card, QPoint p); + virtual void mouseReleaseCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); } +// virtual void mouseMoveCard(Card *card, QPoint p) { Q_UNUSED(card); Q_UNUSED(p); } + bool canTurnOverDeck(void) { return (numberOfTimesThroughDeck != 3); } + void throughDeck(void) { + numberOfTimesThroughDeck++; + if (numberOfTimesThroughDeck == 3) + circleCross->setCross(); + } + bool snapOn; + virtual void writeConfig( Config& cfg ); + virtual void readConfig( Config& cfg ); +private: + CanvasCircleOrCross *circleCross; + CanvasRoundRect *rectangle; + PatienceWorkingPile *workingPiles[7]; + PatienceDiscardPile *discardPiles[4]; + PatienceFaceDownDeck *faceDownDealingPile; + PatienceFaceUpDeck *faceUpDealingPile; + int numberOfTimesThroughDeck; +}; + + +#endif + diff --git a/noncore/games/solitaire/qpe-solitaire.control b/noncore/games/solitaire/qpe-solitaire.control new file mode 100644 index 0000000..71abb0c --- a/dev/null +++ b/noncore/games/solitaire/qpe-solitaire.control @@ -0,0 +1,9 @@ +Files: bin/patience apps/Games/patience.desktop pics/cards +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: solitaire card games + A solitaire game for the Qtopia environment. diff --git a/noncore/games/solitaire/solitaire.pro b/noncore/games/solitaire/solitaire.pro new file mode 100755 index 0000000..8617cab --- a/dev/null +++ b/noncore/games/solitaire/solitaire.pro @@ -0,0 +1,18 @@ +TEMPLATE = app + +CONFIG += qt warn_on release +DESTDIR = $(QPEDIR)/bin + +HEADERS = canvascard.h canvasshapes.h cardgame.h cardgamelayout.h cardpile.h card.h carddeck.h canvascardgame.h freecellcardgame.h patiencecardgame.h canvascardwindow.h + +SOURCES = canvascard.cpp canvasshapes.cpp cardgame.cpp cardgamelayout.cpp cardpile.cpp card.cpp carddeck.cpp canvascardgame.cpp freecellcardgame.cpp patiencecardgame.cpp canvascardwindow.cpp main.cpp + +TARGET = patience + +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe + +REQUIRES = patience + +TRANSLATIONS = ../i18n/de/patience.ts diff --git a/noncore/games/tetrix/.cvsignore b/noncore/games/tetrix/.cvsignore new file mode 100644 index 0000000..edfa921 --- a/dev/null +++ b/noncore/games/tetrix/.cvsignore @@ -0,0 +1,3 @@ +moc_* +*.moc +Makefile diff --git a/noncore/games/tetrix/Makefile.in b/noncore/games/tetrix/Makefile.in new file mode 100644 index 0000000..3a74fdc --- a/dev/null +++ b/noncore/games/tetrix/Makefile.in @@ -0,0 +1,157 @@ +############################################################################# + +####### 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 = ../bin/ +VER_MAJ = 1 +VER_MIN = 0 +VER_PATCH = 0 +TARGET = tetrix +TARGET1 = lib$(TARGET).so.$(VER_MAJ) + +####### Files + +HEADERS = minefield.h \ + gtetrix.h \ + qtetrix.h \ + qtetrixb.h \ + tpiece.h +SOURCES = main.cpp \ + gtetrix.cpp \ + qtetrix.cpp \ + qtetrixb.cpp \ + tpiece.cpp +OBJECTS = main.o \ + gtetrix.o \ + qtetrix.o \ + qtetrixb.o \ + tpiece.o +INTERFACES = +UICDECLS = +UICIMPLS = +SRCMOC = moc_qtetrix.cpp \ + moc_qtetrixb.cpp +OBJMOC = moc_qtetrix.o \ + moc_qtetrixb.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 tetrix.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 \ + qtetrix.h \ + qtetrixb.h \ + gtetrix.h \ + tpiece.h \ + $(QPEDIR)/include/qpe/qpeapplication.h + +gtetrix.o: gtetrix.cpp \ + gtetrix.h \ + tpiece.h + +qtetrix.o: qtetrix.cpp \ + qtetrix.h \ + qtetrixb.h \ + gtetrix.h \ + tpiece.h \ + $(QPEDIR)/include/qpe/resource.h + +qtetrixb.o: qtetrixb.cpp \ + qtetrixb.h \ + gtetrix.h \ + tpiece.h \ + qtetrix.h + +tpiece.o: tpiece.cpp \ + tpiece.h + +moc_qtetrix.o: moc_qtetrix.cpp \ + qtetrix.h \ + qtetrixb.h \ + gtetrix.h \ + tpiece.h + +moc_qtetrixb.o: moc_qtetrixb.cpp \ + qtetrixb.h \ + gtetrix.h \ + tpiece.h + +moc_qtetrix.cpp: qtetrix.h + $(MOC) qtetrix.h -o moc_qtetrix.cpp + +moc_qtetrixb.cpp: qtetrixb.h + $(MOC) qtetrixb.h -o moc_qtetrixb.cpp + + diff --git a/noncore/games/tetrix/gtetrix.cpp b/noncore/games/tetrix/gtetrix.cpp new file mode 100644 index 0000000..d1f38b1 --- a/dev/null +++ b/noncore/games/tetrix/gtetrix.cpp @@ -0,0 +1,514 @@ +/********************************************************************** +** 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 "gtetrix.h" + +#include <string.h> + +GenericTetrix::GenericTetrix(int boardWidth,int boardHeight) +{ + int i,j; + + width = boardWidth; + height = boardHeight; + boardPtr = new int[height*width]; // Note the order, this makes it easier + // to remove full lines. + for(i = 0 ; i < height ; i++) + for(j = 0 ; j < width ; j++) + board(j,i) = 0; + currentLine = -1; // -1 if no falling piece. + currentPos = 0; + showNext = 0; // FALSE + nLinesRemoved = 0; + nPiecesDropped = 0; + score = 0; + level = 1; + gameID = 0; + nClearLines = height; +} + +GenericTetrix::~GenericTetrix() +{ + delete[] boardPtr; +} + + +void GenericTetrix::clearBoard(int fillRandomLines) +{ + int i,j; + + if (fillRandomLines >= height) + fillRandomLines = height - 1; + + erasePiece(); + for(i = height - nClearLines - 1 ; i >= fillRandomLines ; i--) + for(j = 0 ; j < width ; j++) + if (board(j,i) != 0) { + draw(j,i,0); + board(j,i) = 0; + } + if (fillRandomLines != 0) + for (i = 0 ; i < fillRandomLines ; i++) { + fillRandom(i); + } + nClearLines = height - fillRandomLines; +} + +void GenericTetrix::showBoard() +{ + int i,j; + + showPiece(); + for(i = height - nClearLines - 1 ; i >= 0 ; i--) + for(j = 0 ; j < width ; j++) + if (board(j,i) != 0) + draw(j,i,board(j,i)); +} + +void GenericTetrix::hideBoard() +{ + int i,j; + + erasePiece(); + for(i = height - nClearLines - 1 ; i >= 0 ; i--) + for(j = 0 ; j < width ; j++) + if (board(j,i) != 0) + draw(j,i,0); +} + +void GenericTetrix::startGame(int gameType,int fillRandomLines) +{ + gameID = gameType; + clearBoard(fillRandomLines); + nLinesRemoved = 0; + updateRemoved(nLinesRemoved); + nClearLines = height; + nPiecesDropped = 0; + score = 0; + updateScore(score); + level = 1; + updateLevel(level); + newPiece(); +} + +void GenericTetrix::revealNextPiece(int revealIt) +{ + if (showNext == revealIt) + return; + showNext = revealIt; + if (!showNext) + eraseNextPiece(); + else + showNextPiece(); +} + +void GenericTetrix::updateBoard(int x1,int y1,int x2, int y2, + int dontUpdateBlanks) +{ + int i,j; + int tmp; + + if (x1 > x2) { + tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y1 > y2) { + tmp = y2; + y2 = y1; + y1 = tmp; + } + if (x1 < 0) + x1 = 0; + if (x2 >= width) + x2 = width - 1; + if (y1 < 0) + y1 = 0; + if (y2 >= height) + y2 = height - 1; + for(i = y1 ; i <= y2 ; i++) + for(j = x1 ; j <= x2 ; j++) + if (!dontUpdateBlanks || board(j,height - i - 1) != 0) + draw(j,height - i - 1,board(j,height - i - 1)); + showPiece(); // Remember to update piece correctly!!!! +} + + +void GenericTetrix::fillRandom(int line) +{ + int i,j; + int holes; + + for(i = 0 ; i < width ; i++) + board(i,line) = TetrixPiece::randomValue(7); + holes = 0; + for(i = 0 ; i < width ; i++) + if (board(i,line) == 0) // Count holes in the line. + holes++; + if (holes == 0) // Full line, make a random hole: + board(TetrixPiece::randomValue(width),line) = 0; + if (holes == width) // Empty line, make a random square: + board(TetrixPiece::randomValue(width),line) = + TetrixPiece::randomValue(6) + 1; + for(j = 0 ; j < width ; j++) + draw(j,i,board(j,i)); +} + +void GenericTetrix::moveLeft(int steps) +{ + while(steps) { + if (!canMoveTo(currentPos - 1,currentLine)) + return; + moveTo(currentPos - 1,currentLine); + steps--; + } +} + +void GenericTetrix::moveRight(int steps) +{ + while(steps) { + if (!canMoveTo(currentPos + 1,currentLine)) + return; + moveTo(currentPos + 1,currentLine); + steps--; + } +} + +void GenericTetrix::rotateLeft() +{ + TetrixPiece tmp(currentPiece); + + tmp.rotateLeft(); + if (!canPosition(tmp)) + return; + position(tmp); + currentPiece = tmp; +} + +void GenericTetrix::rotateRight() +{ + TetrixPiece tmp(currentPiece); + + tmp.rotateRight(); + if (!canPosition(tmp)) + return; + position(tmp); + currentPiece = tmp; +} + +void GenericTetrix::dropDown() +{ + if (currentLine == -1) + return; + + int dropHeight = 0; + int newLine = currentLine; + while(newLine) { + if (!canMoveTo(currentPos,newLine - 1)) + break; + newLine--; + dropHeight++; + } + if (dropHeight != 0) + moveTo(currentPos,newLine); + internalPieceDropped(dropHeight); +} + +void GenericTetrix::oneLineDown() +{ + if (currentLine == -1) + return; + if (canMoveTo(currentPos,currentLine - 1)) { + moveTo(currentPos,currentLine - 1); + } else { + internalPieceDropped(0); + } +} + +void GenericTetrix::newPiece() +{ + currentPiece = nextPiece; + if (showNext) + eraseNextPiece(); + nextPiece.setRandomType(); + if (showNext) + showNextPiece(); + currentLine = height - 1 + currentPiece.getMinY(); + currentPos = width/2 + 1; + if (!canMoveTo(currentPos,currentLine)) { + currentLine = -1; + gameOver(); + } else { + showPiece(); + } +} + +void GenericTetrix::removePiece() +{ + erasePiece(); + currentLine = -1; +} + +void GenericTetrix::drawNextSquare(int,int,int) +{ + +} + +void GenericTetrix::pieceDropped(int) +{ + newPiece(); +} + +void GenericTetrix::updateRemoved(int) +{ +} + +void GenericTetrix::updateScore(int) +{ +} + +void GenericTetrix::updateLevel(int) +{ +} + +void GenericTetrix::removeFullLines() +{ + int i,j,k; + int nFullLines; + + for(i = 0 ; i < height - nClearLines ; i++) { + for(j = 0 ; j < width ; j++) + if (board(j,i) == 0) + break; + if (j == width) { + nFullLines = 1; + for(k = i + 1 ; k < height - nClearLines ; k++) { + for(j = 0 ; j < width ; j++) + if (board(j,k) == 0) + break; + if (j == width) { + nFullLines++; + } else { + for(j = 0 ; j < width ; j++) { + if (board(j,k - nFullLines) != board(j,k)) { + board(j,k - nFullLines) = board(j,k); + draw( j,k - nFullLines, + board(j,k - nFullLines)); + } + } + } + } + nClearLines = nClearLines + nFullLines; + nLinesRemoved = nLinesRemoved + nFullLines; + updateRemoved(nLinesRemoved); + score = score + 10*nFullLines; // updateScore must be + // called by caller! + for (i = height - nClearLines ; + i < height - nClearLines + nFullLines ; + i++) + for(j = 0 ; j < width ; j++) + if (board(j,i) != 0) { + draw(j,i,0); + board(j,i) = 0; + } + } + } +} + +void GenericTetrix::showPiece() +{ + int x,y; + + if (currentLine == -1) + return; + + for(int i = 0 ; i < 4 ; i++) { + currentPiece.getCoord(i,x,y); + draw(currentPos + x,currentLine - y,currentPiece.getType()); + } +} + +void GenericTetrix::erasePiece() +{ + int x,y; + + if (currentLine == -1) + return; + + for(int i = 0 ; i < 4 ; i++) { + currentPiece.getCoord(i,x,y); + draw(currentPos + x,currentLine - y,0); + } +} + +void GenericTetrix::internalPieceDropped(int dropHeight) +{ + gluePiece(); + nPiecesDropped++; + if (nPiecesDropped % 25 == 0) { + level++; + updateLevel(level); + } + score = score + 7 + dropHeight; + removeFullLines(); + updateScore(score); + pieceDropped(dropHeight); +} + +void GenericTetrix::gluePiece() +{ + int x,y; + int min; + + if (currentLine == -1) + return; + + for(int i = 0 ; i < 4 ; i++) { + currentPiece.getCoord(i,x,y); + board(currentPos + x,currentLine - y) = currentPiece.getType(); + } + min = currentPiece.getMinY(); + if (currentLine - min >= height - nClearLines) + nClearLines = height - currentLine + min - 1; +} + +void GenericTetrix::showNextPiece(int erase) +{ + int x,y; + int minX = nextPiece.getMinX(); + int minY = nextPiece.getMinY(); + int maxX = nextPiece.getMaxX(); + int maxY = nextPiece.getMaxY(); + + int xOffset = (3 - (maxX - minX))/2; + int yOffset = (3 - (maxY - minY))/2; + + for(int i = 0 ; i < 4 ; i++) { + nextPiece.getCoord(i,x,y); + if (erase) + drawNextSquare(x + xOffset - minX, + y + yOffset - minY,0); + else + drawNextSquare(x + xOffset - minX, + y + yOffset - minY,nextPiece.getType()); + } +} + +int GenericTetrix::canPosition(TetrixPiece &piece) +{ + if (currentLine == -1) + return 0; + + int x,y; + + for(int i = 0 ; i < 4 ; i++) { + piece.getCoord(i,x,y); + x = currentPos + x; + y = currentLine - y; // Board and pieces have inverted y-coord. systems. + if (x < 0 || x >= width || y < 0 || y >= height) + return 0; // Outside board, cannot put piece here. + if (board(x,y) != 0) + return 0; // Over a non-zero square, cannot put piece here. + } + return 1; // Inside board and no non-zero squares underneath. + +} + +int GenericTetrix::canMoveTo(int xPosition,int line) +{ + if (currentLine == -1) + return 0; + + int x,y; + + for(int i = 0 ; i < 4 ; i++) { + currentPiece.getCoord(i,x,y); + x = xPosition + x; + y = line - y; // Board and pieces have inverted y-coord. systems. + if (x < 0 || x >= width || y < 0 || y >= height) + return 0; // Outside board, cannot put piece here. + if (board(x,y) != 0) + return 0; // Over a non-zero square, cannot put piece here. + } + return 1; // Inside board and no non-zero squares underneath. +} + +void GenericTetrix::moveTo(int xPosition,int line) +{ + if (currentLine == -1) + return; + optimizedMove(xPosition,line,currentPiece); + currentPos = xPosition; + currentLine = line; +} + +void GenericTetrix::position(TetrixPiece &piece) +{ + if (currentLine == -1) + return; + + optimizedMove(currentPos,currentLine,piece); +} + +void GenericTetrix::optimizedMove(int newPos, int newLine, + TetrixPiece &newPiece) +{ + int updates [8][3]; + int nUpdates; + int value; + int x,y; + int i,j; + + for(i = 0 ; i < 4 ; i++) { // Put the erasing coords into updates + currentPiece.getCoord(i,x,y); + updates[i][0] = currentPos + x; + updates[i][1] = currentLine - y; + updates[i][2] = 0; + } + nUpdates = 4; + for(i = 0 ; i < 4 ; i++) { // Any drawing coord same as an erasing one? + newPiece.getCoord(i,x,y); + x = newPos + x; + y = newLine - y; + for (j = 0 ; j < 4 ; j++) + if (updates[j][0] == x && updates[j][1] == y) { // Same coord, + // don't have to erase + if (currentPiece.getType() == newPiece.getType()) + updates[j][2] = -1; // Correct on screen, no update! + else + updates[j][2] = newPiece.getType(); + break; + } + if (j == 4) { // This coord does not overlap an erasing one + updates[nUpdates][0] = x; + updates[nUpdates][1] = y; + updates[nUpdates][2] = newPiece.getType(); + nUpdates++; + } + } + for (i = 0 ; i < nUpdates ; i++) { // Do the updating + x = updates[i][0]; + y = updates[i][1]; + value = updates[i][2]; + if (value != -1) // Only update if new value != current + draw(x,y,value); + } +} diff --git a/noncore/games/tetrix/gtetrix.h b/noncore/games/tetrix/gtetrix.h new file mode 100644 index 0000000..520dd89 --- a/dev/null +++ b/noncore/games/tetrix/gtetrix.h @@ -0,0 +1,104 @@ +/********************************************************************** +** 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 GTETRIX_H +#define GTETRIX_H + +#include "tpiece.h" + + +class GenericTetrix +{ +public: + GenericTetrix(int boardWidth = 10,int boardHeight = 22); + virtual ~GenericTetrix(); + + void clearBoard(int fillRandomLines = 0); + void revealNextPiece(int revealIt); + void updateBoard(int x1,int y1,int x2,int y2,int dontUpdateBlanks = 0); + void updateNext(){if (showNext) showNextPiece();} + void hideBoard(); + void showBoard(); + void fillRandom(int line); + + void moveLeft(int steps = 1); + void moveRight(int steps = 1); + void rotateLeft(); + void rotateRight(); + void dropDown(); + void oneLineDown(); + void newPiece(); + void removePiece(); + + int noOfClearLines() {return nClearLines;} + int getLinesRemoved() {return nLinesRemoved;} + int getPiecesDropped() {return nPiecesDropped;} + int getScore() {return score;} + int getLevel() {return level;} + int boardHeight() {return height;} + int boardWidth() {return width;} + + virtual void drawSquare(int x,int y,int value) = 0; + virtual void gameOver() = 0; + + virtual void startGame(int gameType = 0,int fillRandomLines = 0); + virtual void drawNextSquare(int x,int y,int value); + virtual void pieceDropped(int dropHeight); + virtual void updateRemoved(int noOfLines); + virtual void updateScore(int newScore); + virtual void updateLevel(int newLevel); + +private: + void draw(int x, int y, int value){drawSquare(x,height - y,value);} + void removeFullLines(); + void removeLine(int line); + void showPiece(); + void erasePiece(); + void internalPieceDropped(int dropHeight); + void gluePiece(); + void showNextPiece(int erase = 0); + void eraseNextPiece(){showNextPiece(1);}; + int canPosition(TetrixPiece &piece); // Returns a boolean value. + int canMoveTo(int xPosition, int line); // Returns a boolean value. + void moveTo(int xPosition,int line); + void position(TetrixPiece &piece); + void optimizedMove(int newPos, int newLine,TetrixPiece &newPiece); + + int &board(int x,int y){return boardPtr[width*y + x];} + + TetrixPiece currentPiece; + TetrixPiece nextPiece; + int currentLine; + int currentPos; + int showNext; // Boolean variable. + int nLinesRemoved; + int nPiecesDropped; + int score; + int level; + int gameID; + int nClearLines; + int width; + int height; + int *boardPtr; +}; + + +#endif diff --git a/noncore/games/tetrix/main.cpp b/noncore/games/tetrix/main.cpp new file mode 100644 index 0000000..e36d52d --- a/dev/null +++ b/noncore/games/tetrix/main.cpp @@ -0,0 +1,33 @@ +/********************************************************************** +** 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 "qtetrix.h" + +#include <qpe/qpeapplication.h> + +int main( int argc, char **argv ) +{ + QPEApplication a(argc,argv); + + QTetrix *tetrix = new QTetrix; + a.showMainWidget(tetrix); + + return a.exec(); +} diff --git a/noncore/games/tetrix/qpe-tetrix.control b/noncore/games/tetrix/qpe-tetrix.control new file mode 100644 index 0000000..46dfdf5 --- a/dev/null +++ b/noncore/games/tetrix/qpe-tetrix.control @@ -0,0 +1,10 @@ +Files: bin/tetrix apps/Games/tetrix.desktop +Priority: optional +Section: qpe/games +Maintainer: Warwick Allison <warwick@trolltech.com> +Architecture: arm +Arch: iPAQ +Version: $QPE_VERSION-3 +Depends: qpe-base ($QPE_VERSION) +Description: Game: control falling blocks + A game for the Qtopia environment. diff --git a/noncore/games/tetrix/qtetrix.cpp b/noncore/games/tetrix/qtetrix.cpp new file mode 100644 index 0000000..f649894 --- a/dev/null +++ b/noncore/games/tetrix/qtetrix.cpp @@ -0,0 +1,170 @@ +/********************************************************************** +** 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 "qtetrix.h" + +#include <qpe/resource.h> + +#include <qapplication.h> +#include <qlabel.h> +#include <qdatetime.h> +#include <qlayout.h> + + + +void drawTetrixButton( QPainter *p, int x, int y, int w, int h, + const QColor *color ) +{ + QColor fc; + if ( color ) { + QPointArray a; + a.setPoints( 3, x,y+h-1, x,y, x+w-1,y ); + p->setPen( color->light() ); + p->drawPolyline( a ); + a.setPoints( 3, x+1,y+h-1, x+w-1,y+h-1, x+w-1,y+1 ); + p->setPen( color->dark() ); + p->drawPolyline( a ); + x++; + y++; + w -= 2; + h -= 2; + fc = *color; + } + else + fc = p->backgroundColor(); + p->fillRect( x, y, w, h, fc ); +} + + +ShowNextPiece::ShowNextPiece( QWidget *parent, const char *name ) + : QFrame( parent, name ) +{ + setFrameStyle( QFrame::Panel | QFrame::Sunken ); + xOffset = -1; // -1 until first resizeEvent. +} + +void ShowNextPiece::resizeEvent( QResizeEvent *e ) +{ + QSize sz = e->size(); + blockWidth = (sz.width() - 3)/5; + blockHeight = (sz.height() - 3)/6; + xOffset = (sz.width() - 3)/5; + yOffset = (sz.height() - 3)/6; +} + + +void ShowNextPiece::paintEvent( QPaintEvent * ) +{ + QPainter p( this ); + drawFrame( &p ); + p.end(); // explicit end() so any slots can paint too + emit update(); +} + + +void ShowNextPiece::drawNextSquare(int x, int y,QColor *color) +{ + if (xOffset == -1) // Before first resizeEvent? + return; + + QPainter paint; + paint.begin(this); + drawTetrixButton( &paint, xOffset+x*blockWidth, yOffset+y*blockHeight, + blockWidth, blockHeight, color ); + paint.end(); +} + + +QTetrix::QTetrix( QWidget *parent, const char *name, WFlags f ) + : QMainWindow( parent, name, f ) +{ + setIcon( Resource::loadPixmap( "tetrix_icon" ) ); + setCaption( tr("Tetrix" ) ); + + QTime t = QTime::currentTime(); + TetrixPiece::setRandomSeed( (((double)t.hour())+t.minute()+t.second())/ + (24+60+60) ); + + QWidget *gameArea = new QWidget( this ); + setCentralWidget( gameArea ); + + QGridLayout *gl = new QGridLayout( gameArea, 5, 3, 8 ); + + QLabel *l; + l = new QLabel( tr("Next"), gameArea ); + gl->addWidget( l, 0, 0 ); + showNext = new ShowNextPiece(gameArea); + showNext->setBackgroundColor(QColor(0,0,0)); + gl->addWidget( showNext, 0, 1 ); + + l = new QLabel( tr("Score"), gameArea ); + gl->addWidget( l, 1, 0 ); + showScore = new QLabel(gameArea); + gl->addWidget( showScore, 1, 1 ); + l = new QLabel( tr("Level"), gameArea ); + gl->addWidget( l, 2, 0 ); + showLevel = new QLabel(gameArea); + gl->addWidget( showLevel, 2, 1 ); + l = new QLabel( tr("Removed"), gameArea ); + gl->addWidget( l, 3, 0 ); + showLines = new QLabel(gameArea); + gl->addWidget( showLines, 3, 1 ); + + board = new QTetrixBoard(gameArea); + board->setBackgroundColor(QColor(0,0,0)); + board->setFixedWidth( 124 ); + gl->addMultiCellWidget( board, 0, 4, 2, 2 ); + gl->addColSpacing( 2, 100 ); + gl->addColSpacing( 1, 35 ); + gl->addRowSpacing( 0, 35 ); + + QPushButton *pb = new QPushButton( tr("Start"), gameArea ); + pb->setFocusPolicy( NoFocus ); + connect( pb, SIGNAL( clicked() ), board, SLOT( start() ) ); + gl->addMultiCellWidget( pb, 4, 4, 0, 1 ); + + connect( board, SIGNAL(gameOverSignal()), SLOT(gameOver()) ); + connect( board, SIGNAL(drawNextSquareSignal(int,int,QColor*)), showNext, + SLOT(drawNextSquare(int,int,QColor*)) ); + connect( showNext, SIGNAL(update()), board, SLOT(updateNext()) ); + connect( board, SIGNAL(updateScoreSignal(int)), showScore, + SLOT(setNum(int)) ); + connect( board, SIGNAL(updateLevelSignal(int)), showLevel, + SLOT(setNum(int))); + connect( board, SIGNAL(updateRemovedSignal(int)), showLines, + SLOT(setNum(int))); + + showScore->setNum( 0 ); + showLevel->setNum( 0 ); + showLines->setNum( 0 ); + board->revealNextPiece(TRUE); + board->setFocusPolicy( StrongFocus ); +} + +void QTetrix::gameOver() +{ +} + + +void QTetrix::quit() +{ + close(); +} diff --git a/noncore/games/tetrix/qtetrix.h b/noncore/games/tetrix/qtetrix.h new file mode 100644 index 0000000..b6e058a --- a/dev/null +++ b/noncore/games/tetrix/qtetrix.h @@ -0,0 +1,78 @@ +/********************************************************************** +** 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 QTETRIX_H +#define QTETRIX_H + +#include "qtetrixb.h" +#include <qframe.h> +#include <qlcdnumber.h> +#include <qpushbutton.h> +#include <qpainter.h> +#include <qmainwindow.h> + +class QLabel; + +class ShowNextPiece : public QFrame +{ + Q_OBJECT + friend class QTetrix; +public: + ShowNextPiece( QWidget *parent=0, const char *name=0 ); +public slots: + void drawNextSquare( int x, int y,QColor *color ); +signals: + void update(); +private: + void paintEvent( QPaintEvent * ); + void resizeEvent( QResizeEvent * ); + + int blockWidth,blockHeight; + int xOffset,yOffset; +}; + + +class QTetrix : public QMainWindow +{ + Q_OBJECT +public: + QTetrix( QWidget *parent=0, const char *name=0, WFlags f=0 ); + void startGame() { board->startGame(); } + +public slots: + void gameOver(); + void quit(); +private: + void keyPressEvent( QKeyEvent *e ) { board->keyPressEvent(e); } + + QTetrixBoard *board; + ShowNextPiece *showNext; + QLabel *showScore; + QLabel *showLevel; + QLabel *showLines; +}; + + +void drawTetrixButton( QPainter *, int x, int y, int w, int h, + const QColor *color ); + + +#endif diff --git a/noncore/games/tetrix/qtetrixb.cpp b/noncore/games/tetrix/qtetrixb.cpp new file mode 100644 index 0000000..521f171 --- a/dev/null +++ b/noncore/games/tetrix/qtetrixb.cpp @@ -0,0 +1,251 @@ +/********************************************************************** +** 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 "qtetrixb.h" +#include "qtetrix.h" +#include <qtimer.h> +#include <qkeycode.h> +#include <qpainter.h> + +const int waitAfterLineTime = 500; + +QTetrixBoard::QTetrixBoard( QWidget *p, const char *name ) + : QFrame( p, name ) +{ + setFrameStyle( QFrame::Panel | QFrame::Sunken ); + paint = 0; + timer = new QTimer(this); + connect( timer, SIGNAL(timeout()), SLOT(timeout()) ); + + colors[0].setRgb(200,100,100); + colors[1].setRgb(100,200,100); + colors[2].setRgb(100,100,200); + colors[3].setRgb(200,200,100); + colors[4].setRgb(200,100,200); + colors[5].setRgb(100,200,200); + colors[6].setRgb(218,170, 0); + + xOffset = -1; // -1 until a resizeEvent is received. + blockWidth = 20; + yOffset = 30; + blockHeight = 20; + noGame = TRUE; + isPaused = FALSE; + waitingAfterLine = FALSE; + updateTimeoutTime(); // Sets timeoutTime +} + +void QTetrixBoard::startGame(int gameType,int fillRandomLines) +{ + if ( isPaused ) + return; // ignore if game is paused + noGame = FALSE; + GenericTetrix::startGame( gameType, fillRandomLines ); + // Note that the timer is started by updateLevel! +} + + +void QTetrixBoard::pause() +{ + if ( noGame ) // game not active + return; + isPaused = !isPaused; + if ( isPaused ) { + timer->stop(); + hideBoard(); + } + else + timer->start(timeoutTime); + update(); +} + + +void QTetrixBoard::drawSquare(int x,int y,int value) +{ + if (xOffset == -1) // Before first resizeEvent? + return; + + const int X = xOffset + x*blockWidth; + const int Y = yOffset + (y - 1)*blockHeight; + + bool localPainter = paint == 0; + QPainter *p; + if ( localPainter ) + p = new QPainter( this ); + else + p = paint; + drawTetrixButton( p, X, Y, blockWidth, blockHeight, + value == 0 ? 0 : &colors[value-1] ); + /* + if ( value != 0 ) { + QColor tc, bc; + tc = colors[value-1].light(); + bc = colors[value-1].dark(); + p->drawShadePanel( X, Y, blockWidth, blockHeight, + tc, bc, 1, colors[value-1], TRUE ); + } + else + p->fillRect( X, Y, blockWidth, blockHeight, backgroundColor() ); + */ + if ( localPainter ) + delete p; +} + +void QTetrixBoard::drawNextSquare( int x, int y, int value ) +{ + if ( value == 0 ) + emit drawNextSquareSignal (x, y, 0 ); + else + emit drawNextSquareSignal( x, y, &colors[value-1] ); +} + +void QTetrixBoard::updateRemoved( int noOfLines ) +{ + if ( noOfLines > 0 ) { + timer->stop(); + timer->start( waitAfterLineTime ); + waitingAfterLine = TRUE; + } + emit updateRemovedSignal( noOfLines ); +} + +void QTetrixBoard::updateScore( int newScore ) +{ + emit updateScoreSignal( newScore ); +} + +void QTetrixBoard::updateLevel( int newLevel ) +{ + timer->stop(); + updateTimeoutTime(); + timer->start( timeoutTime ); + emit updateLevelSignal( newLevel ); +} + +void QTetrixBoard::pieceDropped(int) +{ + if ( waitingAfterLine ) // give player a break if a line has been removed + return; + newPiece(); +} + +void QTetrixBoard::gameOver() +{ + timer->stop(); + noGame = TRUE; + emit gameOverSignal(); +} + +void QTetrixBoard::timeout() +{ + if ( waitingAfterLine ) { + timer->stop(); + waitingAfterLine = FALSE; + newPiece(); + timer->start( timeoutTime ); + } else { + oneLineDown(); + } +} + +void QTetrixBoard::drawContents( QPainter *p ) +{ + const char *text = "Press \"Pause\""; + QRect r = contentsRect(); + paint = p; // set widget painter + if ( isPaused ) { + p->drawText( r, AlignCenter | AlignVCenter, text ); + return; + } + int x1,y1,x2,y2; + x1 = (r.left() - xOffset) / blockWidth; + if (x1 < 0) + x1 = 0; + if (x1 >= boardWidth()) + x1 = boardWidth() - 1; + + x2 = (r.right() - xOffset) / blockWidth; + if (x2 < 0) + x2 = 0; + if (x2 >= boardWidth()) + x2 = boardWidth() - 1; + + y1 = (r.top() - yOffset) / blockHeight; + if (y1 < 0) + y1 = 0; + if (y1 >= boardHeight()) + y1 = boardHeight() - 1; + + y2 = (r.bottom() - yOffset) / blockHeight; + if (y2 < 0) + y2 = 0; + if (y2 >= boardHeight()) + y2 = boardHeight() - 1; + + updateBoard( x1, y1, x2, y2, TRUE ); + paint = 0; // reset widget painter + return; +} + +void QTetrixBoard::resizeEvent(QResizeEvent *e) +{ + QSize sz = e->size(); + blockWidth = (sz.width() - 2)/10; + blockHeight = (sz.height() - 2)/22; + xOffset = 1; + //yOffset = 1; + yOffset = (sz.height() - 2) - (blockHeight *22); +} + +void QTetrixBoard::keyPressEvent( QKeyEvent *e ) +{ + if ( noGame || isPaused || waitingAfterLine ) + return; + switch( e->key() ) { + case Key_Left : + moveLeft(); + break; + case Key_Right : + moveRight(); + break; + case Key_Down : +// rotateRight(); + dropDown(); + break; + case Key_Up : + rotateLeft(); + break; + case Key_Space : + dropDown(); + break; + case Key_D : + oneLineDown(); + break; + default: + return; + } + e->accept(); +} + +void QTetrixBoard::updateTimeoutTime() +{ + timeoutTime = 1000/(1 + getLevel()); +} diff --git a/noncore/games/tetrix/qtetrixb.h b/noncore/games/tetrix/qtetrixb.h new file mode 100644 index 0000000..4134a84 --- a/dev/null +++ b/noncore/games/tetrix/qtetrixb.h @@ -0,0 +1,80 @@ +/********************************************************************** +** 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 QTETRIXB_H +#define QTETRIXB_H + +#include "gtetrix.h" +#include <qframe.h> + +class QTimer; + +class QTetrixBoard : public QFrame, public GenericTetrix +{ + Q_OBJECT +public: + QTetrixBoard( QWidget *parent=0, const char *name=0 ); + + void gameOver(); + void startGame(int gameType = 0,int fillRandomLines = 0); + +public slots: + void timeout(); + void updateNext() { GenericTetrix::updateNext(); } + void key(QKeyEvent *e) { keyPressEvent(e); } + void start() { startGame(); } + void pause(); + +signals: + void gameOverSignal(); + void drawNextSquareSignal(int x,int y,QColor *color1); + void updateRemovedSignal(int noOfLines); + void updateScoreSignal(int score); + void updateLevelSignal(int level); + +public: // until we have keyboard focus, should be protected + void keyPressEvent( QKeyEvent * ); + +private: + void drawContents( QPainter * ); + void resizeEvent( QResizeEvent * ); + void drawSquare(int x,int y,int value); + void drawNextSquare(int x,int y,int value); + void updateRemoved(int noOfLines); + void updateScore(int newScore); + void updateLevel(int newLlevel); + void pieceDropped(int dropHeight); + void updateTimeoutTime(); + + QTimer *timer; + + int xOffset,yOffset; + int blockWidth,blockHeight; + int timeoutTime; + bool noGame; + bool isPaused; + bool waitingAfterLine; + + QColor colors[7]; + QPainter *paint; +}; + +#endif diff --git a/noncore/games/tetrix/tetrix.pro b/noncore/games/tetrix/tetrix.pro new file mode 100644 index 0000000..1160585 --- a/dev/null +++ b/noncore/games/tetrix/tetrix.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = ../bin +HEADERS = minefield.h \ + gtetrix.h \ + qtetrix.h \ + qtetrixb.h \ + tpiece.h +SOURCES = main.cpp \ + gtetrix.cpp \ + qtetrix.cpp \ + qtetrixb.cpp \ + tpiece.cpp +INCLUDEPATH += $(QPEDIR)/include +DEPENDPATH += $(QPEDIR)/include +LIBS += -lqpe +INTERFACES = diff --git a/noncore/games/tetrix/tpiece.cpp b/noncore/games/tetrix/tpiece.cpp new file mode 100644 index 0000000..fe8b766 --- a/dev/null +++ b/noncore/games/tetrix/tpiece.cpp @@ -0,0 +1,201 @@ +/********************************************************************** +** 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 "tpiece.h" +#include "qstring.h" +#include <stdlib.h> +#include <time.h> + +void TetrixPiece::rotateLeft() +{ + if ( pieceType == 5 ) // don't rotate square piece type + return; + int tmp; + for (int i = 0 ; i < 4 ; i++) { + tmp = getXCoord(i); + setXCoord(i,getYCoord(i)); + setYCoord(i,-tmp); + } +} + +void TetrixPiece::rotateRight() +{ + if ( pieceType == 5 ) // don't rotate square piece type + return; + int tmp; + for (int i = 0 ; i < 4 ; i++) { + tmp = getXCoord(i); + setXCoord(i,-getYCoord(i)); + setYCoord(i,tmp); + } +} + +int TetrixPiece::getMinX() +{ + int tmp = coordinates[0][0]; + for(int i = 1 ; i < 4 ; i++) + if (tmp > coordinates[i][0]) + tmp = coordinates[i][0]; + return tmp; +} + +int TetrixPiece::getMaxX() +{ + int tmp = coordinates[0][0]; + for(int i = 1 ; i < 4 ; i++) + if (tmp < coordinates[i][0]) + tmp = coordinates[i][0]; + return tmp; + +} + +int TetrixPiece::getMinY() +{ + int tmp = coordinates[0][1]; + for(int i = 1 ; i < 4 ; i++) + if (tmp > coordinates[i][1]) + tmp = coordinates[i][1]; + return tmp; +} + +int TetrixPiece::getMaxY() +{ + int tmp = coordinates[0][1]; + for(int i = 1 ; i < 4 ; i++) + if (tmp < coordinates[i][1]) + tmp = coordinates[i][1]; + return tmp; +} + +void TetrixPiece::initialize(int type) +{ + static int pieceTypes[7][4][2] = {{{ 0,-1}, + { 0, 0}, + {-1, 0}, + {-1, 1}}, + + {{ 0,-1}, + { 0, 0}, + { 1, 0}, + { 1, 1}}, + + {{ 0,-1}, + { 0, 0}, + { 0, 1}, + { 0, 2}}, + + {{-1, 0}, + { 0, 0}, + { 1, 0}, + { 0, 1}}, + + {{ 0, 0}, + { 1, 0}, + { 0, 1}, + { 1, 1}}, + + {{-1,-1}, + { 0,-1}, + { 0, 0}, + { 0, 1}}, + + {{ 1,-1}, + { 0,-1}, + { 0, 0}, + { 0, 1}}}; + if (type < 1 || type > 7) + type = 1; + pieceType = type; + for(int i = 0 ; i < 4 ; i++) { + coordinates[i][0] = pieceTypes[type - 1][i][0]; + coordinates[i][1] = pieceTypes[type - 1][i][1]; + } +} + + +/* + * Sigh, oh beautiful nostalgia! This random algorithm has + * been taken from the book "Adventures with your pocket calculator" + * and I used it in my first implemented and machine- + * run program of any size to speak of. Imagine how hungry I + * was after having programmed BASIC on paper for + * half a year?!!?!?!?!?!? The first program I typed in was a + * slot machine game and was made in BASIC on a SHARP + * PC-1211 with 1,47 KB RAM (one point four seven kilobytes) and + * a one-line LCD-display (I think it had 32 characters) in the + * year of our lord 1981. The man I had bought the machine from worked + * as a COBOL programmer and was amazed and impressed + * when I demonstrated the program 2 days after I had + * bought the machine, quote: "Gees, I have been looking so long + * for a "random" command in that BASIC, what is it called?" + * Oh, how I still get a thrill out of the thought of the + * explanation I then gave him... + */ + +/* + * Sukk, aa vakre nostalgi! Denne random algoritmen er + * tatt fra boka "Adventures with your pocket calculator" + * og den brukte jeg i mitt foerste implementerte og maskin- + * kjoerte program av nevneverdig stoerrelse. Tror du jeg var + * noe sulten etter aa ha programmert BASIC paa papir i et + * halvt aar?!!?!?!?!?!? Programmet jeg tasta inn foerst var et + * "enarmet banditt" spill og ble laget i BASIC paa en SHARP + * PC-1211 med 1,47 KB RAM (en komma foertisju kilobyte) og + * et en-linjers LCD-display (tror det hadde 32 karakterer) i det + * herrens aar 1981. Mannen jeg kjoepte maskinen av jobbet til + * daglig med COBOL programmering og var forbloeffet og imponert + * da jeg demonstrerte programmet 2 dager etter at jeg hadde + * kjoept maskinen, sitat: "Joess, jeg som har leita saa lenge + * etter en random kommando i den BASICen, hva var det den + * het?" Aa, jeg frydes ennaa ved tanken paa forklaringen jeg + * deretter ga ham... + */ + +double TetrixPiece::randomSeed = 0.33333; + +void TetrixPiece::setRandomSeed(double seed) +{ +#ifdef __MIPSEL__ + srand( clock() ); +#else + QCString buffer; + if (seed < 0) + seed = - seed; + if (seed >= 1) + seed = seed - (double) ((int) seed); + buffer.sprintf("%1.5f",(float) seed); + for (int i = 0 ; i < 5 ; i++) + if ((buffer[i + 2] - '0') % 2 == 0) + buffer[i + 2]++; + randomSeed = atof(buffer); +#endif +} + +int TetrixPiece::randomValue(int maxPlusOne) +{ +#ifdef __MIPSEL__ + return rand() % maxPlusOne; +#else + randomSeed = randomSeed*147; + randomSeed = randomSeed - (double) ((int) randomSeed); + return (int) (randomSeed*maxPlusOne); +#endif +} diff --git a/noncore/games/tetrix/tpiece.h b/noncore/games/tetrix/tpiece.h new file mode 100644 index 0000000..9c1c629 --- a/dev/null +++ b/noncore/games/tetrix/tpiece.h @@ -0,0 +1,62 @@ +/********************************************************************** +** 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 TPIECE_H +#define TPIECE_H + +class TetrixPiece +{ +public: + TetrixPiece() {setRandomType();} + TetrixPiece(int type) {initialize(type % 7 + 1);} + + void setRandomType() {initialize(randomValue(7) + 1);} + + void rotateLeft(); + void rotateRight(); + + int getType() {return pieceType;} + int getXCoord(int index) {return coordinates[index][0];} + int getYCoord(int index) {return coordinates[index][1];} + void getCoord(int index,int &x,int&y){x = coordinates[index][0]; + y = coordinates[index][1];} + int getMinX(); + int getMaxX(); + int getMinY(); + int getMaxY(); + + static void setRandomSeed(double seed); + static int randomValue(int maxPlusOne); + +private: + void setXCoord(int index,int value) {coordinates[index][0] = value;} + void setYCoord(int index,int value) {coordinates[index][1] = value;} + void setCoords(int index,int x,int y){coordinates[index][0] = x; + coordinates[index][1] = y;} + void initialize(int type); + + int pieceType; + int coordinates[4][2]; + + static double randomSeed; +}; + +#endif 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 <qpe/qpeapplication.h> + +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 @@ +<!DOCTYPE UI><UI> +<class>NewGameBase</class> +<widget> + <class>QWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Form1</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>290</width> + <height>443</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Form1</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>8</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>3</number> + </property> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>GroupBox1</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Players</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>7</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>2</number> + </property> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player0</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player1</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player2</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player3</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player4</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QComboBox</class> + <item> + <property> + <name>text</name> + <string></string> + </property> + </item> + <item> + <property> + <name>text</name> + <string>AI3: Smart AI player</string> + </property> + </item> + <property stdset="1"> + <name>name</name> + <cstring>player5</cstring> + </property> + <property stdset="1"> + <name>editable</name> + <bool>true</bool> + </property> + </widget> + </vbox> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>GroupBox2</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Rules</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>7</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>2</number> + </property> + <widget> + <class>QComboBox</class> + <property stdset="1"> + <name>name</name> + <cstring>rules</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property> + <name>name</name> + <cstring>Spacer1</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Vertical</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout1</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <spacer> + <property> + <name>name</name> + <cstring>Horizontal Spacing2</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonOk</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>&Start</string> + </property> + <property stdset="1"> + <name>autoDefault</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>default</name> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +</UI> 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 <warwick@trolltech.com> +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 @@ +<!DOCTYPE UI><UI> +<class>RulesBase</class> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>RulesBase</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>283</width> + <height>264</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Game Rules</string> + </property> + <property stdset="1"> + <name>sizeGripEnabled</name> + <bool>false</bool> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>11</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout3</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Name:</string> + </property> + </widget> + <widget> + <class>QLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>gamename</cstring> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>GroupBox3</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Board</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>5</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>4</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel2</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + </sizepolicy> + </property> + <property stdset="1"> + <name>text</name> + <string>Size:</string> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>width</cstring> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>15</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>3</number> + </property> + <property stdset="1"> + <name>value</name> + <number>15</number> + </property> + </widget> + <widget> + <class>QSpinBox</class> + <property stdset="1"> + <name>name</name> + <cstring>height</cstring> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>15</number> + </property> + <property stdset="1"> + <name>minValue</name> + <number>3</number> + </property> + <property stdset="1"> + <name>value</name> + <number>15</number> + </property> + </widget> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>editboard</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Edit...</string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QTable</class> + <property stdset="1"> + <name>name</name> + <cstring>tiletable</cstring> + </property> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout3</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonDelete</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Delete</string> + </property> + <property stdset="1"> + <name>autoDefault</name> + <bool>true</bool> + </property> + </widget> + <spacer> + <property> + <name>name</name> + <cstring>Horizontal Spacing2</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonOk</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>&OK</string> + </property> + <property stdset="1"> + <name>autoDefault</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>default</name> + <bool>true</bool> + </property> + </widget> + <widget> + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>buttonCancel</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>&Cancel</string> + </property> + <property stdset="1"> + <name>autoDefault</name> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>RulesBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>RulesBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +</UI> 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 <qpe/applnk.h> +#include <qpe/global.h> +#include <qpe/filemanager.h> +#include <qpe/resource.h> +#include <qpe/config.h> + +#include <qapplication.h> +#include <qmessagebox.h> +#include <qcombobox.h> +#include <qdatetime.h> +#include <qfileinfo.h> +#include <qfile.h> +#include <qdir.h> +#include <qiconset.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qtextstream.h> +#include <qtimer.h> +#include <qpe/qpetoolbar.h> +#include <qtoolbutton.h> +#include <qvbox.h> +#include <qwidgetstack.h> +#include <qpainter.h> +#include <qlayout.h> +#include <qregexp.h> + +#include <stdlib.h> +#include <unistd.h> +#include <pwd.h> +#include <sys/types.h> + +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; p<nplayers; p++) { + cfg.setGroup("Player"+QString::number(p+1)); + if ( gameover ) cfg.clearGroup(); else rack(p)->writeConfig(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; p<nplayers; p++) { + cfg.setGroup("Player"+QString::number(p+1)); + rack(p)->readConfig(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<vtiles; i++) { + QString line; + ts >> 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; i<nplayers; i++) + if ( !rack(i)->count() ) + 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; i<nplayers; i++) { + Rack* r = rack(i); + int c = r->count(); + if ( c ) { + int lose=0; + for ( int j=0; j<c; j++ ) + lose += r->tileRef(j)->value(); + totalleft += lose; + scoreinfo->addScore(i,-lose); + } else { + out = i; + } + } + int highest=0; + int winner=0; + for (i=0; i<nplayers; i++) { + int s = scoreinfo->playerScore(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; i<rack->count(); 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; x<rc; x++ ) { + if ( !(used&msk) ) { + const Tile* t = rack->tileRef(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; i<n; i++ ) + st += tiles[i]->text(); +qDebug("%d,%d: %s (%d) for %d",current.x(),current.y(),st.latin1(),n,s); +} +*/ + if ( s > best_score ) { + int i; + for ( i=0; i<n; i++ ) + best[i] = tiles[i]; + for ( i=0; i<blused; i++ ) + best_blankvalues[i] = blankvalues[i]; + best_n = n; + best_blused = blused; + best_score = s; + best_dir = d; + best_start = current; + } +} + +int TileItem::smallWidth() +{ + return 16; +} + +int TileItem::smallHeight() +{ + return 16; +} + +int TileItem::bigWidth() +{ + return 22; +} + +int TileItem::bigHeight() +{ + return 22; +} + +void TileItem::setState( State state ) +{ + hide(); + s = state; + show(); // ### use update() in Qt 3.0 +} + +void TileItem::setTile(const Tile& tile) +{ + hide(); + t = tile; + show(); // ### use update() in Qt 3.0 +} + +void TileItem::setBig(bool b) +{ + big = b; +} + +void TileItem::drawShape(QPainter& p) +{ + static QFont value_font("heletica",8); + static QFont big_font("smoothtimes",17); + static QFont small_font("smoothtimes",10); + + QRect area(x(),y(),width(),height()); + p.setBrush(s == Floating ? yellow/*lightGray*/ : white); + p.drawRect(area); + if ( big ) { + p.setFont(value_font); + QString n = QString::number(t.value()); + int w = p.fontMetrics().width('1'); + int h = p.fontMetrics().height(); + w *= n.length(); + QRect valuearea(x()+width()-w-2,y()+height()-h+1,w,h); + p.drawText(valuearea,AlignCenter,n); + p.setFont(big_font); + area = QRect(x(),y(),width()-2,height()-1); + } else { + p.setFont(small_font); + area = QRect(x(),y()+2,width(),height()-2); + } + if ( t.value() == 0 ) + p.setPen(darkGray); + p.drawText(area,AlignCenter,t.text().upper()); +} + +Board::Board(QPixmap bgshapes, int w, int h, QWidget* parent) : + QCanvasView(new QCanvas(bgshapes,w,h, TileItem::smallWidth(), TileItem::smallHeight()), + parent) +{ + grid = new TileItem*[w*h]; + memset(grid,0,w*h*sizeof(TileItem*)); + setFrameStyle(0); + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); + current_rack = 0; + shown_n = 0; +} + +Board::~Board() +{ + delete canvas(); +} + +void Board::writeConfig(Config& cfg) +{ + QStringList t; + int n=canvas()->tilesHorizontally()*canvas()->tilesVertically(); + for (int i=0; i<n; i++) + t.append( grid[i] ? grid[i]->tile().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; i<n; i++) { + delete grid[i]; + grid[i]=0; + } +} + + +void Board::setCurrentRack(Rack* r) +{ + turn_score = -1; + current_rack = r; +} + +void Board::resetRack() +{ + unshowTurn(); + canvas()->update(); +} + +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 ( i<shown_n && contains(at) ) { + if ( item(at) && item(at)->state() == 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 ( i<shown_n && i<current_rack->count() && 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 ( i<shown_n && i<current_rack->count() && 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; i<n; i++) { + tiles[i] = current_rack->tileRef(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; b<bl; b++) { + QString v = le[b]->text(); + 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("<p>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; i<n; i++) + tiles[i] = current_rack->tileRef(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)) || i<n); ) { + if ( t ) { + if ( checkdict || words ) mainword += t->text(); + 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<yTiles(); y++) { + for (int x=0; x<xTiles(); x++) { + int re = shapes[i++]-'0'; + if ( re > 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; i<ntiles; i++) + item[i]=0; + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); + canvas()->setBackgroundColor(gray); + dragging = 0; +} + +Rack::~Rack() +{ + clear(); + delete canvas(); +} + +void Rack::clear() +{ + for (int i=0; i<n; i++) + delete item[i]; + n=0; +} + +void Rack::writeConfig(Config& cfg) +{ + QStringList l; + for (int i=0; i<n; i++) + l.append(tile(i).key()); + cfg.writeEntry("Tiles",l,';'); +} + +void Rack::readConfig(Config& cfg) +{ + clear(); + int x=0; + QStringList l = cfg.readListEntry("Tiles",';'); + for (QStringList::ConstIterator it=l.begin(); it!=l.end(); ++it) { + TileItem *i = new TileItem(Tile(*it),TRUE,canvas()); + i->move(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; i<n ;i++) + if ( item[i] == dragging ) { + item[i]->setZ(1); + } else { + item[i]->move(i*w, 0); + item[i]->setZ(0); + } + canvas()->update(); +} + +void Rack::setBlanks(const Tile* bv) +{ + for (int j=0; j<n; j++) { + Tile tt = item[j]->tile(); + 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; j<n; j++) { + Tile tt = item[j]->tile(); + int f=-1; + for (int i=0; i<sn && f<0; i++) { + if (s[i] && *s[i] == tt ) { + s[i]=0; + f=i; + } + } + if ( f >= 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; i<n ;i++) + if ( item[i]->tile() == t ) { + remove(i); + return; + } +} + +void Rack::remove(int i) +{ + delete item[i]; + n--; + for (;i<n;i++) + item[i]=item[i+1]; + layoutTiles(); +} + +void Rack::resizeEvent(QResizeEvent* e) +{ + canvas()->resize(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<Tile> 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("<P>",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="<p>"; + int i=0; + //int spl=(names.count()+1)/2; // 2 lines + for (QStringList::ConstIterator it=names.begin(); it!=names.end(); ) { + if ( i==boldone ) r += "<b>"; + QString n = *it; + n.replace(QRegExp(":.*"),""); + r += n; + r += ":"; + r += QString::number(score[i]); + if ( i==boldone ) r += "</b>"; + + ++i; + ++it; + if ( it != names.end() ) + r += " "; + } + setText(r); +} + +void ScoreInfo::showTemporaryScore(int amount) +{ + if ( amount < 0 ) + setText(tr("<P>Invalid move")); + else + setText(tr("<P>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 <qpe/qdawg.h> +#include <qpe/applnk.h> + +#include <qmainwindow.h> +#include <qcanvas.h> +#include <qlabel.h> + +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<Tile> 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<TileItem*> 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 |