From c90c389a8a8d9d8661e9772ec4144c5cf2039f23 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegames@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kenolaba/AbTop.cpp | 988 ++++++++++++++++++++++ kenolaba/AbTop.h | 152 ++++ kenolaba/Ball.cpp | 492 +++++++++++ kenolaba/Ball.h | 155 ++++ kenolaba/Board.cpp | 1493 +++++++++++++++++++++++++++++++++ kenolaba/Board.h | 198 +++++ kenolaba/BoardWidget.cpp | 1027 +++++++++++++++++++++++ kenolaba/BoardWidget.h | 116 +++ kenolaba/ChangeLog | 35 + kenolaba/EvalDlg.ui | 1760 +++++++++++++++++++++++++++++++++++++++ kenolaba/EvalDlgImpl.cpp | 299 +++++++ kenolaba/EvalDlgImpl.h | 44 + kenolaba/EvalScheme.cpp | 231 +++++ kenolaba/EvalScheme.h | 61 ++ kenolaba/Makefile.am | 21 + kenolaba/Move.cpp | 261 ++++++ kenolaba/Move.h | 132 +++ kenolaba/Network.cpp | 193 +++++ kenolaba/Network.h | 60 ++ kenolaba/README | 23 + kenolaba/Spy.cpp | 155 ++++ kenolaba/Spy.h | 46 + kenolaba/TODO | 8 + kenolaba/bitmaps/Arrow1 | 8 + kenolaba/bitmaps/Arrow1Mask | 6 + kenolaba/bitmaps/Arrow2 | 8 + kenolaba/bitmaps/Arrow2Mask | 6 + kenolaba/bitmaps/Arrow3 | 8 + kenolaba/bitmaps/Arrow3Mask | 6 + kenolaba/bitmaps/Arrow4 | 8 + kenolaba/bitmaps/Arrow4Mask | 6 + kenolaba/bitmaps/Arrow5 | 8 + kenolaba/bitmaps/Arrow5Mask | 6 + kenolaba/bitmaps/Arrow6 | 8 + kenolaba/bitmaps/Arrow6Mask | 6 + kenolaba/bitmaps/Makefile.am | 1 + kenolaba/hi128-app-kenolaba.png | Bin 0 -> 15572 bytes kenolaba/hi16-app-kenolaba.png | Bin 0 -> 879 bytes kenolaba/hi22-app-kenolaba.png | Bin 0 -> 1369 bytes kenolaba/hi32-app-kenolaba.png | Bin 0 -> 2388 bytes kenolaba/hi48-app-kenolaba.png | Bin 0 -> 4346 bytes kenolaba/hi64-app-kenolaba.png | Bin 0 -> 6254 bytes kenolaba/kenolaba.cpp | 71 ++ kenolaba/kenolaba.desktop | 64 ++ kenolaba/kenolabaui.rc | 53 ++ kenolaba/toolbar/Makefile.am | 7 + kenolaba/toolbar/edit.xpm | 38 + kenolaba/toolbar/help.xpm | 29 + kenolaba/toolbar/hint.xpm | 31 + kenolaba/toolbar/network.xpm | 35 + kenolaba/toolbar/new.xpm | 36 + kenolaba/toolbar/noball.xpm | 22 + kenolaba/toolbar/ok.xpm | 25 + kenolaba/toolbar/redball.xpm | 25 + kenolaba/toolbar/spy0.xpm | 39 + kenolaba/toolbar/spy1.xpm | 38 + kenolaba/toolbar/spy2.xpm | 40 + kenolaba/toolbar/spy3.xpm | 38 + kenolaba/toolbar/stop.xpm | 30 + kenolaba/toolbar/undo.xpm | 27 + kenolaba/toolbar/warning.xpm | 26 + kenolaba/toolbar/yellowball.xpm | 25 + kenolaba/version.h | 1 + 63 files changed, 8735 insertions(+) create mode 100644 kenolaba/AbTop.cpp create mode 100644 kenolaba/AbTop.h create mode 100644 kenolaba/Ball.cpp create mode 100644 kenolaba/Ball.h create mode 100644 kenolaba/Board.cpp create mode 100644 kenolaba/Board.h create mode 100644 kenolaba/BoardWidget.cpp create mode 100644 kenolaba/BoardWidget.h create mode 100644 kenolaba/ChangeLog create mode 100644 kenolaba/EvalDlg.ui create mode 100644 kenolaba/EvalDlgImpl.cpp create mode 100644 kenolaba/EvalDlgImpl.h create mode 100644 kenolaba/EvalScheme.cpp create mode 100644 kenolaba/EvalScheme.h create mode 100644 kenolaba/Makefile.am create mode 100644 kenolaba/Move.cpp create mode 100644 kenolaba/Move.h create mode 100644 kenolaba/Network.cpp create mode 100644 kenolaba/Network.h create mode 100644 kenolaba/README create mode 100644 kenolaba/Spy.cpp create mode 100644 kenolaba/Spy.h create mode 100644 kenolaba/TODO create mode 100644 kenolaba/bitmaps/Arrow1 create mode 100644 kenolaba/bitmaps/Arrow1Mask create mode 100644 kenolaba/bitmaps/Arrow2 create mode 100644 kenolaba/bitmaps/Arrow2Mask create mode 100644 kenolaba/bitmaps/Arrow3 create mode 100644 kenolaba/bitmaps/Arrow3Mask create mode 100644 kenolaba/bitmaps/Arrow4 create mode 100644 kenolaba/bitmaps/Arrow4Mask create mode 100644 kenolaba/bitmaps/Arrow5 create mode 100644 kenolaba/bitmaps/Arrow5Mask create mode 100644 kenolaba/bitmaps/Arrow6 create mode 100644 kenolaba/bitmaps/Arrow6Mask create mode 100644 kenolaba/bitmaps/Makefile.am create mode 100644 kenolaba/hi128-app-kenolaba.png create mode 100644 kenolaba/hi16-app-kenolaba.png create mode 100644 kenolaba/hi22-app-kenolaba.png create mode 100644 kenolaba/hi32-app-kenolaba.png create mode 100644 kenolaba/hi48-app-kenolaba.png create mode 100644 kenolaba/hi64-app-kenolaba.png create mode 100644 kenolaba/kenolaba.cpp create mode 100644 kenolaba/kenolaba.desktop create mode 100644 kenolaba/kenolabaui.rc create mode 100644 kenolaba/toolbar/Makefile.am create mode 100644 kenolaba/toolbar/edit.xpm create mode 100644 kenolaba/toolbar/help.xpm create mode 100644 kenolaba/toolbar/hint.xpm create mode 100644 kenolaba/toolbar/network.xpm create mode 100644 kenolaba/toolbar/new.xpm create mode 100644 kenolaba/toolbar/noball.xpm create mode 100644 kenolaba/toolbar/ok.xpm create mode 100644 kenolaba/toolbar/redball.xpm create mode 100644 kenolaba/toolbar/spy0.xpm create mode 100644 kenolaba/toolbar/spy1.xpm create mode 100644 kenolaba/toolbar/spy2.xpm create mode 100644 kenolaba/toolbar/spy3.xpm create mode 100644 kenolaba/toolbar/stop.xpm create mode 100644 kenolaba/toolbar/undo.xpm create mode 100644 kenolaba/toolbar/warning.xpm create mode 100644 kenolaba/toolbar/yellowball.xpm create mode 100644 kenolaba/version.h (limited to 'kenolaba') diff --git a/kenolaba/AbTop.cpp b/kenolaba/AbTop.cpp new file mode 100644 index 00000000..a2283f16 --- /dev/null +++ b/kenolaba/AbTop.cpp @@ -0,0 +1,988 @@ +/* Class AbTop */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AbTop.h" +#include "Board.h" +#include "BoardWidget.h" +#include "EvalDlgImpl.h" +#include "EvalScheme.h" +#include "Network.h" +#include "Spy.h" +#include "version.h" + +#include +#include + +// #define MYTRACE 1 + +const AbTop::Data AbTop::LEVEL[Nb_Levels] = { + { "Easy", I18N_NOOP("&Easy") }, + { "Normal", I18N_NOOP("&Normal") }, + { "Hard", I18N_NOOP("&Hard") }, + { "Challange", I18N_NOOP("&Challenge") } +}; + +const AbTop::Data AbTop::IPLAY[Nb_IPlays] = { + { "Red", I18N_NOOP("&Red") }, + { "Yellow", I18N_NOOP("&Yellow") }, + { "Both", I18N_NOOP("&Both") }, + { "None", I18N_NOOP("&None") } +}; + +AbTop::AbTop() + :KMainWindow(0) +{ + timerState = noGame; + + myPort = Network::defaultPort; + currentEvalScheme = 0; + net = 0; + + actValue = 0; + stop = false; + editMode = false; + spyLevel = 0; + pastePossible = true; + + + timer = new QTimer; + connect( timer, SIGNAL(timeout()), this, SLOT(timerDone()) ); + + board = new Board(); + setMoveNo(0); + + connect( board, SIGNAL(searchBreak()), this, SLOT(searchBreak()) ); + Q_CHECK_PTR(board); + boardWidget = new BoardWidget(*board,this); + +#ifdef SPION + spy = new Spy(*board); +#endif + + connect( boardWidget, SIGNAL(updateSpy(QString)), + this, SLOT(updateSpy(QString)) ); + + setCentralWidget(boardWidget); + boardWidget->show(); + + // this creates the GUI + setupActions(); + setupStatusBar(); + setMinimumSize(200,300); + + // RMB context menu + connect( boardWidget, SIGNAL(rightButtonPressed(int,const QPoint&)), + this, SLOT(rightButtonPressed(int,const QPoint&)) ); + + connect( boardWidget, SIGNAL(edited(int)), + this, SLOT(edited(int)) ); + + connect( board, SIGNAL(updateBestMove(Move&,int)), + this, SLOT(updateBestMove(Move&,int)) ); + + connect( boardWidget, SIGNAL(moveChoosen(Move&)), + this, SLOT(moveChoosen(Move&)) ); + + /* default */ + setLevel(Easy); + setIPlay(Red); + showMoveLong = true; + showSpy = false; + renderBalls = true; + + updateStatus(); + updateActions(); + setupGUI(); +} + +AbTop::~AbTop() +{ + /* Unregister from other abalone processes */ + delete net; + delete timer; +#ifdef SPION + delete spy; +#endif +} + + +/** + * Create all the actions... + * + * The GUI will be built in createGUI using a XML file + * + */ + +void AbTop::setupActions() +{ + newAction = KStdGameAction::gameNew( this, SLOT(newGame()), actionCollection() ); + KStdGameAction::quit( this, SLOT(close()), actionCollection() ); + + stopAction = new KAction( i18n("&Stop Search"), "stop", Key_S, this, + SLOT(stopSearch()), actionCollection(), "move_stop"); + + backAction = new KAction( i18n("Take &Back"), "back", + KStdAccel::shortcut(KStdAccel::Prior), this, + SLOT(back()), actionCollection(), "move_back"); + + forwardAction = new KAction( i18n("&Forward"), "forward", + KStdAccel::shortcut(KStdAccel::Next), this, + SLOT(forward()), actionCollection(), "move_forward"); + + hintAction = KStdGameAction::hint(this, SLOT(suggestion()), actionCollection()); + + KStdAction::copy( this, SLOT(copy()), actionCollection()); + pasteAction = KStdAction::paste( this, SLOT(paste()), actionCollection()); + + (void) new KAction( i18n("&Restore Position"), + KStdAccel::shortcut(KStdAccel::Open), + this, SLOT(restorePosition()), + actionCollection(), "edit_restore" ); + + (void) new KAction( i18n("&Save Position"), + KStdAccel::shortcut(KStdAccel::Save), + this, SLOT(savePosition()), + actionCollection(), "edit_save" ); + + KToggleAction *ta; + + ta = new KToggleAction( i18n("&Network Play"), "network", Key_N, + actionCollection(), "game_net"); + connect(ta, SIGNAL(toggled(bool)), this, SLOT(gameNetwork(bool))); + + editAction = new KToggleAction( i18n("&Modify"), "edit", + CTRL+Key_Insert, actionCollection(), "edit_modify"); + connect(editAction, SIGNAL(toggled(bool)), this, SLOT( editModify(bool))); + + showMenubar = KStdAction::showMenubar(this, SLOT(toggleMenubar()), actionCollection()); + KStdAction::saveOptions( this, SLOT(writeConfig()), actionCollection()); + + KStdAction::preferences( this, SLOT(configure()), actionCollection()); + + moveSlowAction = new KToggleAction( i18n("&Move Slow"), 0, + actionCollection(), "options_moveSlow"); + connect(moveSlowAction, SIGNAL(toggled(bool)), this, SLOT(optionMoveSlow(bool))); + + renderBallsAction = new KToggleAction( i18n("&Render Balls"), 0, + actionCollection(), "options_renderBalls"); + connect(renderBallsAction, SIGNAL(toggled(bool)), this, SLOT(optionRenderBalls(bool))); + + showSpyAction = new KToggleAction( i18n("&Spy"), 0, + actionCollection(), "options_showSpy"); + connect(showSpyAction, SIGNAL(toggled(bool)), this, SLOT(optionShowSpy(bool))); + + + levelAction = KStdGameAction::chooseGameType(0, 0, actionCollection()); + QStringList list; + for (uint i=0; isetItems(list); + connect(levelAction, SIGNAL(activated(int)), SLOT(setLevel(int))); + + iplayAction = new KSelectAction(i18n("&Computer Play"), 0, actionCollection(), "options_iplay"); + list.clear(); + for (uint i=0; isetItems(list); + connect(iplayAction, SIGNAL(activated(int)), SLOT(setIPlay(int))); +} + +void AbTop::toggleMenubar() +{ + if (menuBar()->isVisible()) + menuBar()->hide(); + else + menuBar()->show(); +} + +void AbTop::configure() +{ + KDialogBase *dlg = new KDialogBase( 0, "ConfigureEvaluation", true, + i18n("Configure Evaluation"), + KDialogBase::Ok | KDialogBase::Cancel, + KDialogBase::Ok, true); + + EvalDlgImpl *edlg = new EvalDlgImpl(dlg,board); + dlg->setMainWidget(edlg); + if (dlg->exec()) { + *currentEvalScheme = *(edlg->evalScheme()); + board->setEvalScheme(currentEvalScheme); + } + delete edlg; +} + +/* Right Mouse button pressed in BoardWidget area */ +void AbTop::rightButtonPressed(int /* field */, const QPoint& pos) +{ + QPopupMenu* rmbMenu = static_cast (factory()->container("rmbPopup",this)); + if (rmbMenu) + rmbMenu->popup( pos ); +} + +/* Read config options + * + * menu must already be created! + */ +void AbTop::readConfig() +{ + kdDebug(12011) << "Reading config..." << endl; + + KConfig* config = kapp->config(); + config->setGroup("Options"); + + readOptions(config); + + applyMainWindowSettings( config, "Appearance" ); + + showMenubar->setChecked( !menuBar()->isHidden() ); + + currentEvalScheme = new EvalScheme("Current"); + currentEvalScheme->read(config); + board->setEvalScheme( currentEvalScheme ); +} + +void AbTop::readOptions(KConfig* config) +{ + QString entry = config->readEntry("Level"); + for (uint i=0; ireadEntry("Computer"); + for (uint i=0; ireadBoolEntry("MoveSlow", false); + moveSlowAction->setChecked( showMoveLong ); + + renderBalls = config->readBoolEntry("RenderBalls", true); + boardWidget->renderBalls(renderBalls); + renderBallsAction->setChecked( renderBalls ); + + showSpy = config->readBoolEntry("ShowSpy", true); + board->updateSpy(showSpy); + showSpyAction->setChecked( showSpy ); +} + +void AbTop::readProperties(KConfig *config) +{ + QString entry; + + readOptions(config); + + currentEvalScheme = new EvalScheme("Current"); + currentEvalScheme->read(config); + board->setEvalScheme( currentEvalScheme ); + + + if (!(entry = config->readEntry("TimerState")).isNull()) + timerState = entry.toInt(); + if (timerState == noGame) return; + + stop = config->readBoolEntry("GameStopped", false); + + int mNo = 0; + if (!(entry = config->readEntry("Position")).isNull()) { + mNo = board->setState(entry); + boardWidget->updatePosition(true); + } + setMoveNo(mNo, true); + + show(); + playGame(); +} + +void AbTop::writeConfig() +{ + kdDebug(12011) << "Writing config..." << endl; + + KConfig* config = kapp->config(); + config->setGroup("Options"); + + writeOptions(config); + + saveMainWindowSettings( config, "Appearance" ); + + if (currentEvalScheme) + currentEvalScheme->save(config); + config->sync(); +} + + +void AbTop::writeOptions(KConfig *config) +{ + config->writeEntry("Level", LEVEL[levelAction->currentItem()].key); + config->writeEntry("Computer", IPLAY[iplayAction->currentItem()].key); + + config->writeEntry("MoveSlow", showMoveLong); + config->writeEntry("RenderBalls", renderBalls); + config->writeEntry("ShowSpy", showSpy); +} + +void AbTop::saveProperties(KConfig *config) +{ + writeOptions(config); + if (currentEvalScheme) + currentEvalScheme->save(config); + + config->writeEntry("TimerState", timerState); + + if (timerState == noGame) return; + + config->writeEntry("GameStopped", stop); + config->writeEntry("Position", board->getState(moveNo)); + config->sync(); +} + +void AbTop::savePosition() +{ + KConfig* config = kapp->config(); + config->setGroup("SavedPosition"); + config->writeEntry("Position", board->getState(moveNo)); +} + +void AbTop::restorePosition() +{ + KConfig* config = kapp->config(); + config->setGroup("SavedPosition"); + QString entry = config->readEntry("Position"); + + timerState = notStarted; + timer->stop(); + board->begin(Board::color1); + stop = false; + setMoveNo( board->setState(entry), true ); + + if (net) + net->broadcast( board->getASCIIState( moveNo ).ascii() ); + + boardWidget->updatePosition(true); + + playGame(); +} + +void AbTop::setupStatusBar() +{ + QString tmp; + + QString t = i18n("Press %1 for a new game").arg( newAction->shortcut().toString()); + statusLabel = new QLabel( t, statusBar(), "statusLabel" ); + statusBar()->addWidget(statusLabel,1,false); + + // PERMANENT: Moving side + move No. + + // validPixmap, only visible in Modify mode: is position valid ? + warningPix = BarIcon( "warning" ); + okPix = BarIcon( "ok" ); + validLabel = new QLabel( "", statusBar(), "validLabel" ); + validLabel->setFixedSize( 18, statusLabel->sizeHint().height() ); + validLabel->setAlignment( AlignCenter ); + validLabel->hide(); + validShown = false; + + redBall = BarIcon( "redball" ); + yellowBall = BarIcon( "yellowball" ); + noBall = BarIcon( "noball" ); + ballLabel = new QLabel( "", statusBar(), "ballLabel" ); + ballLabel->setPixmap(noBall); + ballLabel->setFixedSize( 18, statusLabel->sizeHint().height() ); + ballLabel->setAlignment( AlignCenter ); + statusBar()->addWidget(ballLabel, 0, true); + + moveLabel = new QLabel( i18n("Move %1").arg("--"), statusBar(), "moveLabel" ); + statusBar()->addWidget(moveLabel, 0, true); + +#ifdef MYTRACE + /* Create a toolbar menu for debugging output level */ + KToolBar *tb = toolBar("mainToolBar"); + if (tb) { + QPopupMenu* spyPopup = new QPopupMenu; + spy0 = BarIcon( "spy0" ); + spy1 = BarIcon( "spy1" ); + spy2 = BarIcon( "spy2" ); + spy3 = BarIcon( "spy3" ); + spyPopup->insertItem(spy0, 0); + spyPopup->insertItem(spy1, 1); + spyPopup->insertItem(spy2, 2); + spyPopup->insertItem(spy3, 3); + connect( spyPopup, SIGNAL(activated(int)), + this, SLOT(setSpy(int)) ); + tb->insertButton(spy0, 30, spyPopup, + TRUE, i18n("Spy")); + } +#endif + +} + + + +void AbTop::updateSpy(QString s) +{ + if (showSpy) { + if (s.isEmpty()) { + updateStatus(); + // statusBar()->clear(); + } + else + statusLabel->setText(s); + } +} + +void AbTop::updateBestMove(Move& m, int value) +{ + if (showSpy) { + boardWidget->showMove(m,3); + boardWidget->showMove(m,0,false); + + QString tmp; + tmp.sprintf("%s : %+d", (const char*) m.name().utf8(), value-actValue); + updateSpy(tmp); + kapp->processEvents(); + } +} + + +void AbTop::updateStatus() +{ + QString tmp; + bool showValid = false; + + if (!editMode && timerState == noGame) { + tmp = i18n("Move %1").arg("--"); + ballLabel->setPixmap(noBall); + } + else { + tmp = i18n("Move %1").arg(moveNo/2 + 1); + ballLabel->setPixmap( (board->actColor() == Board::color1) + ? redBall : yellowBall); + } + moveLabel->setText(tmp); + + if (editMode) { + tmp = QString("%1: %2 %3 - %4 %5") + .arg( i18n("Edit") ) + .arg( i18n("Red") ).arg(boardWidget->getColor1Count()) + .arg( i18n("Yellow") ).arg(boardWidget->getColor2Count()); + validLabel->setPixmap( (board->validState() == Board::invalid) + ? warningPix:okPix ); + showValid = true; + } + else if (timerState == noGame) { + tmp = i18n("Press %1 for a new game").arg( newAction->shortcut().toString()); + } + else { + if (timerState == gameOver) { + tmp = (board->actColor() == Board::color2) ? + i18n("Red won"):i18n("Yellow won"); + validLabel->setPixmap( warningPix ); + showValid = true; + } + else { + tmp = QString("%1 - %2") + .arg( (board->actColor() == Board::color1) ? + i18n("Red"):i18n("Yellow") ) + .arg( iPlayNow() ? + i18n("I am thinking...") : i18n("It is your turn!") ); + } + } + statusLabel->setText(tmp); + if (validShown != showValid) { + if (showValid) { + statusBar()->addWidget(validLabel); + validLabel->show(); + } + else { + statusBar()->removeWidget(validLabel); + validLabel->hide(); + } + validShown = showValid; + } + statusBar()->clear(); + statusBar()->repaint(); +} + +void AbTop::edited(int vState) +{ + if (vState == Board::empty) + timerState = noGame; + + updateStatus(); +} + +/* only , , have to be updated */ +void AbTop::updateActions() +{ + bool iPlay = iPlayNow(); + + /* New && Copy always on */ + + /* Paste */ + pastePossible = !iPlay; + pasteAction->setEnabled(!iPlay); + + /* Edit */ + editAction->setEnabled(!iPlay); + + /* Stop search */ + stopAction->setEnabled(iPlay); + + /* Back */ + bool bBack = (editMode && moveNo>0) || + (board->movesStored() >=1 && !iPlay); + backAction->setEnabled(bBack); + + /* Forward */ + bool bForward = editMode && moveNo<999; + forwardAction->setEnabled(bForward); + + /* Hint */ + bool bHint = !editMode && !iPlay && (haveHint().type != Move::none); + hintAction->setEnabled(bHint); +} + +/* let the program be responsive even in a long search... */ +void AbTop::searchBreak() +{ + kapp->processEvents(); +} + + +void AbTop::setSpy(int id ) +{ + toolBar("mainToolBar")->setButtonPixmap(30, (id==0)?spy0:(id==1)?spy1:(id==2)?spy2:spy3 ); + spyLevel = id; + board->setSpyLevel(spyLevel); +} + +void AbTop::timerDone() +{ + int interval = 400; + + switch(timerState) { + case noGame: + case notStarted: + return; + case showMove: + case showMove+2: + case showSugg: + case showSugg+2: + case showSugg+4: + boardWidget->showMove(actMove, 2); + interval = 200; + break; + case showMove+1: + case showMove+3: + case showSugg+1: + case showSugg+3: + boardWidget->showMove(actMove, 3); + break; + case showSugg+5: + interval = 800; + case showMove+4: + boardWidget->showMove(actMove, 4); + break; + case showMove+5: + boardWidget->showMove(actMove, 0); + timerState = moveShown; + playGame(); + return; + case showSugg+6: + boardWidget->showMove(actMove, 0); + timerState = notStarted; + return; + } + timerState++; + timer->start(interval,TRUE); +} + +void AbTop::userMove() +{ + /* User has to move */ + static MoveList list; + + list.clear(); + board->generateMoves(list); + + if (list.getLength() == 0) { + stop = true; + timerState = gameOver; + playGame(); + } + else + boardWidget->choseMove(&list); +} + +bool AbTop::iPlayNow() +{ + if (editMode || + (board->validState() != Board::valid) || + timerState == gameOver) + return false; + + int c = board->actColor(); + + /* color1 is red */ + return ((iplay == Both) || + ((c == Board::color1) && (iplay == Red) ) || + ((c == Board::color2) && (iplay == Yellow) )); +} + +void AbTop::playGame() +{ + if (timerState == moveShown) { + if (actMove.type != Move::none) { + board->playMove(actMove); + moveNo++; // actColor in board is changed in playMove + + if (net) + net->broadcast( board->getASCIIState( moveNo ).ascii() ); + } + actValue = - board->calcEvaluation(); + boardWidget->updatePosition(true); + timerState = notStarted; + } + if (!board->isValid()) { + stop = true; + timerState = gameOver; + } + + updateStatus(); + updateActions(); + boardWidget->setCursor(crossCursor); + if (stop) return; + + + if (!iPlayNow()) { + userMove(); + return; + } + boardWidget->setCursor(waitCursor); + kapp->processEvents(); + + if (moveNo <4) { + /* Chose a random move making the position better for actual color */ + + /* If comparing ratings among color1/2 on move, we have to negate one */ + int v = -board->calcEvaluation(), vv; + do { + actMove = board->randomMove(); + board->playMove(actMove); + vv = board->calcEvaluation(); + board->takeBack(); + } while( (board->actColor() == Board::color1) ? (vvv) ); + } + else { + actMove = (board->bestMove()); + + if (actMove.type == Move::none) { + stop = true; + timerState = gameOver; + playGame(); + return; + } + } + + timerState = showMoveLong ? showMove : showMove+3; + timerDone(); +} + +void AbTop::moveChoosen(Move& m) +{ + actMove = m; + timerState = moveShown; + playGame(); +} + +void AbTop::newGame() +{ + /* stop a running animation */ + timerState = notStarted; + timer->stop(); + + /* reset board */ + board->begin(Board::color1); + boardWidget->updatePosition(true); + setMoveNo(0, true); + + if (net) + net->broadcast( board->getASCIIState( moveNo ).ascii() ); + + /* if not in EditMode, start Game immediately */ + if (!editMode) { + stop = false; + playGame(); + } +} + +/* Copy ASCII representation into Clipboard */ +void AbTop::copy() +{ + QClipboard *cb = QApplication::clipboard(); + cb->setText( board->getASCIIState( moveNo ).ascii() ); +} + +void AbTop::paste() +{ + if (!pastePossible) return; + + QClipboard *cb = QApplication::clipboard(); + pastePosition( cb->text().ascii() ); + /* don't do this in pastePosition: RECURSION !! */ + + if (net) + net->broadcast( board->getASCIIState( moveNo ).ascii() ); +} + +void AbTop::pastePosition(const char * text) +{ + if (!pastePossible) return; + if ( text ) { + timerState = notStarted; + timer->stop(); + board->begin(Board::color1); + stop = false; + + int mNo = board->setASCIIState(text); + if (mNo<0) mNo=0; + setMoveNo( mNo, true); + + boardWidget->updatePosition(true); + + if ( (board->validState()==Board::invalid) && !editMode) { + editAction->setChecked(true); + return; + } + + playGame(); + } +} + + +void AbTop::gameNetwork(bool on) +{ + if (!on) { + if (net != 0) { + delete net; + net = 0; + } + return; + } + + if (myPort == 0) myPort = Network::defaultPort; + net = new Network(myPort); + char *h, h2[100]; + int p, i; + for(h = hosts.first(); h!=0; h=hosts.next()) { + for(i=0;h[i]!=0 && h[i]!=':';i++); + if (h[i]==':') + p = atoi(h+i+1); + else + p = 0; + + if (p == 0) p = Network::defaultPort; + strncpy(h2,h,i); + h2[i]=0; + net->addListener(h2, p); + } + QObject::connect(net, SIGNAL(gotPosition(const char *)), + this, SLOT(pastePosition(const char *)) ); +} + + +void AbTop::editModify(bool on) +{ + int vState = board->validState(); + + editMode = boardWidget->setEditMode( on ); + if (vState != Board::valid) + timerState = noGame; + + updateActions(); + updateStatus(); + if (!editMode && vState == Board::valid) { + actMove.type = Move::none; + timerState = moveShown; + playGame(); + } +} + +void AbTop::stopGame() +{ + stop = true; + board->stopSearch(); +} + +void AbTop::stopSearch() +{ + // When computer plays both, switch back to human for next color + if (iplay == Both) { + if (board->actColor() == Board::color1) setIPlay(Red); + else setIPlay(Yellow); + } + board->stopSearch(); +} + +bool AbTop::queryClose() +{ + board->stopSearch(); + return true; +} + +void AbTop::continueGame() +{ + if (timerState != noGame && timerState != gameOver) { + stop = false; + if (timerState == notStarted) + playGame(); + } +} + +/** + * Reset the Move number of the actual game to + * If is true, update GUI actions and redraw statusbar + */ +void AbTop::setMoveNo(int m, bool updateGUI) +{ + moveNo = m; + + board->setActColor( ((moveNo%2)==0) ? Board::color1 : Board::color2 ); + + if (updateGUI) { + updateStatus(); + updateActions(); + } +} + + +/* "Back" action activated + * + * If in edit mode, simple go 1 back + * If in a game, go back 2 if possible + */ +void AbTop::back() +{ + if (editMode) { + if (moveNo > 0) + setMoveNo(moveNo-1, true); + return; + } + + if (moveNo < 1) return; + + if (timerState == gameOver) + timerState = notStarted; + if (timerState != notStarted) return; + + /* If possible, go 2 steps back */ + if (moveNo>0 && board->takeBack()) moveNo--; + if (moveNo>0 && board->takeBack()) moveNo--; + setMoveNo( moveNo, true ); + + boardWidget->updatePosition(true); + + userMove(); +} + +/* Only for edit Mode */ +void AbTop::forward() +{ + if (editMode) { + if (moveNo < 999) + setMoveNo(moveNo+1, true); + return; + } +} + +Move AbTop::haveHint() +{ + static Move m; + static int oldMoveNo = 0; + + if (timerState != notStarted) { + m.type = Move::none; + } + else if (moveNo != oldMoveNo) { + MoveList list; + + oldMoveNo = moveNo; + m = board->nextMove(); + board->generateMoves(list); + if (!list.isElement(m,0)) + m.type = Move::none; + } + return m; +} + + +void AbTop::suggestion() +{ + if (timerState != notStarted) return; + Move m = haveHint(); + if (m.type == Move::none) return; + + actMove = m; + + timerState = showSugg; + timerDone(); +} + +void AbTop::setLevel(int l) +{ + levelAction->setCurrentItem(l); + depth = l+2; + board->setDepth(depth); + // kdDebug(12011) << "Level set to " << d << endl; +} + +void AbTop::setIPlay(int i) +{ + iplayAction->setCurrentItem(i); + iplay = (IPlay)i; + continueGame(); +} + +void AbTop::optionMoveSlow(bool on) +{ + showMoveLong = on; +} + +void AbTop::optionRenderBalls(bool on) +{ + renderBalls = on; + boardWidget->renderBalls(renderBalls); +} + +void AbTop::optionShowSpy(bool on) +{ + showSpy = on; + board->updateSpy(showSpy); + +#ifdef SPION + if (showSpy) + spy->show(); + else { + spy->nextStep(); + spy->hide(); + } +#endif + +} + + +#include "AbTop.moc" diff --git a/kenolaba/AbTop.h b/kenolaba/AbTop.h new file mode 100644 index 00000000..35357452 --- /dev/null +++ b/kenolaba/AbTop.h @@ -0,0 +1,152 @@ +/* Class AbTop: the toplevel widget of Kenolaba + * + * Josef Weidendorfer, 9/97 +*/ + +#ifndef _ABTOP_H_ +#define _ABTOP_H_ + +#include + +#include "Move.h" + + +class QTimer; +class QPopupMenu; +class QLabel; + +class KAction; +class KToggleAction; +class KSelectAction; + +class Network; +class Board; +class BoardWidget; +class Move; +class EvalScheme; + +#ifdef SPION +class Spy; +#endif + + + +class AbTop: public KMainWindow +{ + Q_OBJECT + +public: + AbTop(); + ~AbTop(); + + /* timer states */ + enum { noGame, gameOver, notStarted, moveShown, + showMove = 100, showSugg=200 + }; + + void netPort(int p) { myPort = p; } + void netHost(char* h) { hosts.append(h); } + +protected: + virtual void saveProperties( KConfig * ); + virtual void readProperties( KConfig * ); + + +public slots: + void timerDone(); + void newGame(); + void copy(); + void paste(); + void pastePosition(const char *); + void stopGame(); + void continueGame(); + bool queryClose(); + void back(); + void forward(); + void suggestion(); + void stopSearch(); + void searchBreak(); + void moveChoosen(Move&); + void savePosition(); + void restorePosition(); + void setSpy(int); + void updateSpy(QString); + void edited(int); + void updateBestMove(Move&,int); + void readConfig(); + void writeConfig(); + void rightButtonPressed(int,const QPoint&); + + void gameNetwork(bool); + void editModify(bool); + void optionMoveSlow(bool); + void optionRenderBalls(bool); + void optionShowSpy(bool); + void toggleMenubar(); + void configure(); + void setLevel(int); + void setIPlay(int); + +private: + void setupActions(); + void updateStatus(); + void userMove(); + void playGame(); + void loadPixmaps(); + void setupStatusBar(); + void updateActions(); + void setMoveNo(int, bool updateGUI = false); + bool iPlayNow(); + Move haveHint(); + void readOptions(KConfig *); + void writeOptions(KConfig *); + + Move actMove; + Board* board; + int actValue; + BoardWidget *boardWidget; + EvalScheme* currentEvalScheme; + QTimer *timer; + int timerState; + int depth, moveNo; + bool showMoveLong, stop, showSpy; + bool editMode, renderBalls; + int spyLevel; + bool pastePossible, validShown; + + enum IPlay { Red = 0, Yellow, Both, None, Nb_IPlays }; + IPlay iplay; + + int stop_id, back_id, hint_id; + int easy_id, normal_id, hard_id, challange_id, slow_id, level_id; + int render_id; + int yellow_id, red_id, both_id, none_id, iplay_id; + int spy_id, paste_id, edit_id, forward_id, net_id; + + QLabel *validLabel, *ballLabel, *moveLabel, *statusLabel; + QPixmap warningPix, okPix, redBall, yellowBall, noBall, netPix; + QPixmap spy0, spy1, spy2, spy3; + + Network *net; + int myPort; + QStrList hosts; + + KAction *newAction, *stopAction, *backAction, *forwardAction, *hintAction, *pasteAction; + KToggleAction *showMenubar, *renderBallsAction, *moveSlowAction, + *showSpyAction, *editAction; + KSelectAction *levelAction, *iplayAction; + + struct Data { + const char *key, *label; + }; + enum Level { Easy = 0, Normal, Hard, Challenge, Nb_Levels }; + static const Data LEVEL[Nb_Levels]; + static const Data IPLAY[AbTop::Nb_IPlays]; + +#ifdef SPION + Spy* spy; +#endif + +}; + +#endif /* _ABTOP_H_ */ diff --git a/kenolaba/Ball.cpp b/kenolaba/Ball.cpp new file mode 100644 index 00000000..565ef296 --- /dev/null +++ b/kenolaba/Ball.cpp @@ -0,0 +1,492 @@ +/* Ball animation classes */ + +#include "Ball.h" +#include +#include +#include +#include +#include +#include + +Ball* Ball::first = 0; +//QImage Ball::back; +int Ball::sizeX, Ball::sizeY; +double Ball::lightX, Ball::lightY, Ball::lightZ; +QColor Ball::lightColor; +double Ball::rippleCount, Ball::rippleDepth; + +/* set global Ball parameter */ +void Ball::setSize(int x, int y) +{ + sizeX = x; + sizeY = y; + + invalidate(); +} + +void Ball::invalidate() +{ + Ball *b; + + /* invalidate all Balls... */ + for(b=first;b!=0;b=b->next) + b->pm.resize(0,0); +} + +void Ball::setLight(int x, int y, int z, const QColor& c) +{ + double len = sqrt(double(x*x + y*y + z*z)); + + lightX = x/len; + lightY = y/len; + lightZ = z/len; + + lightColor = c; + + invalidate(); +} + + +void Ball::setTexture(double c, double d) +{ + rippleCount = c; + rippleDepth = d; + + invalidate(); +} + + + +Ball::Ball(const QColor& c, double a, int t) +{ + if (first ==0) { + sizeX = sizeY = -1; + setLight(); + setTexture(7,.3); + } + + bColor = c; + an = a; + sina = sin(a), cosa = cos(a); + + zoom= 1.05, flip = 2.0, limit = 0; + tex = t; + + next = first; + first = this; +} + +Ball::~Ball() +{ + Ball* b; + + if (first == this) + first = next; + else { + for(b = first; b!=0; b=b->next) + if (b->next == this) break; + if (b!=0) + b->next = next; + } +} + +QPixmap* Ball::pixmap() +{ + if (pm.isNull() && sizeX>0 && sizeY>0) + render(); + return ± +} + +void Ball::render() +{ + int x,y; + double xx,yy,zz, ll,lll, red,green,blue; + + if (sizeX==0 || sizeY==0) + return; + + QImage image(sizeX,sizeY,32); + image.fill(0); + + double vv=2./(sizeX+sizeY); + + /* Go through all pixels, mapping x/y to (-1..1,-1..1) */ + for(y=0;yflip) zz=2*flip-zz; + else { + zz -= limit; + } + + if (zz>-vv) { + zz = (zz<0) ? 0 : sqrt(zz); + + /* ll: light intensity at this point */ + ll = xx*lightX + yy*lightY + zz*lightZ; + + /* some face modification */ + double mapx = xx*(2-zz); + double mapy = yy*(2-zz); + double rmapx = cosa*mapx + sina*mapy; /* rotate */ + double rmapy = -sina*mapx + cosa*mapy; + + if (tex>0) + ll += rippleDepth* cos(rippleCount*rmapx)*cos(rippleCount*rmapy); + + ll = (ll<0.01) ? 0.0 : (ll>.99) ? 1.0 : ll; + lll = ll*ll; + + // printf("x %f, y %f, z %f : ll %f lll %f\n", xx,yy,zz,ll,lll); + + + /* mix ball+light */ + red = lll * lightColor.red() + (1-lll) * bColor.red(); + green = lll * lightColor.green() + (1-lll) * bColor.green(); + blue = lll * lightColor.blue() + (1-lll) * bColor.blue(); + + /* lightness */ + red = .2 * bColor.red() + .8 * ll * red; + green = .2 * bColor.green() + .8 * ll * green; + blue = .2 * bColor.blue() + .8 * ll * blue; + + image.setPixel(x,y, qRgb( (int)red, (int)green, (int)blue )); + } + } + } + const QImage iMask = image.createHeuristicMask(); + QBitmap bMask; + bMask = iMask; + pm.convertFromImage( image, 0 ); + pm.setMask(bMask); +} + + +/* Class BallAnimation */ + +BallAnimation::BallAnimation(int s, Ball* ball1, Ball* ball2) +{ + QColor c1 = ball1->ballColor(); + double a1 = ball1->angle(); + int r1 = c1.red(), g1 = c1.green(), b1 = c1.blue(); + + QColor c2 = ball2->ballColor(); + double a2 = ball2->angle(); + int r2 = c2.red(), g2 = c2.green(), b2 = c2.blue(); + + QColor c; + double a; + int i; + + steps = s; + s--; + + balls.append( new Ball( c1,a1 ) ); + + for(i=1; i< s; i++) { + c.setRgb( r1+(r2-r1)*i/s, g1+(g2-g1)*i/s, b1+(b2-b1)*i/s ); + a = a1+(a2-a1)*i/s; + + balls.append( new Ball( c,a ) ); + } + + balls.append( new Ball( c2,a2 ) ); +} + + +/* Class BallPosition */ +BallPosition::BallPosition(int xp,int yp, Ball* d) +{ + x=xp; + y=yp; + def=d; + actStep = -1; + actType = ANIMATION_STOPPED; + actAnimation=0; +} + + +/* Class BallWidget */ + +BallWidget::BallWidget( int _freq, int bFr, QWidget *parent, const char *name ) + : QWidget(parent,name), positions(MAX_POSITION), animations(MAX_ANIMATION) +{ + int i; + + for(i=0;i= MAX_ANIMATION) return; + + if (animations[no] !=0) + delete animations[no]; + + animations[no] = new BallAnimation(s,b1,b2); +} + + +/* X, Y are coordinates in a virtual 1000x1000 area */ +void BallWidget::createBallPosition(int no, int x, int y, Ball* def) +{ + if (no<0 || no>= MAX_POSITION) return; + + if (positions[no] !=0) + delete positions[no]; + + positions[no] = new BallPosition(x,y, def); +} + +void BallWidget::startAnimation(int pos, int anim, int type) +{ + BallPosition *p; + + if (pos<0 || pos>=MAX_POSITION || positions[pos]==0) return; + if (anim<0 || anim>=MAX_ANIMATION || animations[anim]==0) return; + + p = positions.at(pos); + p->actAnimation = animations.at(anim); + + /* One step *BEFORE* start */ + p->actStep = -1; + p->actDir = 1; + p->actType = type; + + if (!isRunning) { + isRunning = true; + timer->start( 0, true ); + } +} + +/* If LOOP: Set to ONESHOT, otherwise set to last frame */ +void BallWidget::stopAnimation(int pos) +{ + BallPosition *p; + + if (pos<0 || pos>=MAX_POSITION || positions[pos]==0) return; + + p = positions.at(pos); + if (p->actType == ANIMATION_STOPPED || + p->actAnimation == 0) return; + + if (p->actType == ANIMATION_LOOP || + p->actType == ANIMATION_CYCLE) { + p->actType = ANIMATION_FORWARD; + // return; + } + /* Set last step: animate() does the rest */ + p->actDir = 1; + p->actStep = p->actAnimation->steps; +} + +void BallWidget::resizeEvent(QResizeEvent *) +{ + int w = width() *10/12, h = height(); + + realSize = (w>h) ? h:w; + + Ball::setSize( realSize/ballFraction, realSize/ballFraction ); + repaint(); +} + +void BallWidget::paintEvent(QPaintEvent *) +{ + paint(this); +} + + +void BallWidget::paint(QPaintDevice *pd) +{ + int i; + BallPosition *p; + int xReal, yReal; + + int w = width(), h = height(); + + if (realSize<0) return; + + for(i=0;ix * realSize / 500 - Ball::w() )/2; + yReal = (h + p->y * realSize / 500 - Ball::h() )/2; + + if (p->actAnimation==0 || p->actStep==-1) { + if (p->def !=0 ) + bitBlt( pd, xReal, yReal, p->def->pixmap() ); + } + else { + int s = p->actStep; + if (s>= p->actAnimation->steps) + s = p->actAnimation->steps-1; + Ball* b = p->actAnimation->balls.at(s); + bitBlt( pd, xReal, yReal, b->pixmap() ); + } + } +} + +void BallWidget::animate() +{ + bool doAnimation = false; + + int i; + BallPosition *p; + int xReal, yReal; + int w = width(), h = height(); + + for(i=0;iactType == ANIMATION_STOPPED || + p->actAnimation ==0) continue; + + p->actStep += p->actDir; + if (p->actStep <= -1) { + p->actDir = 1; + p->actStep = 1; + doAnimation = true; + } + else if (p->actStep >= p->actAnimation->steps) { + if (p->actType == ANIMATION_CYCLE) { + p->actDir = -1; + p->actStep = p->actAnimation->steps -2; + doAnimation = true; + } + else if (p->actType == ANIMATION_LOOP) { + p->actStep = 1; /*skip first frame for smooth animation */ + doAnimation = true; + } + else { + p->actType = ANIMATION_STOPPED; + p->actAnimation = 0; + emit animationFinished(i); + } + } + else { + doAnimation = true; + } + + /* Update Pixmap */ + xReal = (w + p->x * realSize / 500 - Ball::w() )/2; + yReal = (h + p->y * realSize / 500 - Ball::h() )/2; + if (p->actAnimation==0 || p->actStep==-1) { + if (p->def !=0 ) + bitBlt( this, xReal, yReal, p->def->pixmap() ); + } + else { + int s = p->actStep; + if (s>= p->actAnimation->steps) + s = p->actAnimation->steps-1; + Ball* b = p->actAnimation->balls.at(s); + bitBlt( this, xReal, yReal, b->pixmap() ); + } + } + if (!doAnimation) { + isRunning = false; + emit animationsFinished(); + } + else { + timer->start(1000/freq,true); + } + + // repaint( false ); +} + + +/* Ball Test */ + + +BallTest::BallTest( QWidget *parent, const char *name ) + : BallWidget(10,2,parent,name) +{ + int w,h; + + w = h = 150; + resize(w,h); + // Ball::setSize( w/2, h/2, this ); + + Ball *b1 = new Ball( green ); + Ball *b2 = new Ball( yellow ); + Ball *b3 = new Ball( red ); + Ball *b4 = new Ball( red, 3.14/2 ); + + createBlending(0,5,b1,b2); + createBallPosition( 0,250, 250, b1); + + createBlending(1,10,b1,b3); + createBallPosition(1, 250, 750, b1); + + createBlending(2,15,b3,b2); + createBallPosition( 2, 750, 250, b3); + + createBlending(3,20,b3,b4); + createBallPosition(3, 750, 750, b3); +} + +/* +void BallTest::paintEvent( QPaintEvent * ) +{ + bitBlt(this,0,0, b.pixmap()); +} +*/ + +void BallTest::mousePressEvent( QMouseEvent * ) +{ + startAnimation(0,0, ANIMATION_CYCLE); + startAnimation(1,1); + startAnimation(2,2); + startAnimation(3,3, ANIMATION_LOOP); +} + +void BallTest::mouseReleaseEvent( QMouseEvent * ) +{ + stopAnimation(0); + stopAnimation(1); + stopAnimation(3); +} + +/* Test... + +#include + +int main(int argc, char *argv[]) +{ + zoom=.52; + flip=.85; + limit=.75; + + KApplication app(argc, argv, "BallTest"); + BallTest top; + + app.setMainWidget( &top ); + top.show(); + return app.exec(); +} + +*/ +#include "Ball.moc" diff --git a/kenolaba/Ball.h b/kenolaba/Ball.h new file mode 100644 index 00000000..1a3e0d28 --- /dev/null +++ b/kenolaba/Ball.h @@ -0,0 +1,155 @@ +/* Class Ball, BallWidget + * + * Online rendered balls with caching + animation widget + * + * Supported static effects + * - ball color + * - ripple texture + * + * Supported animation sequences for now: + * - Color Blending + * - Texture rotate + * + * April 1999, Josef Weidendorfer + */ + +#ifndef _BALL_H_ +#define _BALL_H_ + +#include +#include +#include +#include +#include + +/* textures for balls */ +#define TEX_FLAT 0 +#define TEX_RIPPLE 1 + +class Ball { + + public: + Ball(const QColor& c, double a = 0.0, int t=TEX_RIPPLE ); + ~Ball(); + + QPixmap* pixmap(); + + double angle() { return an; } + QColor ballColor() { return bColor; } + void setSpecials(double z, double f, double l) + { zoom = z, flip=f, limit=l; } + + static int w() { return sizeX; } + static int h() { return sizeY; } + static void setSize(int x,int y); + static void setLight(int x=5, int y=3, int z=10, + const QColor& c = QColor(200,230,255) ); + static void setTexture(double c=13., double d=.2); + + private: + + void render(); + static void invalidate(); + + //static QImage back; + static int sizeX, sizeY; + static double lightX, lightY, lightZ; + static QColor lightColor; + static double rippleCount, rippleDepth; + + QPixmap pm; + QColor bColor; + double an, sina, cosa; + double zoom, flip, limit; + int tex; + + Ball *next; + static Ball* first; +}; + + +class BallAnimation { + public: + BallAnimation(int s, Ball*, Ball*); + + int steps; + QPtrList balls; +}; + +#define ANIMATION_STOPPED 0 +#define ANIMATION_FORWARD 1 +#define ANIMATION_BACK 2 +#define ANIMATION_LOOP 3 +#define ANIMATION_CYCLE 4 + +class BallPosition { + public: + BallPosition(int xp,int yp, Ball* d); + + int x, y, actStep, actDir, actType; + Ball* def; + BallAnimation* actAnimation; +}; + +#define MAX_POSITION 130 +#define MAX_ANIMATION 20 + +class BallWidget : public QWidget +{ + Q_OBJECT + + public: + BallWidget(int _freq, int bFr, QWidget *parent = 0, const char *name = 0); + ~BallWidget(); + + void createBlending(int, int, Ball* , Ball* ); + void createBallPosition(int, int x, int y, Ball*); + + void startAnimation(int pos, int anim, int type=ANIMATION_FORWARD); + void stopAnimation(int pos); + + void paint(QPaintDevice *); + + virtual void resizeEvent(QResizeEvent *); + virtual void paintEvent(QPaintEvent *); + + signals: + void animationFinished(int); + void animationsFinished(void); + + protected: + void drawBackground(); + + private slots: + void animate(); + + protected: + QMemArray positions; + QMemArray animations; + + private: + int freq; + int xStart, yStart, realSize, ballFraction; + bool isRunning; + QTimer *timer; +}; + + +/* Ball Test */ + +class BallTest: public BallWidget +{ + Q_OBJECT +public: + BallTest(QWidget *parent=0, const char *name=0 ); +protected: + void mousePressEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + + +}; + + + + +#endif // _BALL_H_ diff --git a/kenolaba/Board.cpp b/kenolaba/Board.cpp new file mode 100644 index 00000000..b8546fbc --- /dev/null +++ b/kenolaba/Board.cpp @@ -0,0 +1,1493 @@ +/* Class Board + * + * with methods for + * - play/take back moves + * - generate allowed moves + * - calculate rating for position + * - search for best move + * + * Josef Weidendorfer, 28.8.97 +*/ + +#include + +#include +#include + +#include +#include + +#include "Board.h" +#include "EvalScheme.h" + +// #define MYTRACE 1 + +#if 0 +#define CHECK(b) Q_ASSERT(b) +#else +#define CHECK(b) +#endif + + +static int ratedPositions, wonPositions, searchCalled, moveCount; +static int normalCount, pushCount, outCount, cutoffCount; + +/*********************** Class PrincipalVariation *************************/ + +void PrincipalVariation::clear(int d) +{ + int i,j; + + for(i=0;iactMaxDepth) return; + for(i=d+1;i<=actMaxDepth;i++) { + move[d][i]=move[d+1][i]; + move[d+1][i].type = Move::none; + } + move[d][d]=m; +} + + + +/****************************** Class Board ****************************/ + + +/* Board for start of a game */ +int Board::startBoard[]={ + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10, + 10, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10, + 10, 0, 0, 1, 1, 1, 0, 0, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 10, 10, 10, 0, 0, 2, 2, 2, 0, 0, 10, + 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 10, + 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; + + +/* first centrum of board, then rings around (numbers are indexes) */ +int Board::order[]={ + 60, + 61,72,71,59,48,49, + 62,73,84,83,82,70,58,47,36,37,38,50, + 63,74,85,96,95,94,93,81,69,57,46,35,24,25,26,27,39,51, + 64,75,86,97,108,107,106,105,104,92,80,68,56,45,34,23,12, + 13,14,15,16,28,40,52 }; + +/* See EvalScheme.{h|cpp} + * + // Ratings for fields are calculated out of these values + // (see setFieldValues) + int Board::ringValue[] = { 45, 35, 25, 10, 0 }; + int Board::ringDiff[] = { 0, 10, 10, 8, 5 }; + + // Value added to board rating according to the difference of + // stones in game of player1 and player2 + int Board::stoneValue[]= { 0,-800,-1800,-3000,-4400,-6000 }; + + // Default Values for moves values (see Move.h) + int Board::moveValue[]= { 40,30,30, 15,14,13, 5,5,5, 2,2,2, 1 }; + + // Default Values for inARow values (see Move.h) + int Board::inARowValue[]= { 2, 5, 4, 3 }; +*/ + +int Board::fieldValue[61]; +int Board::direction[]= { -11,1,12,11,-1,-12,-11,1 }; + + +Board::Board() +{ + clear(); + breakOut = bUpdateSpy = false; + spyLevel = 1; + spyDepth = 0; + debug = 0; + realMaxDepth = 1; + _evalScheme = 0; +} + +void Board::setEvalScheme(EvalScheme* scheme) +{ + if (!scheme) + scheme = new EvalScheme( QString("Default") ); + + _evalScheme = scheme; + setFieldValues(); +} + +void Board::setFieldValues() +{ + if (!_evalScheme) return; + + int i, j = 0, k = 59; + int ringValue[5], ringDiff[5]; + + for(i=0;i<5;i++) { + ringDiff[i] = _evalScheme->ringDiff(i); + ringValue[i] = _evalScheme->ringValue(i); + if (ringDiff[i]<1) ringDiff[i]=1; + } + + fieldValue[0] = ringValue[0]; + for(i=1;i<7;i++) + fieldValue[i] = ringValue[1] + ((j+=k) % ringDiff[1]); + for(i=7;i<19;i++) + fieldValue[i] = ringValue[2] + ((j+=k) % ringDiff[2]); + for(i=19;i<37;i++) + fieldValue[i] = ringValue[3] + ((j+=k) % ringDiff[3]); + for(i=37;i<61;i++) + fieldValue[i] = ringValue[4] + ((j+=k) % ringDiff[4]); +} + + + +void Board::begin(int startColor) +{ + int i; + + for(i=0;i */ +void Board::generateFieldMoves(int startField, MoveList& list) +{ + int d, dir, c, actField; + bool left, right; + int opponent = (color == color1) ? color2 : color1; + + Q_ASSERT( field[startField] == color ); + + /* 6 directions */ + for(d=1;d<7;d++) { + dir = direction[d]; + + /* 2nd field */ + c = field[actField = startField+dir]; + if (c == free) { + /* (c .) */ + list.insert(startField, d, Move::move1); + continue; + } + if (c != color) + continue; + + /* 2nd == color */ + + left = (field[startField+direction[d-1]] == free); + if (left) { + left = (field[actField+direction[d-1]] == free); + if (left) + /* 2 left */ + list.insert(startField, d, Move::left2); + } + + right = (field[startField+direction[d+1]] == free); + if (right) { + right = (field[actField+direction[d+1]] == free); + if (right) + /* 2 right */ + list.insert(startField, d, Move::right2); + } + + /* 3rd field */ + c = field[actField += dir]; + if (c == free) { + /* (c c .) */ + list.insert(startField, d, Move::move2); + continue; + } + else if (c == opponent) { + + /* 4th field */ + c = field[actField += dir]; + if (c == free) { + /* (c c o .) */ + list.insert(startField, d, Move::push1with2); + } + else if (c == out) { + /* (c c o |) */ + list.insert(startField, d, Move::out1with2); + } + continue; + } + if (c != color) + continue; + + /* 3nd == color */ + + if (left) { + if (field[actField+direction[d-1]] == free) + /* 3 left */ + list.insert(startField, d, Move::left3); + } + + if (right) { + if (field[actField+direction[d+1]] == free) + /* 3 right */ + list.insert(startField, d, Move::right3); + } + + /* 4th field */ + c = field[actField += dir]; + if (c == free) { + /* (c c c .) */ + list.insert(startField, d, Move::move3); + continue; + } + if (c != opponent) + continue; + + /* 4nd == opponent */ + + /* 5. field */ + c = field[actField += dir]; + if (c == free) { + /* (c c c o .) */ + list.insert(startField, d, Move::push1with3); + continue; + } + else if (c == out) { + /* (c c c o |) */ + list.insert(startField, d, Move::out1with3); + continue; + } + if (c != opponent) + continue; + + /* 5nd == opponent */ + + /* 6. field */ + c = field[actField += dir]; + if (c == free) { + /* (c c c o o .) */ + list.insert(startField, d, Move::push2); + } + else if (c == out) { + /* (c c c o o |) */ + list.insert(startField, d, Move::out2); + } + } +} + + +void Board::generateMoves(MoveList& list) +{ + int actField, f; + + for(f=0;f delete oldest entry */ + if (storedLast == storedFirst) + if (++storedFirst == MvsStored) storedFirst = 0; + + storedMove[storedLast] = m; + + f = m.field; + CHECK( (m.type >= 0) && (m.type < Move::none)); + CHECK( field[f] == color ); + field[f] = free; + dir = direction[m.direction]; + + switch(m.type) { + case Move::out2: /* (c c c o o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == opponent ); + CHECK( field[f + 4*dir] == opponent ); + CHECK( field[f + 5*dir] == out ); + field[f + 3*dir] = color; + break; + case Move::out1with3: /* (c c c o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == opponent ); + CHECK( field[f + 4*dir] == out ); + field[f + 3*dir] = color; + break; + case Move::move3: /* (c c c .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == free ); + field[f + 3*dir] = color; + break; + case Move::out1with2: /* (c c o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == opponent ); + CHECK( field[f + 3*dir] == out ); + field[f + 2*dir] = color; + break; + case Move::move2: /* (c c .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == free ); + field[f + 2*dir] = color; + break; + case Move::push2: /* (c c c o o .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == opponent ); + CHECK( field[f + 4*dir] == opponent ); + CHECK( field[f + 5*dir] == free ); + field[f + 3*dir] = color; + field[f + 5*dir] = opponent; + break; + case Move::left3: + dir2 = direction[m.direction-1]; + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + dir2] == free ); + CHECK( field[f + dir+dir2] == free ); + CHECK( field[f + 2*dir+dir2] == free ); + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + break; + case Move::right3: + dir2 = direction[m.direction+1]; + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + dir2] == free ); + CHECK( field[f + dir+dir2] == free ); + CHECK( field[f + 2*dir+dir2] == free ); + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + break; + case Move::push1with3: /* (c c c o .) => (. c c c o) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == opponent ); + CHECK( field[f + 4*dir] == free ); + field[f + 3*dir] = color; + field[f + 4*dir] = opponent; + break; + case Move::push1with2: /* (c c o .) => (. c c o) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == opponent ); + CHECK( field[f + 3*dir] == free ); + field[f + 2*dir] = color; + field[f + 3*dir] = opponent; + break; + case Move::left2: + dir2 = direction[m.direction-1]; + CHECK( field[f + dir] == color ); + CHECK( field[f + dir2] == free ); + CHECK( field[f + dir+dir2] == free ); + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + break; + case Move::right2: + dir2 = direction[m.direction+1]; + CHECK( field[f + dir] == color ); + CHECK( field[f + dir2] == free ); + CHECK( field[f + dir+dir2] == free ); + field[f+dir2] = color; + field[f+=dir] = free; + field[f+dir2] = color; + break; + case Move::move1: /* (c .) => (. c) */ + CHECK( field[f + dir] == free ); + field[f + dir] = color; + break; + default: + break; + } + + if (m.isOutMove()) { + if (color == color1) + color2Count--; + else + color1Count--; + } + + /* change actual color */ + color = opponent; + + CHECK( isConsistent() ); + +} + +bool Board::takeBack() +{ + int f, dir, dir2; + int opponent = color; + Move& m = storedMove[storedLast]; + + CHECK( isConsistent() ); + + if (storedFirst == storedLast) return false; + + /* change actual color */ + color = (color == color1) ? color2:color1; + + if (m.isOutMove()) { + if (color == color1) + color2Count++; + else + color1Count++; + } + + f = m.field; + CHECK( field[f] == free ); + field[f] = color; + dir = direction[m.direction]; + + switch(m.type) { + case Move::out2: /* (. c c c o |) => (c c c o o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == color ); + CHECK( field[f + 4*dir] == opponent ); + CHECK( field[f + 5*dir] == out ); + field[f + 3*dir] = opponent; + break; + case Move::out1with3: /* (. c c c |) => (c c c o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == color ); + CHECK( field[f + 4*dir] == out ); + field[f + 3*dir] = opponent; + break; + case Move::move3: /* (. c c c) => (c c c .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == color ); + field[f + 3*dir] = free; + break; + case Move::out1with2: /* (. c c | ) => (c c o |) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == out ); + field[f + 2*dir] = opponent; + break; + case Move::move2: /* (. c c) => (c c .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + field[f + 2*dir] = free; + break; + case Move::push2: /* (. c c c o o) => (c c c o o .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == color ); + CHECK( field[f + 4*dir] == opponent ); + CHECK( field[f + 5*dir] == opponent ); + field[f + 3*dir] = opponent; + field[f + 5*dir] = free; + break; + case Move::left3: + dir2 = direction[m.direction-1]; + CHECK( field[f + dir] == free ); + CHECK( field[f + 2*dir] == free ); + CHECK( field[f + dir2] == color ); + CHECK( field[f + dir+dir2] == color ); + CHECK( field[f + 2*dir+dir2] == color ); + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + break; + case Move::right3: + dir2 = direction[m.direction+1]; + CHECK( field[f + dir] == free ); + CHECK( field[f + 2*dir] == free ); + CHECK( field[f + dir2] == color ); + CHECK( field[f + dir+dir2] == color ); + CHECK( field[f + 2*dir+dir2] == color ); + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + break; + case Move::push1with3: /* (. c c c o) => (c c c o .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == color ); + CHECK( field[f + 4*dir] == opponent ); + field[f + 3*dir] = opponent; + field[f + 4*dir] = free; + break; + case Move::push1with2: /* (. c c o) => (c c o .) */ + CHECK( field[f + dir] == color ); + CHECK( field[f + 2*dir] == color ); + CHECK( field[f + 3*dir] == opponent ); + field[f + 2*dir] = opponent; + field[f + 3*dir] = free; + break; + case Move::left2: + dir2 = direction[m.direction-1]; + CHECK( field[f + dir] == free ); + CHECK( field[f + dir2] == color ); + CHECK( field[f + dir+dir2] == color ); + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + break; + case Move::right2: + dir2 = direction[m.direction+1]; + CHECK( field[f + dir] == free ); + CHECK( field[f + dir2] == color ); + CHECK( field[f + dir+dir2] == color ); + field[f+dir2] = free; + field[f+=dir] = color; + field[f+dir2] = free; + break; + case Move::move1: /* (. c) => (c .) */ + CHECK( field[f + dir] == color ); + field[f + dir] = free; + break; + default: + break; + } + + if (--storedLast < 0) storedLast = MvsStored-1; + + CHECK( isConsistent() ); + + return true; +} + +int Board::movesStored() +{ + int c = storedLast - storedFirst; + if (c<0) c+= MvsStored; + return c; +} + + +/** countFrom + * + * Used for board evaluation to count allowed move types and + * connectiveness. VERY similar to move generation. + * + * Returns number of found moves + */ +void Board::countFrom(int startField, int color, + MoveTypeCounter& TCounter, + InARowCounter& CCounter) +{ + int d, dir, c, actField, c2; + bool left, right; + + /* 6 directions */ + for(d=1;d<7;d++) { + dir = direction[d]; + + /* 2nd field */ + c = field[actField = startField+dir]; + if (c == free) { + TCounter.incr( Move::move1 ); + continue; + } + + if (c != color) + continue; + + /* 2nd == color */ + + CCounter.incr( InARowCounter::inARow2 ); + + /* left side move 2 */ + left = (field[startField+direction[d-1]] == free); + if (left) { + left = (field[actField+direction[d-1]] == free); + if (left) + TCounter.incr( Move::left2 ); + } + + /* right side move 2 */ + right = (field[startField+direction[d+1]] == free); + if (right) { + right = (field[actField+direction[d+1]] == free); + if (right) + TCounter.incr( Move::right2 ); + } + + /* 3rd field */ + c = field[actField += dir]; + if (c == free) { + /* (c c .) */ + TCounter.incr( Move::move2 ); + continue; + } + else if (c == out) { + continue; + } + else if (c != color) { + + /* 4th field */ + c = field[actField += dir]; + if (c == free) { + /* (c c o .) */ + TCounter.incr( Move::push1with2 ); + } + else if (c == out) { + /* (c c o |) */ + TCounter.incr( Move::out1with2 ); + } + continue; + } + + /* 3nd == color */ + + CCounter.incr( InARowCounter::inARow3 ); + + /* left side move 3 */ + if (left) { + left = (field[actField+direction[d-1]] == free); + if (left) + TCounter.incr( Move::left3 ); + } + + /* right side move 3 */ + if (right) { + right = (field[actField+direction[d+1]] == free); + if (right) + TCounter.incr( Move::right3 ); + } + + /* 4th field */ + c = field[actField += dir]; + if (c == free) { + /* (c c c .) */ + TCounter.incr( Move::move3 ); + continue; + } + else if (c == out) { + continue; + } + else if (c != color) { + + /* 4nd == opponent */ + + /* 5. field */ + c2 = field[actField += dir]; + if (c2 == free) { + /* (c c c o .) */ + TCounter.incr( Move::push1with3 ); + continue; + } + else if (c2 == out) { + /* (c c c o |) */ + TCounter.incr( Move::out1with3 ); + continue; + } + if (c2 != c) + continue; + + /* 5nd == opponent */ + + /* 6. field */ + c2 = field[actField += dir]; + if (c2 == free) { + /* (c c c o o .) */ + TCounter.incr( Move::push2 ); + } + else if (c2 == out) { + /* (c c c o o |) */ + TCounter.incr( Move::out2 ); + } + + continue; + } + + /* 4nd == color */ + + CCounter.incr( InARowCounter::inARow4 ); + + /* 5th field */ + c = field[actField += dir]; + if (c != color) + continue; + + /* 4nd == color */ + + CCounter.incr( InARowCounter::inARow5 ); + } +} + +/** indent + * + * Internal: for debugging output only + */ +void indent(int d) +{ + char tmp[]=" "; + tmp[d*3] = 0; + printf("> %s",tmp); +} + + + +/** validState + * + * Check for a valid board position to play from: + * (1) Number of balls for each color has to be between 9 and 14 + * (2) There must be a move possible for actual color + */ +int Board::validState() +{ + MoveTypeCounter tc; + InARowCounter cc; + + int c1 = 0, c2 = 0; + int i,j, moveCount, res; + + for(i=0;i8 && c1<15 && c2>8 && c2<15 && moveCount>0 ) + res = valid; + else + res = invalid; + +#ifdef MYTRACE + if (spyLevel>2) { + indent(spyDepth); + printf("Valid: %s (Color1 %d, Color2 %d, moveCount of %d: %d)\n", + (res == empty) ? "empty" : (res==valid) ? "valid":"invalid", + c1,c2,color,moveCount); + } +#endif + + return res; +} + + + +/* Calculate a evaluation for actual position + * + * A higher value means a better position for opponent + * NB: This means a higher value for better position of + * 'color before last move' + */ +int Board::calcEvaluation() +{ + MoveTypeCounter tcColor, tcOpponent; + InARowCounter ccColor, ccOpponent; + + int f,i,j; + + /* different evaluation types */ + int fieldValueSum=0, stoneValueSum=0; + int moveValueSum=0, inARowValueSum=0; + int valueSum; + + /* First check simple winner condition */ + if (color1Count <9) + valueSum = (color==color1) ? 16000 : -16000; + else if (color2Count <9) + valueSum = (color==color2) ? 16000 : -16000; + else { + + /* Calculate fieldValueSum and count move types and connectivity */ + for(i=0;imoveValue(t) * + (tcOpponent.get(t) - tcColor.get(t)); + + for(int i=0;i < InARowCounter::inARowCount;i++) + inARowValueSum += _evalScheme->inARowValue(i) * + (ccOpponent.get(i) - ccColor.get(i)); + + if (color == color2) + stoneValueSum = _evalScheme->stoneValue(14 - color1Count) - + _evalScheme->stoneValue(14 - color2Count); + else + stoneValueSum = _evalScheme->stoneValue(14 - color2Count) - + _evalScheme->stoneValue(14 - color1Count); + + valueSum = fieldValueSum + moveValueSum + + inARowValueSum + stoneValueSum; + } + } + +#ifdef MYTRACE + if (spyLevel>2) { + indent(spyDepth); + printf("Eval %d (field %d, move %d, inARow %d, stone %d)\n", + valueSum, fieldValueSum, moveValueSum, + inARowValueSum, stoneValueSum ); + } +#endif + + return valueSum; +} + +bool Board::isConsistent() +{ + int c1 = 0, c2 = 0; + int i,j; + + for(i=0;i1) { + indent(depth); + printf("%s (%6d .. %6d) MaxType %s\n", depth, + (color==color1)?"O":"X", alpha,beta, + (depth < maxDepth-1) ? "Moving" : + (depth < maxDepth)? "Pushing" : "PushOUT" ); + } + */ +#endif + + /* check for a old best move in main combination */ + if (inPrincipalVariation) { + m = pv[depth]; + + if ((m.type != Move::none) && + (!list.isElement(m, 0, true))) + m.type = Move::none; + + if (m.type == Move::none) + inPrincipalVariation = false; + +#ifdef MYTRACE + else { + if (spyLevel>1) { + indent(spyDepth); + printf("Got from pv !\n" ); + } + } +#endif + } + + // first, play all moves with depth search + depthPhase = true; + + while (1) { + + // get next move + if (m.type == Move::none) { + if (depthPhase) + depthPhase = list.getNext(m, maxType); + if (!depthPhase) + if (!list.getNext(m, Move::none)) break; + } + // we could start with a non-depth move from principal variation + doDepthSearch = depthPhase && (m.type <= maxType); + +#ifdef MYTRACE + + if (m.isOutMove()) outCount++; + else if (m.isPushMove()) pushCount++; + else normalCount++; + + if (doDepthSearch) { + oldRatedPositions = ratedPositions; + oldWonPositions = wonPositions; + oldSearchCalled = searchCalled; + oldMoveCount = moveCount; + oldNormalCount = normalCount; + oldPushCount = pushCount; + oldOutCount = outCount; + oldCutoffCount = cutoffCount; + + if (spyLevel>1) { + indent(spyDepth); + printf("%s [%6d .. %6d] ", + (color==color1)?"O":"X", alpha,beta); + m.print(); + printf("\n"); + } + +#ifdef SPION + if (bUpdateSpy) emit update(depth, 0, m, false); +#endif + } +#endif + + playMove(m); + if (!isValid()) { + /* Possibility (1) to win: Ball Count <9 */ + value = 14999-depth; + // value = ((depth < maxDepth) ? 15999:14999) - depth; +#ifdef MYTRACE + wonPositions++; +#endif + } + else { + + if (doDepthSearch) { + /* opponent searches for his maximum; but we want the + * minimum: so change sign (for alpha/beta window too!) + */ + value = - search(depth+1,-beta,-alpha); + } + else { + ratedPositions++; + + value = calcEvaluation(); + } + } + takeBack(); + + /* For GUI response */ + if (doDepthSearch && (maxDepth - depth >2)) + emit searchBreak(); + +#ifdef MYTRACE + + if (doDepthSearch) { + spyDepth = depth; + + if (spyLevel>1) { + + indent(spyDepth); + if (oldSearchCalled < searchCalled) { + printf(" %d Calls", searchCalled-oldSearchCalled); + if (cutoffCount>oldCutoffCount) + printf(" (%d Cutoffs)", cutoffCount-oldCutoffCount); + printf(", GenMoves %d (%d/%d/%d played)", + moveCount - oldMoveCount, + normalCount - oldNormalCount, + pushCount-oldPushCount, + outCount-oldOutCount); + printf(", Rate# %d", + ratedPositions+wonPositions + - oldRatedPositions - oldWonPositions); + if (wonPositions > oldWonPositions) + printf(" (%d Won)", wonPositions- oldWonPositions); + printf("\n"); + indent(spyDepth); + } + + printf(" => Rated %d%s\n", + value, + (value>14900) ? ", WON !": + (value>=beta) ? ", CUTOFF !": + (value>actValue) ? ", Best !": ""); + } + } + else { + if (spyLevel>2) { + indent(spyDepth); + printf("%s (%6d .. %6d) %-25s => Rating %6d%s\n", + (color==color1)?"O":"X", alpha,beta, + m.name().latin1(), + value, + (value>14900) ? ", WON !": + (value>=beta) ? ", CUTOFF !": + (value>actValue) ? ", Best !": ""); + } + } + + if (value>=beta) cutoffCount++; +#endif + +#ifdef SPION + if (bUpdateSpy) { + if (value > actValue) + emit updateBest(depth, value, m, value >= beta); + emit update(depth, value, m, true); + } +#endif + if (value > actValue) { + actValue = value; + pv.update(depth, m); + + // Only update best move if not stopping search + if (!breakOut && (depth == 0)) { + _bestMove = m; + + if (bUpdateSpy) { + emit updateBestMove(m, actValue); +#ifdef MYTRACE + if (spyLevel>0) { + int i; + printf("> New pv (Rating %d):", actValue); + for(i=0;i<=maxDepth;i++) { + printf("\n> D %d: %s", + i, pv[i].name().latin1() ); + } + printf("\n>\n"); + } +#endif + } + } + + if (actValue>14900 || actValue >= beta) + return actValue; + + /* maximize alpha */ + if (actValue > alpha) alpha = actValue; + } + + if (breakOut) depthPhase=false; + m.type = Move::none; + } + + return actValue; +} + + +Move& Board::bestMove() +{ + int alpha=-15000,beta=15000; + int nalpha,nbeta, actValue; + + if (!_evalScheme) { + // Use default values if not set + setEvalScheme(); + } + + pv.clear(realMaxDepth); + _bestMove.type = Move::none; + + maxDepth=1; + show = false; + breakOut = false; + spyDepth = 0; + + if (spyLevel>0) + printf("\n> New Search\n>\n"); + + /* iterative deepening loop */ + do { + if (spyLevel>0) + printf("> MaxDepth: %d\n>\n", maxDepth); + + /* searches on same level with different alpha/beta windows */ + while(1) { + if (spyLevel>0) + printf("> AB-Window: (%d ... %d)\n>\n", alpha, beta); + + nalpha=alpha, nbeta=beta; + inPrincipalVariation = (pv[0].type != Move::none); + + /* Statistics */ + searchCalled = 0; + moveCount = 0; + ratedPositions = 0; + wonPositions = 0; + normalCount = 0; + pushCount = 0; + outCount = 0; + cutoffCount = 0; + + actValue = search(0,alpha,beta); + + if (spyLevel>0) + { + int i; + if (spyLevel>1) + printf(">\n"); + printf("> Got PV with Rating %d:",actValue); + for(i=0;i<=maxDepth;i++) { + printf("\n> D %d: ", i); + pv[i].print(); + } + printf("\n>\n"); + + printf("> Search called : %6d / %d Cutoffs\n", + searchCalled, cutoffCount); + printf("> Moves generated : %6d / %d Played\n", + moveCount, normalCount+pushCount+outCount); + printf("> Nrml/Push/Out : %6d / %d / %d\n", + normalCount,pushCount,outCount); + printf("> Positions rated : %6d / %d Won\n>\n", + ratedPositions+wonPositions, wonPositions); + + } + + if (actValue > 14900 || actValue < -14900) + breakOut=true; + + /* Don't break out if we haven't found a move */ + if (_bestMove.type == Move::none) + breakOut=false; + + if (breakOut) break; + + // widen alpha-beta window if needed + if (actValue <= nalpha) { + alpha = -15000; + if (beta<15000) beta=actValue+1; + continue; + } + if (actValue >= nbeta) { + if (alpha > -15000) alpha = actValue-1; + beta=15000; + continue; + } + break; + } + + /* Window in both directions cause of deepening */ + alpha=actValue-200, beta=actValue+200; + + if (breakOut) break; + + maxDepth++; + } + while(maxDepth <= realMaxDepth); + + /* If Spy is On, we want replayable search: don't change rating! */ + if (spyLevel==0) + changeEvaluation(); + else { + printf(">>> Got Move : "); + pv[0].print(); + printf("\n\n"); + } + + spyDepth = 0; + + return _bestMove; +} + +Move Board::randomMove() +{ + Move m; + MoveList list; + + generateMoves(list); + int l = list.getLength(); + + int j = random.getLong(l) +1; + + while(j != 0) { + list.getNext(m, Move::none); + j--; + } + + return m; +} + + +void Board::print(int ) +{ + int row,i; + char spaces[]=" "; + const char *z[]={". ","O ","X ", "o ", "x "}; + + printf("\n -----------\n"); + for(row=0;row<4;row++) { + printf("%s/ ",spaces+row); + for(i=0;i<5+row;i++) printf("%s",z[field[row*11+12+i]]); + printf("\\\n"); + } + printf(" | "); + for(i=0;i<9;i++) printf("%s",z[field[56+i]]); + printf("|\n"); + for(row=0;row<4;row++) { + printf("%s\\ ",spaces+3-row); + for(i=0;i<8-row;i++) printf("%s",z[field[68+row*12+i]]); + printf("/\n"); + } + printf(" ----------- O: %d X: %d\n", + color1Count, color2Count); +} + +QString Board::getASCIIState(int moveNo) +{ + QString state, tmp; + + int row,i; + char spaces[]=" "; + const char *z[]={". ","O ","X ", "o ", "x "}; + + state += tmp.sprintf("\n #%-3d ----------- O: %d X: %d\n", + moveNo, color1Count, color2Count); + for(row=0;row<4;row++) { + state += tmp.sprintf("%s/ ",spaces+row); + for(i=0;i<5+row;i++) + state += tmp.sprintf("%s",z[field[row*11+12+i]]); + state += "\\\n"; + } + state += " | "; + for(i=0;i<9;i++) + state += tmp.sprintf("%s",z[field[56+i]]); + state += "|\n"; + for(row=0;row<4;row++) { + state += tmp.sprintf("%s\\ ",spaces+3-row); + for(i=0;i<8-row;i++) + state += tmp.sprintf("%s",z[field[68+row*12+i]]); + state += "/\n"; + } + state += " -----------\n\n"; + + return state; +} + +int Board::setASCIIState(const QString& state) +{ + int moveNo=-1, index; + int len = state.length(); + int color1Count = 0; + int color2Count = 0; + + /* get moveNo if supplied */ + if ((index = state.find("#"))>=0) + moveNo = state.mid(index+1,3).toInt(); + + int f=12, row=0, rowEnd = 17; + char c = ' '; + + index=state.find("/"); + + while(index>=0) { + + while(++index= len) index=-1; + continue; + } + + if (f == rowEnd) { + row++; + if (row <4) { + index = state.find("/",index); + f = 12 + row*11; + rowEnd = row*12+17; + } + else if (row==4) { + index = state.find("|",index); + f = 56; + rowEnd = 65; + } + else if (row <9) { + index = state.find("\\",index); + f = 8 + row*12; + rowEnd = 21 + row*11; + } + else + break; + // printf("Row %d: %d - %d, Idx %d\n", row, f, rowEnd, index); + } + } + return moveNo; +} + + +QString Board::getState(int moveNo) +{ + QString state; + QString entry, tmp; + int i; + + /* Color + Counts */ + state += (char) ('A' + moveNo /25 ); + state += (char) ('A' + moveNo %25 ); + state += (char) ('A' + color1Count); + state += (char) ('A' + color2Count); + state += (char) ('A' + 4*color + field[order[0]]); + + /* Board (field values can be 0-3; 2 fields coded in one char */ + for(i=1;i<61;i+=2) + state+= (char) ('A' + 4*field[order[i]] + field[order[i+1]] ); + + /* -> 35 chars */ + return state; +} + +int Board::setState(QString& _state) +{ + int moveNo; + const char *state = _state.ascii(); + + if (_state.length() != 35) return 0; + + moveNo = 25*(state[0] - 'A') + (state[1] - 'A'); + color1Count = state[2] - 'A'; + color2Count = state[3] - 'A'; + color = (state[4] - 'A') / 4; + field[order[0]] = (state[4] - 'A') %4; + + int i = 1; + for(int j = 5; j<35; j++) { + int w = state[j] - 'A'; + field[order[i++]] = w/4; + field[order[i++]] = w % 4; + } + return moveNo; +} + +void Board::setSpyLevel(int level) +{ + spyLevel = level; +} +#include "Board.moc" diff --git a/kenolaba/Board.h b/kenolaba/Board.h new file mode 100644 index 00000000..61871d1f --- /dev/null +++ b/kenolaba/Board.h @@ -0,0 +1,198 @@ +/* Class Board - represents a game state + * + * Josef Weidendorfer, 28.8.97 +*/ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include +#include +#include "Move.h" + +class KConfig; +class EvalScheme; + +/* Class for best moves so far */ +class PrincipalVariation +{ +public: + PrincipalVariation() + { clear(1); } + + enum { maxDepth = 10 }; + + bool hasMove(int d) + { return (d>actMaxDepth) ? + false : (move[0][d].type != Move::none); } + + Move& operator[](int i) + { return (i<0 || i>=maxDepth) ? move[0][0] : move[0][i]; } + + void update(int d, Move& m); + void clear(int d); + void setMaxDepth(int d) + { actMaxDepth = (d>maxDepth) ? maxDepth-1 : d; } + +private: + Move move[maxDepth][maxDepth]; + int actMaxDepth; + +}; + + +class Board : public QObject +{ + Q_OBJECT + + public: + Board(); + ~Board() {} + + /* different states of one field */ + enum { + out = 10, free = 0, + color1, color2, color1bright, color2bright + }; + enum { AllFields = 121, /* visible + ring of unvisible around */ + RealFields = 61, /* number of visible fields */ + MvsStored = 100 }; + + int debug; + + /* fill Board with defined values */ + void begin(int startColor); /* start of a game */ + void clear(); /* empty board */ + + /* fields can't be changed ! */ + int operator[](int no) const; + + int actColor() const + { return color; } + + /* Generate list of allowed moves for player with + * Returns a calculated value for actual position */ + void generateMoves(MoveList& list); + + /* Functions handling moves + * played moves can be taken back ( moves are remembered) */ + void playMove(const Move& m); + bool takeBack(); /* if not remembered, do nothing */ + int movesStored(); /* return how many moves are remembered */ + + Move& lastMove() + { return storedMove[storedLast]; } + + void showHist(); + + /* Evaluation Scheme to use */ + void setEvalScheme( EvalScheme* scheme = 0); + EvalScheme* evalScheme() { return _evalScheme; } + + /* Calculate a value for actual position + * (greater if better for color1) */ + int calcEvaluation(); + + /* Evalution is based on values which can be changed + * a little (so computer's moves aren't always the same) */ + void changeEvaluation(); + + void setActColor(int c) { color=c; } + void setColor1Count(int c) { color1Count = c; } + void setColor2Count(int c) { color2Count = c; } + void setField(int i, int v) { field[i] = v; } + + void setSpyLevel(int); + + int getColor1Count() { return color1Count; } + int getColor2Count() { return color2Count; } + + enum { empty=0, valid, invalid }; + int validState(); + bool isValid() { return (color1Count>8 && color2Count>8); } + + /* Check that color1Count & color2Count is consisten with board */ + bool isConsistent(); + + /* Searching best move: alpha/beta search */ + void setDepth(int d) + { realMaxDepth = d+1; } + Move& bestMove(); + + /* next move in main combination */ + Move& nextMove() { return pv[1]; } + + Move randomMove(); + void stopSearch() { breakOut = true; } + + /* Compressed ASCII representation */ + QString getState(int); + int setState(QString&); + + /* Readable ASCII representation */ + QString getASCIIState(int); + int setASCIIState(const QString&); + + void updateSpy(bool b) { bUpdateSpy = b; } + + /* simple terminal view of position */ + void print(int); + + static int fieldDiffOfDir(int d) { return direction[d]; } + + signals: + void searchBreak(); + void updateBestMove(Move&,int); + + void update(int,int,Move&,bool); + void updateBest(int,int,Move&,bool); + + private: + void setFieldValues(); + + /* helper function for generateMoves */ + void generateFieldMoves(int, MoveList&); + /* helper function for calcValue */ + void countFrom(int,int, MoveTypeCounter&, InARowCounter&); + /* helper functions for bestMove (recursive search!) */ + int search(int, int, int); + int search2(int, int, int); + + KRandomSequence random; /* random generator */ + + int field[AllFields]; /* actual board */ + int color1Count, color2Count; + int color; /* actual color */ + Move storedMove[MvsStored]; /* stored moves */ + int storedFirst, storedLast; /* stored in ring puffer manner */ + + /* for search */ + PrincipalVariation pv; + Move _bestMove; + bool breakOut, inPrincipalVariation, show, bUpdateSpy; + int maxDepth, realMaxDepth; + + int spyLevel, spyDepth; + EvalScheme* _evalScheme; + + /* ratings; semi constant - are rotated by changeRating() */ + static int fieldValue[RealFields]; + + /* constant arrays */ + static int startBoard[AllFields]; + static int order[RealFields]; + static int direction[8]; + + // static int stoneValue[6]; + // static int moveValue[Move::typeCount]; + // static int connectValue[ConnectCounter::connectCount]; + // static int ringValue[5], ringDiff[5]; +}; + + +inline int Board::operator[](int no) const +{ + return (no<12 || no>120) ? out : field[no]; +} + +#endif diff --git a/kenolaba/BoardWidget.cpp b/kenolaba/BoardWidget.cpp new file mode 100644 index 00000000..9d420cc3 --- /dev/null +++ b/kenolaba/BoardWidget.cpp @@ -0,0 +1,1027 @@ +/* Implementation of class BoardWidget + * + * This class handles rendering of a Board to a KDE/QT widget, + * shows moves (with a timer) and manages input of moves + * + * Josef Weidendorfer, 9/97 + */ + +#include +#include +#include + +#include +#include + +#ifdef HAVE_KIR +#include +#endif + +#include "Board.h" +#include "BoardWidget.h" + +/* Cursors */ +#include "bitmaps/Arrow1" +#include "bitmaps/Arrow1Mask" +#include "bitmaps/Arrow2" +#include "bitmaps/Arrow2Mask" +#include "bitmaps/Arrow3" +#include "bitmaps/Arrow3Mask" +#include "bitmaps/Arrow4" +#include "bitmaps/Arrow4Mask" +#include "bitmaps/Arrow5" +#include "bitmaps/Arrow5Mask" +#include "bitmaps/Arrow6" +#include "bitmaps/Arrow6Mask" + +BoardWidget::BoardWidget(Board& b, QWidget *parent, const char *name) + : BallWidget(10,9,parent, name), board(b) +{ + pList =0; + gettingMove = false; + editMode = false; + renderMode = false; + +#ifdef HAVE_KIR + m_backRenderer = KIRManager::attach( this, "Background" ); + connect( m_backRenderer, SIGNAL(rendered()), + this, SLOT(drawBoard()) ); +#endif + + /* setup cursors */ + +#define createCursor(bitmap,name) \ + static QBitmap bitmap(bitmap##_width, bitmap##_height, \ + (unsigned char *) bitmap##_bits, TRUE); \ + static QBitmap bitmap##Mask(bitmap##Mask_width, bitmap##Mask_height, \ + (unsigned char *) bitmap##Mask_bits, TRUE); \ + name = new QCursor(bitmap, bitmap##Mask, bitmap##_x_hot, bitmap##_y_hot); + + createCursor(Arrow1, arrow[1]); + createCursor(Arrow2, arrow[2]); + createCursor(Arrow3, arrow[3]); + createCursor(Arrow4, arrow[4]); + createCursor(Arrow5, arrow[5]); + createCursor(Arrow6, arrow[6]); + + setCursor(crossCursor); + + // boardColor = new QColor("lightblue"); + boardColor = new QColor(backgroundColor()); + redColor = new QColor("red2"); + yellowColor = new QColor("yellow2"); + redHColor = new QColor("orange"); + yellowHColor = new QColor("green"); + + initBalls(); + + updatePosition(); +} + +BoardWidget::~BoardWidget() +{ + for(int i=1; i<7; i++) + if (arrow[i] != 0) + delete arrow[i]; + +#ifdef HAVE_KIR + if (m_backRenderer != 0) + delete m_backRenderer; +#endif + delete boardColor; + delete redColor; + delete yellowColor; + delete redHColor; + delete yellowHColor; + +} + +void BoardWidget::configure() +{ +#ifdef HAVE_KIR + if (m_backRenderer != 0) { + m_backRenderer->setup(); + m_backRenderer->manager()->saveModules(); + } +#endif +} + + +void BoardWidget::createPos(int pos, int i, int j, Ball* b) +{ + int x=(465*(2*(i)-(j))/9); + int y=(500*19*(j)/100); + createBallPosition(pos, x,y, b); +} + +void BoardWidget::initBalls() +{ + n2 = new Ball( *yellowColor ); + h2 = new Ball( *yellowHColor ); + d2 = new Ball( *yellowHColor, 3.14/2 ); + + n1 = new Ball( *redColor ); + h1 = new Ball( *redHColor ); + d1 = new Ball( *redHColor, 3.14/2 ); + + // e = new Ball( white,0,0 ); + // e->setSpecials(.6,.85,.75); + + createBlending(1,10,h1,n1); + createBlending(2,10,h1,d1); + createBlending(3,10,h2,n2); + createBlending(4,10,h2,d2); + + int i,j,pos; + for(j=-4;j<5;j++) + for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { + pos=60+j*11+i; + createPos(pos, i,j, 0); + } + + pos = 0; + /* the outer marks of color1 */ + for(i=0;i<3;i++) createPos(pos++, -6, i-4, 0 ); + for(i=0;i<3;i++) createPos(pos++, 2+i, i-4, 0 ); + + /* the outer marks of color2 */ + for(i=0;i<3;i++) createPos(pos++, 6, 4-i, 0 ); + for(i=0;i<3;i++) createPos(pos++, -2-i, 4-i, 0 ); +} + +void BoardWidget::resizeEvent(QResizeEvent *e) +{ + drawBoard(); + BallWidget::resizeEvent(e); +} + +void BoardWidget::moveEvent(QMoveEvent*) +{ + drawBoard(); +} + +void BoardWidget::paintEvent(QPaintEvent *) +{ + if (renderMode) { + pm = boardPM; + BallWidget::paint(&pm); + } + else + draw(); + bitBlt(this, 0, 0, &pm); +} + + +void drawShadedHexagon(QPainter *p, int x, int y, int r, int lineWidth, + const QColorGroup& g, bool sunken) +{ + int dx=r/2, dy=(r*87)/100; + int y1=y-dy, y2=y+dy; + int i; + + QPen oldPen = p->pen(); + + p->setPen(sunken ? g.midlight() : g.dark()); + + for(i=0; idrawLine( x-i+dx, y-dy, x+2*dx-i, y); + p->drawLine( x+2*dx-i, y, x-i+dx, y+dy); + p->drawLine( x-i+dx, y1+i, x+i-dx, y1+i); + } + + p->setPen(sunken ? g.dark() : g.midlight()); + + for(i=0; idrawLine( x+i-dx, y-dy, x+i-2*dx, y); + p->drawLine( x+i-2*dx, y, x+i-dx, y+dy); + p->drawLine( x-i+dx, y2-i, x+i-dx, y2-i); + } + + p->setPen(oldPen); +} + + +void drawColor(QPainter *p, int x, int y, int r, QColor* c) +{ + QColor w("white"); + QPalette pal(*c); + + QPen oldPen = p->pen(); + QBrush oldBrush = p->brush(); + + p->setBrush(pal.active().dark()); + p->setPen(pal.active().dark()); + p->drawEllipse( x-r - 10,y-r +5, 2*r,2*r); + + p->setBrush(pal.active().mid()); + p->setPen(pal.active().mid()); + p->drawEllipse( x-r,y-r, 2*r,2*r); + + p->setBrush(pal.active().light()); + p->setPen(pal.active().light()); + p->drawEllipse( x-r/3, y-r/3, 4*r/3,4*r/3); + + p->setBrush(w); + p->setPen(w); + p->drawEllipse( x+r/3, y+r/3, r/3,r/3); + + p->setPen(oldPen); + p->setBrush(oldBrush); +} + + +void BoardWidget::drawBoard() +{ + boardPM.resize(width(), height()); + boardPM.fill(this, 0,0); + +#ifndef HAVE_KIR + QColorGroup g = QPalette( *boardColor ).active(); + QColorGroup g2 = QWidget::colorGroup(); + + int boardSize = width() *10/12; + if (boardSize > height()) boardSize = height(); + + QPainter p; + p.begin(&boardPM); + p.setBrush(g2.brush(QColorGroup::Mid)); + + QWMatrix m; + QPoint cp = rect().center(); + m.translate(cp.x(), cp.y()); + m.scale(boardSize/1100.0, boardSize/1000.0); + + m.rotate(0); + + p.setWorldMatrix(m); + + /* draw field */ + + int i,j; + + QPointArray a; + int dx=520 /2, dy=(520 *87)/100; + a.setPoints(6, -dx,-dy, dx,-dy, 2*dx,0, dx,dy, -dx,dy, -2*dx,0 ); + p.drawPolygon(a); + + drawShadedHexagon(&p, 0,0, 505, 1, g, false); + drawShadedHexagon(&p, 0,0, 512, 3, g, true); + drawShadedHexagon(&p, 0,0, 525, 5, g2, true); + +#define xpos(i,j) (495*(2*(i)-(j))/9) +#define ypos(j) (500*19*(j)/100) + + for(j=-4;j<5;j++) + for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { + int x=xpos(i,j); + int y=ypos(j); + + drawShadedHexagon(&p, x,y, 50, 2, g, true); + drawShadedHexagon(&p, x,y, 30, 1, g, false); + } + p.end(); +#endif + draw(); +} + +void BoardWidget::renderBalls(bool r) +{ + renderMode=r; + draw(); +} + +void BoardWidget::updateBalls() +{ + int i,j; + + for(j=-4;j<5;j++) + for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { + int pos = 60+j*11+i; + int w=field[60+j*11+i]; + + if (w==Board::color1) { + if (positions[pos]->def != n1) { + positions[pos]->def= n1; + startAnimation(pos,1, ANIMATION_FORWARD); + } + else { + stopAnimation(pos); + } + } + else if (w==Board::color1bright) + startAnimation(pos,2,ANIMATION_LOOP); + else if (w==Board::color2) { + if (positions[pos]->def != n2) { + positions[pos]->def= n2; + startAnimation(pos,3,ANIMATION_FORWARD); + } + else { + stopAnimation(pos); + } + } + else if (w==Board::color2bright) + startAnimation(pos,4,ANIMATION_LOOP); + else if (w==Board::free) { + positions[pos]->def= 0; + positions[pos]->actAnimation = 0; + // stopAnimation(pos); + } + } + + for(i=0;i<6;i++) + positions[i]->def= ((14-color1Count)>i && color1Count>0) ? n1:0; + + for(i=6;i<12;i++) + positions[i]->def= ((14-color2Count)>i-6 && color2Count>0) ? n2:0; + +} + +void BoardWidget::draw() +{ + if (boardPM.isNull()) + return; + + pm = boardPM; + + if (renderMode) { + updateBalls(); + repaint(false); + return; + } + + int boardSize = width() *10/12; + if (boardSize > height()) boardSize = height(); + + QPainter p; + p.begin(&pm); + p.setBrush(foregroundColor()); + + QWMatrix m; + QPoint cp = rect().center(); + m.translate(cp.x(), cp.y()); + m.scale(boardSize/1100.0, boardSize/1000.0); + + m.rotate(0); + + p.setWorldMatrix(m); + + /* draw fields */ + + int i,j; + + for(j=-4;j<5;j++) + for(i= ((j>0)?j-4:-4) ; i< ((j<0)?5+j:5) ;i++) { + int x=xpos(i,j); + int y=ypos(j); + int w=field[60+j*11+i]; + + if (w==Board::color1) + drawColor(&p, x,y, 35, redColor ); + else if (w==Board::color1bright) + drawColor(&p, x,y, 35, redHColor ); + else if (w==Board::color2) + drawColor(&p, x,y, 35, yellowColor ); + else if (w==Board::color2bright) + drawColor(&p, x,y, 35, yellowHColor ); + } + + if (color1Count >0) { + /* the outer marks of color1 */ + if (color1Count <12) { + for(i=11; i>8 && i>color1Count ;i--) + drawColor(&p, xpos(12-i,7-i)+55, ypos(7-i), 35, redColor ); + } + for(i=14; i>11 && i>color1Count ;i--) + drawColor(&p, xpos(-6,10-i)+55, ypos(10-i), 35, redColor ); + + /* the outer marks of color2 */ + if (color2Count <12) { + for(i=11; i>8 && i>color2Count ;i--) + drawColor(&p, xpos(i-12,i-7)-55, ypos(i-7), 35, yellowColor); + } + for(i=14; i>11 && i>color2Count ;i--) + drawColor(&p, xpos(6,i-10)-55, ypos(i-10), 35, yellowColor); + } + p.end(); + bitBlt(this, 0, 0, &pm); +} + +/** updatePosition + * + * Update my position with that of the member. + * If is true, draw widget + */ +void BoardWidget::updatePosition(bool updateGUI) +{ + for(int i=0; i2) ? Board::color1bright:Board::free; + opponentNew = (step<2) ? Board::color2 : Board::color2bright; + } + else { + colorNew = (step<2) ? Board::color2 : + (step>2) ? Board::color2bright:Board::free; + opponentNew = (step<2) ? Board::color1 : Board::color1bright; + } + + afterMove = (step == 1) || (step == 4); + + f = m.field; + dir = Board::fieldDiffOfDir(m.direction); + + /* first field */ + field[f] = afterMove ? Board::free : colorNew; + + switch(m.type) { + case Move::out2: /* (c c c o o |) */ + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + field[f + 3*dir] = afterMove ? colorNew : opponentNew; + field[f + 4*dir] = opponentNew; + break; + case Move::out1with3: /* (c c c o |) */ + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + field[f + 3*dir] = afterMove ? colorNew : opponentNew; + break; + case Move::move3: /* (c c c .) */ + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + field[f + 3*dir] = afterMove ? colorNew : Board::free; + break; + case Move::out1with2: /* (c c o |) */ + field[f + dir] = colorNew; + field[f + 2*dir] = afterMove ? colorNew : opponentNew; + break; + case Move::move2: /* (c c .) */ + field[f + dir] = colorNew; + field[f + 2*dir] = afterMove ? colorNew : Board::free; + break; + case Move::push2: /* (c c c o o .) */ + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + field[f + 3*dir] = afterMove ? colorNew : opponentNew; + field[f + 4*dir] = opponentNew; + field[f + 5*dir] = afterMove ? opponentNew : Board::free; + break; + case Move::left3: + dir2 = Board::fieldDiffOfDir(m.direction-1); + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + break; + case Move::right3: + dir2 = Board::fieldDiffOfDir(m.direction+1); + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + break; + case Move::push1with3: /* (c c c o .) => (. c c c o) */ + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + field[f + 3*dir] = afterMove ? colorNew : opponentNew; + field[f + 4*dir] = afterMove ? opponentNew : Board::free; + break; + case Move::push1with2: /* (c c o .) => (. c c o) */ + field[f + dir] = colorNew; + field[f + 2*dir] = afterMove ? colorNew : opponentNew; + field[f + 3*dir] = afterMove ? opponentNew : Board::free; + break; + case Move::left2: + dir2 = Board::fieldDiffOfDir(m.direction-1); + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + break; + case Move::right2: + dir2 = Board::fieldDiffOfDir(m.direction+1); + field[f+dir2] = afterMove ? colorNew : Board::free; + field[f+=dir] = afterMove ? Board::free : colorNew; + field[f+dir2] = afterMove ? colorNew : Board::free; + break; + case Move::move1: /* (c .) => (. c) */ + field[f + dir] = afterMove ? colorNew : Board::free; + break; + default: + break; + } + + if (updateGUI) + draw(); +} + +void BoardWidget::showStart(const Move& m, int step, bool updateGUI) +{ + int f, dir; + int colorNew; + + if (boardOK) { + /* board ok means: board has the normal state before move */ + if (step == 0) + return; /* nothing to be done */ + } + boardOK = (step == 0) ? true:false; + + if (color == Board::color1) + colorNew = (step==0) ? Board::color1 : Board::color1bright; + else + colorNew = (step==0) ? Board::color2 : Board::color2bright; + + f = m.field; + + /* first field */ + field[f] = colorNew; + + switch(m.type) { + case Move::left3: + case Move::right3: + dir = Board::fieldDiffOfDir(m.direction); + field[f + dir] = colorNew; + field[f + 2*dir] = colorNew; + break; + case Move::left2: + case Move::right2: + dir = Board::fieldDiffOfDir(m.direction); + field[f + dir] = colorNew; + default: + break; + } + + if (updateGUI) + draw(); +} + + +void BoardWidget::choseMove(MoveList *pl) +{ + if (!gettingMove && pl != 0) { + pList = pl; + gettingMove = true; + mbDown = false; + actValue = - board.calcEvaluation(); + kdDebug(12011) << "Chose Move..." << endl; + } +} + + +/* returns position of point (xx,yy) + */ +int BoardWidget::positionOf(int xx, int yy) +{ + int boardSize = QMIN( width()*10/12, height() ); + int x = (1000 * (xx- (width()-boardSize)/2)) / boardSize; + int y = (1000 * (yy- (height()-boardSize)/2)) / boardSize; + + /* + kdDebug(12011) << "(" << xx << "," << yy << ") -> (" + << x << "," << y << ")" << endl; + */ + + y = (y-2)/47; + if (y < 2 || y > 18) return 0; + x= ((x+25)/25+ (y-10) )/2; + if (y < 10 && ((x < 2) || (x > 8+y) )) return 0; + if (y >= 10 && ((x < y-8) || (x > 18) )) return 0; + + return 22*y + x; +} + + +bool isBetweenFields(int pos) +{ + bool res = ( ((pos%2) == 1) || ( ((pos/22)%2) == 1) ); + // kdDebug(12011) << "Pos " << pos << " is between fields: " << res << endl; + return res; +} + +int fieldOf(int pos) +{ + int f = 11*(pos/44) + (pos%22)/2; + // kdDebug(12011) << "Field1 of pos " << pos << " is " << f << endl; + return f; +} + +int field2Of(int pos) +{ + int y = pos/22, x = pos%22; + int f2 = 0, f1 = 11*(y/2) + (x/2); + + if ( (y%2) == 0) { + /* exact on row */ + if ( (x%2) != 0) { + /* horizontial between fields */ + f2 = f1+1; + } + } + else { + /* vertical between fields */ + f2 = f1 + ( ((x%2)==0) ? 11:12 ); + } + + // kdDebug(12011) << "Field2 of pos " << pos << " is " << f2 << endl; + return f2; +} + + +/* get direction depending on difference of positions */ +int directionOfPosDiff(int d) +{ + if (d>0) { + return ((d<21) ? Move::Right : + ((d%22) == 0) ? Move::LeftDown : + ((d%23) == 0) ? Move::RightDown : 0); + } + else if (d<0) { + return ((d>-21) ? Move::Left : + ((d%23) == 0) ? Move::LeftUp : + ((d%22) == 0) ? Move::RightUp : 0); + } + return 0; +} + +int directionOfFieldDiff(int d) +{ + if (d>0) { + return ((d<10) ? Move::Right : + ((d%11) == 0) ? Move::LeftDown : + ((d%12) == 0) ? Move::RightDown : 0); + } + else if (d<0) { + return ((d>-10) ? Move::Left : + ((d%12) == 0) ? Move::LeftUp : + ((d%11) == 0) ? Move::RightUp : 0); + } + return 0; +} + +/* Check if is a valid start position for a allowed move + * If yes, set + * , and + */ +bool BoardWidget::isValidStart(int pos, bool midPressed) +{ + bool res = false; + int f1 = fieldOf(pos); + + startField = f1; + + if (isBetweenFields(pos)) { + int f2 = field2Of(pos); + + actMove = Move(f1, directionOfFieldDiff( f2-f1 ), Move::none); + res = pList->isElement(actMove, MoveList::start2); + if (!res) { + startField = f2; + actMove = Move(f2, directionOfFieldDiff( f1-f2 ), Move::none); + res = pList->isElement(actMove, MoveList::start2); + } + startType = MoveList::start2; + return res; + } + + if (midPressed) { + startType = MoveList::start3; + + /* Check all 6 directions */ + for(int dir=1;dir<7;dir++) { + actMove = Move(f1 - Board::fieldDiffOfDir(dir), dir, Move::none ); + if (pList->isElement(actMove, startType)) + return true; + } + /* if we don't find a side move3 fall trough to normal moves... */ + } + + startType = MoveList::start1; + actMove = Move(f1, 0, Move::none); + res = pList->isElement(actMove, startType); + + return res; +} + + +/* Check if is a valid end position for a move + * regarding + * If yes, set + */ +bool BoardWidget::isValidEnd(int pos) +{ + int dir = directionOfPosDiff(pos - startPos); + Move m; + + if (dir == 0) return false; + + switch(startType) { + case MoveList::start1: + m = Move(startField, dir, Move::none); + if (!pList->isElement(m, startType)) + return false; + break; + + case MoveList::start2: + { + int f1 = fieldOf(startPos); + int f2 = field2Of(startPos); + int dir2 = directionOfFieldDiff( f2-f1 ); + int dir3 = directionOfFieldDiff( f1-f2 ); + + switch((dir2-dir+6)%6) { + case 1: + m = Move(f1, dir2, Move::left2); + break; + case 2: + m = Move(f2, dir3, Move::right2); + break; + case 4: + m = Move(f2, dir3, Move::left2); + break; + case 5: + m = Move(f1, dir2, Move::right2); + break; + default: + return false; + } + if (!pList->isElement(m, startType)) + return false; + + break; + } + case MoveList::start3: + { + int rightDir = (dir%6)+1; + m = Move( startField - Board::fieldDiffOfDir(rightDir), rightDir, Move::left3 ); + if (!pList->isElement(m, startType)) { + int leftDir = ((dir-2)%6)+1; + m = Move( startField - Board::fieldDiffOfDir(leftDir), leftDir, Move::right3 ); + if (!pList->isElement(m, startType)) + return false; + } + } + break; + } + + actMove = m; + shownDirection = dir; + return true; +} + + + +void BoardWidget::mousePressEvent( QMouseEvent* pEvent ) +{ + int pos = positionOf( pEvent->x(), pEvent->y() ); + int f = fieldOf(pos); + + if (pEvent->button() == RightButton) { + emit rightButtonPressed(f, pEvent->globalPos()); + return; + } + + if (!gettingMove && !editMode) { + return; + } + mbDown = true; + + + if (editMode) { + editColor = (pEvent->button() == MidButton) ? + Board::color2 : Board::color1; + int newColor = (pEvent->button() == MidButton) ? + Board::color2bright : Board::color1bright; + + if (field[f] == Board::free) { + field[f] = newColor; + } + else if (field[f] == Board::color1) { + if (editColor == Board::color1) { + editColor = Board::free; + newColor = Board::color1bright; + } + field[f] = newColor; + } + else if (field[f] == Board::color2) { + if (editColor == Board::color2) { + editColor = Board::free; + newColor = Board::color2bright; + } + field[f] = newColor; + } + else { + editColor = Board::out; + } + + oldPos = pos; + draw(); + return; + } + + startValid = isValidStart(pos, (pEvent->button() == MidButton)); + kdDebug(12011) << "Start pos " << pos << " is valid: " << startValid << endl; + // actMove.print(); + + if (!startValid) return; + startPos = oldPos = pos; + + showStart(actMove,1); + startShown = true; + + QString tmp; + actValue = - board.calcEvaluation(); + tmp = i18n("Board value: %1").arg(actValue); + emit updateSpy(tmp); +} + + +void BoardWidget::mouseMoveEvent( QMouseEvent* pEvent ) +{ + if ((!gettingMove && !editMode) || !mbDown) return; + + int pos = positionOf( pEvent->x(), pEvent->y() ); + if (pos == oldPos) return; + oldPos = pos; + + if (editMode) { + int f = fieldOf(pos); + if (field[f] != Board::out && field[f] != editColor) { + int newColor = (editColor == Board::color1) ? Board::color1bright : + (editColor == Board::color2) ? Board::color2bright : + (field[f] == Board::color1) ? Board::color1bright : + (field[f] == Board::color2) ? Board::color2bright : field[f]; + field[f] = newColor; + draw(); + } + return; + } + + if (!startValid) { + /* We haven't a valid move yet. Check if we are over a valid start */ + + startValid = isValidStart(pos, (pEvent->button() == MidButton)); + kdDebug(12011) << "Start pos " << pos << " is valid: " << startValid << endl; + // actMove.print(); + + if (!startValid) return; + startPos = oldPos = pos; + + showStart(actMove,1); + startShown = true; + + QString tmp; + actValue = - board.calcEvaluation(); + tmp = i18n("Board value: %1").arg(actValue); + emit updateSpy(tmp); + return; + } + + /* restore board */ + updatePosition(); + startShown = false; + + if (isValidEnd(pos)) { + // actMove.print(); + + board.playMove(actMove); + int v = board.calcEvaluation(); + board.takeBack(); + + QString tmp; + tmp.sprintf("%+d", v-actValue); + QString str = QString("%1 : %2").arg(actMove.name()).arg(tmp); + emit updateSpy(str); + + showMove(actMove,3); + setCursor(*arrow[shownDirection]); + } + else { + QString tmp; + + setCursor(crossCursor); + if (pos == startPos) { + showStart(actMove,1); + startShown = true; + tmp = i18n("Board value: %1").arg(actValue); + } + else + draw(); + emit updateSpy(tmp); + } +} + + +void BoardWidget::mouseReleaseEvent( QMouseEvent* pEvent ) +{ + if (!gettingMove && !editMode) return; + mbDown = false; + + if (editMode) { + int i; + + // printf("Releasing..."); + for(i=0; ix(), pEvent->y() ); + if (isValidEnd(pos)) { + // actMove.print(); + startValid = false; + setCursor(crossCursor); + gettingMove = false; + emit moveChoosen(actMove); + return; + } + + updatePosition(true); + startValid = false; + setCursor(crossCursor); + + QString tmp; + emit updateSpy(tmp); +} + +QSize BoardWidget::sizeHint() const +{ + return QSize(400, 350); +} + +#include "BoardWidget.moc" diff --git a/kenolaba/BoardWidget.h b/kenolaba/BoardWidget.h new file mode 100644 index 00000000..8fc0a317 --- /dev/null +++ b/kenolaba/BoardWidget.h @@ -0,0 +1,116 @@ +#ifndef _BOARDWIDGET_H_ +#define _BOARDWIDGET_H_ + +#include +#include + +#include "Ball.h" +#include "Move.h" +#include "Board.h" + +#ifdef HAVE_KIR +class KIRenderer; +#endif + +class BoardWidget : public BallWidget +{ + Q_OBJECT + + public: + BoardWidget(Board&, QWidget *parent = 0, const char *name = 0); + ~BoardWidget(); + + void createPos(int , int , int , Ball*); + void initBalls(); + void updateBalls(); + + virtual void resizeEvent(QResizeEvent *); + virtual void moveEvent(QMoveEvent *); + virtual void paintEvent(QPaintEvent *); + virtual void mousePressEvent( QMouseEvent* pEvent ); + virtual void mouseReleaseEvent( QMouseEvent* pEvent ); + virtual void mouseMoveEvent( QMouseEvent* pEvent ); + + void renderBalls(bool r); + + void draw(); + + void choseMove(MoveList*); + + /* Show a move with highlighting + * step 0: state before move + * 1: state after move + * 2: remove all marks (for blinking) + * 3: highlight marks (before move) + * 4: highlight marks (after move) + * Always call with step 0 before actual playing the move !! */ + void showMove(const Move& m, int step, bool updateGUI = true); + + /* Only highlight start + * Step 0: original state + * 1: highlight start + * Always call with step 0 before actual playing the move !! */ + void showStart(const Move& m, int step, bool updateGUI = true); + + + /* enable/disable Edit Mode: + * On disabling & valid position it's actually copied to Board + */ + bool setEditMode(bool); + // int validState() { return board->validState(); } + // bool isValid() { return validState()==Board::valid; } + + /* copy actual board position */ + void updatePosition(bool updateGUI = false); + void clearPosition(); + + int getColor1Count() { return color1Count; } + int getColor2Count() { return color2Count; } + + public slots: + void configure(); + void drawBoard(); + + signals: + void moveChoosen(Move&); + void rightButtonPressed(int,const QPoint&); + void updateSpy(QString); + void edited(int); + protected: + virtual QSize sizeHint() const; + + private: + int positionOf(int x, int y); + bool isValidStart(int pos, bool); + bool isValidEnd(int pos); + + QPixmap pm, boardPM; + Board& board; + int actValue; + + bool editMode, renderMode; + int editColor; + + /* copied position */ + int field[Board::AllFields]; + int color1Count, color2Count, color; + bool boardOK; + + /* for getting user Move */ + MoveList *pList; + Move actMove; + bool gettingMove, mbDown, startValid, startShown; + int startPos, actPos, oldPos, shownDirection; + int startField, startField2, actField, oldField, startType; + QColor *boardColor, *redColor, *yellowColor, *redHColor, *yellowHColor; + QCursor *arrowAll, *arrow[7]; + + Ball *n1, *n2, *h1, *h2, *d1, *d2; //, *e; + +#ifdef HAVE_KIR + KIRenderer *m_backRenderer; +#endif +}; + +#endif /* _BOARDWIDGET_H_ */ + diff --git a/kenolaba/ChangeLog b/kenolaba/ChangeLog new file mode 100644 index 00000000..dc3947a5 --- /dev/null +++ b/kenolaba/ChangeLog @@ -0,0 +1,35 @@ +Version 1.01 (24.9.97) + - Internationalisation supported (locale DE supplied) + - Updated HTML documentation (german added !) + +Version 1.02 (16.10.97) + - Improved computers playing (a little slower but much stronger !) + - Toolbar + - Options saved in config file + Ratings too: Change the way computer rates a position + (see Board::calcRating / readRating) + - New option "Spy": See some of the internals of the computers thoughts ! + - Session management + - KStdAccel used for standard key bindings + - Icon/MiniIcon supplied + + +Version 1.03: + * [Robert Williams] Added version.h and ChangeLog + * [Robert Williams] Added -caption "%c" to kenolaba.kdelnk + * [Robert Williams] Added getHelpMenu() + +Version 1.04 (10.6.99) + - Fixed *BIG* bug in a/b search + - Edit mode + - Copy/Paste Positions in nice ASCII over clipboard + - Ball rendering + - Network Mode + +Version 1.05 (16.3.2000) + - Statusbar correction + - Action'ized (Menu + Toolbar), using XML GUI description + +Version 1.05b (24.7.2000) + - Bugfix release, Cleanup for KDE 2.0 + \ No newline at end of file diff --git a/kenolaba/EvalDlg.ui b/kenolaba/EvalDlg.ui new file mode 100644 index 00000000..06931458 --- /dev/null +++ b/kenolaba/EvalDlg.ui @@ -0,0 +1,1760 @@ + +EvalDlg + + + EvalDlg + + + + 0 + 0 + 350 + 388 + + + + Configure Evaluation + + + + unnamed + + + 11 + + + 6 + + + + TabWidget2 + + + + + + moves + + + Moves + + + + unnamed + + + 11 + + + 6 + + + + Layout17 + + + + unnamed + + + 0 + + + 6 + + + + Layout35 + + + + + + unnamed + + + 0 + + + 4 + + + + moveEval1 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel3_2 + + + image0 + + + false + + + + + moveEval2 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel1_2_5 + + + image1 + + + false + + + + + moveEval3 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel3_3 + + + image0 + + + false + + + + + unnamed + + + image1 + + + false + + + + + PixmapLabel1_2_6 + + + image1 + + + false + + + + + PixmapLabel1_2_4 + + + image1 + + + false + + + + + PixmapLabel3 + + + image0 + + + false + + + + + PixmapLabel1_2 + + + image1 + + + false + + + + + PixmapLabel1_3 + + + image1 + + + false + + + + + Spacer2 + + + Horizontal + + + Expanding + + + + + + + TextLabel4_2_2 + + + Push Out + + + AlignTop|AlignLeft + + + + + + + Spacer9_2 + + + Horizontal + + + Expanding + + + + + TextLabel4_2 + + + Push + + + AlignTop|AlignLeft + + + + + + + Layout37 + + + + + + unnamed + + + 0 + + + 4 + + + + PixmapLabel1_2_5_2_3 + + + image1 + + + false + + + + + PixmapLabel3_3_2_3 + + + image0 + + + false + + + + + PixmapLabel3_3_2_2 + + + image0 + + + false + + + + + moveEval4 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + moveEval5 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel2_3 + + + image2 + + + false + + + + + PixmapLabel1_2_5_2 + + + image1 + + + false + + + + + PixmapLabel3_3_2 + + + image0 + + + false + + + + + PixmapLabel2_2_2 + + + image2 + + + false + + + + + PixmapLabel1_3_2 + + + image1 + + + false + + + + + Spacer2_2 + + + Horizontal + + + Expanding + + + + + moveEval6 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel1_4 + + + image1 + + + false + + + + + PixmapLabel1_2_2 + + + image1 + + + false + + + + + PixmapLabel2_2 + + + image2 + + + false + + + + + PixmapLabel1_4_3 + + + image1 + + + false + + + + + PixmapLabel1_2_5_2_2 + + + image1 + + + + + PixmapLabel2 + + + image2 + + + false + + + + + PixmapLabel1_4_2 + + + image1 + + + false + + + + + + + Spacer9 + + + Horizontal + + + Expanding + + + + + Layout38 + + + + + + unnamed + + + 0 + + + 4 + + + + PixmapLabel2_4 + + + image2 + + + false + + + + + PixmapLabel1_3_2_2 + + + image1 + + + false + + + + + PixmapLabel1_2_5_2_2_2 + + + image1 + + + + + Spacer2_2_2 + + + Horizontal + + + Expanding + + + + + moveEval7 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel1_2_2_2 + + + image1 + + + false + + + + + PixmapLabel2_2_2_3 + + + image2 + + + false + + + + + moveEval9 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel1_4_2_2 + + + image1 + + + false + + + + + PixmapLabel1_2_5_2_3_3 + + + image1 + + + false + + + + + moveEval8 + + + + 0 + 0 + 0 + 0 + + + + + 30 + 32767 + + + + AlignLeft + + + + + + + PixmapLabel1_4_3_2 + + + image1 + + + false + + + + + PixmapLabel1_4_4 + + + image1 + + + false + + + + + PixmapLabel1_2_5_2_4 + + + image1 + + + false + + + + + PixmapLabel2_3_3 + + + image2 + + + false + + + + + PixmapLabel2_2_3 + + + image2 + + + false + + + + + + + TextLabel4 + + + Normal + + + AlignTop|AlignLeft + + + + + + + + + TextLabel5 + + + + 0 + 20 + + + + For every move possible the given points are added to the Evaluation. + + + WordBreak|AlignTop|AlignLeft + + + + + + + + + Spacer5 + + + Vertical + + + Expanding + + + + + + + position + + + Position + + + + unnamed + + + 11 + + + 6 + + + + Layout63 + + + + unnamed + + + 0 + + + 0 + + + + Spacer12 + + + Horizontal + + + Expanding + + + + + Layout62 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel1_2_3_2 + + + Inner ring 3: + + + + + posEval3 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + posEval5 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + posEval2 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2 + + + Outermost ring: + + + + + diffEval2 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + diffEval3 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + posEval4 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2 + + + Middle position: + + + + + diffEval5 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + posEval1 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_3 + + + Inner ring 2: + + + + + TextLabel3_4 + + + +/- + + + + + TextLabel3_3 + + + +/- + + + + + diffEval4 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + TextLabel3_2 + + + +/- + + + + + TextLabel1_2_2_2 + + + Innermost ring: + + + + + TextLabel3 + + + +/- + + + + + + + Spacer11 + + + Horizontal + + + Expanding + + + + + + + TextLabel6 + + + For every ball, the given points are added to the evaluation depending on the balls position. The bonus for a given position is changed randomly in the +/- range. + + + WordBreak|AlignTop|AlignLeft + + + + + + + + + Spacer4 + + + Vertical + + + Expanding + + + + + + + inarow + + + In-A-Row + + + + unnamed + + + 11 + + + 6 + + + + Layout64 + + + + unnamed + + + 0 + + + 6 + + + + Spacer14 + + + Horizontal + + + Expanding + + + + + Layout42 + + + + unnamed + + + 0 + + + 6 + + + + rowEval3 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + rowEval2 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + rowEval5 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + rowEval4 + + + + 30 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2_3_2 + + + Three in-a-row: + + + + + TextLabel1_2_2_3 + + + Two in-a-row: + + + + + TextLabel1_2_2_3_3 + + + Four in-a-row: + + + + + TextLabel1_2_2_3_4 + + + Five in-a-row: + + + + + + + Spacer13 + + + Horizontal + + + Expanding + + + + + + + TextLabel6_2 + + + For a number of balls In-a-Row, the given points are added to the evaluation + + + WordBreak|AlignTop|AlignLeft + + + + + + + + + Spacer6 + + + Vertical + + + Expanding + + + + + + + count + + + Count + + + + unnamed + + + 11 + + + 6 + + + + Layout66 + + + + unnamed + + + 0 + + + 6 + + + + Spacer16 + + + Horizontal + + + Expanding + + + + + Layout65 + + + + unnamed + + + 0 + + + 6 + + + + countEval2 + + + + 40 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2_3_4_2 + + + 4 Balls more: + + + + + countEval5 + + + + 40 + 32767 + + + + AlignLeft + + + + + + + countEval4 + + + + 40 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2_3_3_2 + + + 3 Balls more: + + + + + TextLabel1_2_2_3_4_2_2 + + + 5 Balls more: + + + + + countEval1 + + + + 40 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2_3_2_2 + + + 2 Balls more: + + + + + countEval3 + + + + 40 + 32767 + + + + AlignLeft + + + + + + + TextLabel1_2_2_3_5 + + + 1 Ball more: + + + + + + + Spacer15 + + + Horizontal + + + Expanding + + + + + + + TextLabel6_2_2 + + + For a difference in the number of balls, the given points are added to the evaluation. A difference of 6 only can be a lost/won game. + + + WordBreak|AlignTop|AlignLeft + + + + + + + + + Spacer6_2 + + + Vertical + + + Expanding + + + + + + + tab + + + Evaluation Schemes + + + + unnamed + + + 11 + + + 6 + + + + evalList + + + + + Layout13 + + + + unnamed + + + 0 + + + 6 + + + + evalSaveAs + + + Save As... + + + + + evalDelete + + + Delete + + + + + + + TextLabel1 + + + Your evaluation scheme, defined in all other tabs of this dialog, can be stored here. + + + WordBreak|AlignTop|AlignLeft + + + + + + + + + + + + Layout13 + + + + unnamed + + + 0 + + + 6 + + + + Spacer2_3 + + + Horizontal + + + Expanding + + + + + TextLabel9 + + + Evaluation of actual position: + + + + + actualEval + + + Flat + + + + + Spacer1 + + + Horizontal + + + Expanding + + + + + + + + + 789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade6523234530022630543251d2e253d856405bffcbc54105b19c856b630b630b43006711341dc343000ab0401651000b3f4a062ca30801003721241002208160309817525825950318810d8108818921058901662d8ecd583fb4a0fe13eb820c4f1e8fe4d448401d8ab204f23850b483431116a9352ad351700a1cd4f38 + + + 789c6dd0410ac2301005d07d4e3124bb20ad4511413c82e2521017e9c4a28b56d0ba10f1ee66664cda6a3fa1cc7f9436496e61bfdb80cdd5bd75ed0501cfee06d63feafa7938ae5f4a170b082b3cf444e90c10b6d7e644b309b39972a83aaaf322d692ea72162b52adaa58bd540a7f9662283c655f33c65144c5884a0a235b2241b14401c5fa44d83744fc3544c6bea1e4cf7c32f92f91f76806fbe3f7d2fe3aecce317aded17b1944bf57ea03b18f6cb9 + + + 789c6dd04d0ac2301005e07d4e3124bb20ad452c05f1088a4b415c24138b2e5a41eb42c4bb9bc9246a208f52e67d94fcb4d6b0df6d40d7e23e99e98280677303ed1ec3f03c1cd72f219b16fce35f7226640508dbeb78a259f959cd43a81aaadda26bb85aaab8c4962b52ed7db8ba54fb3e2c4b51943055d194321456b648118331596b19d9220564fb1163329b921bfa940cffcd047398d68bfb7a72cea8fc7cf4ddf77ca57b14ef5bfc2f59e47b253ec60c6d67 + + + + TabWidget2 + moveEval1 + moveEval2 + moveEval3 + moveEval4 + moveEval5 + moveEval6 + moveEval7 + moveEval8 + moveEval9 + posEval1 + posEval2 + diffEval2 + posEval3 + diffEval3 + posEval4 + diffEval4 + posEval5 + diffEval5 + rowEval2 + rowEval3 + rowEval4 + rowEval5 + countEval1 + countEval2 + countEval3 + countEval4 + countEval5 + evalList + evalDelete + evalSaveAs + + + kseparator.h + + + diff --git a/kenolaba/EvalDlgImpl.cpp b/kenolaba/EvalDlgImpl.cpp new file mode 100644 index 00000000..a5903429 --- /dev/null +++ b/kenolaba/EvalDlgImpl.cpp @@ -0,0 +1,299 @@ +/** + * Some Implementation details for configEval Dialog + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "EvalDlgImpl.h" +#include "Board.h" +#include "EvalScheme.h" + +EvalDlgImpl::EvalDlgImpl(QWidget* parent, Board* board) + :EvalDlg(parent) +{ + _board = board; + _origScheme = board->evalScheme(); + _scheme = new EvalScheme(*_origScheme); + + connect( evalDelete, SIGNAL( clicked() ), this, SLOT( deleteEntry() ) ); + connect( evalSaveAs, SIGNAL( clicked() ), this, SLOT( saveas() ) ); + connect( evalList, SIGNAL( highlighted(int) ), this, SLOT( select(int) ) ); + + KConfig* config = kapp->config(); + config->setGroup("General"); + QStringList list = config->readListEntry("EvalSchemes"); + evalList->insertItem( i18n("Current") ); + evalList->insertItem( i18n("Default") ); + for(int i=0;iinsertItem(list[i]); + + evalList->setSelected(0, TRUE); + + updateWidgets(); + connectEditLines(); +} + +EvalDlgImpl::~EvalDlgImpl() +{ + delete _scheme; +} + + +void EvalDlgImpl::connectEditLines() +{ + connect( moveEval1, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval2, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval3, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval4, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval5, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval6, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval7, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval8, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( moveEval9, SIGNAL(textChanged(const QString&)), this, SLOT(updateMove()) ); + connect( posEval1, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( posEval2, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( posEval3, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( posEval4, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( posEval5, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( diffEval2, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( diffEval3, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( diffEval4, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( diffEval5, SIGNAL(textChanged(const QString&)), this, SLOT(updateFields()) ); + connect( rowEval2, SIGNAL(textChanged(const QString&)), this, SLOT(updateInARow()) ); + connect( rowEval3, SIGNAL(textChanged(const QString&)), this, SLOT(updateInARow()) ); + connect( rowEval4, SIGNAL(textChanged(const QString&)), this, SLOT(updateInARow()) ); + connect( rowEval5, SIGNAL(textChanged(const QString&)), this, SLOT(updateInARow()) ); + connect( countEval1, SIGNAL(textChanged(const QString&)), this, SLOT(updateCount()) ); + connect( countEval2, SIGNAL(textChanged(const QString&)), this, SLOT(updateCount()) ); + connect( countEval3, SIGNAL(textChanged(const QString&)), this, SLOT(updateCount()) ); + connect( countEval4, SIGNAL(textChanged(const QString&)), this, SLOT(updateCount()) ); + connect( countEval5, SIGNAL(textChanged(const QString&)), this, SLOT(updateCount()) ); +} + +void EvalDlgImpl::disconnectEditLines() +{ + moveEval1->disconnect(); + moveEval2->disconnect(); + moveEval3->disconnect(); + moveEval4->disconnect(); + moveEval5->disconnect(); + moveEval6->disconnect(); + moveEval7->disconnect(); + moveEval8->disconnect(); + moveEval9->disconnect(); + posEval1->disconnect(); + posEval2->disconnect(); + posEval3->disconnect(); + posEval4->disconnect(); + posEval5->disconnect(); + diffEval2->disconnect(); + diffEval3->disconnect(); + diffEval4->disconnect(); + diffEval5->disconnect(); + rowEval2->disconnect(); + rowEval3->disconnect(); + rowEval4->disconnect(); + rowEval5->disconnect(); + countEval1->disconnect(); + countEval2->disconnect(); + countEval3->disconnect(); + countEval4->disconnect(); + countEval5->disconnect(); +} + +void EvalDlgImpl::updateWidgets() +{ + // Moves + moveEval1->setText( QString::number(_scheme->moveValue(Move::move1)) ); + moveEval2->setText( QString::number(_scheme->moveValue(Move::move2)) ); + moveEval3->setText( QString::number(_scheme->moveValue(Move::move3)) ); + moveEval4->setText( QString::number(_scheme->moveValue(Move::push1with2)) ); + moveEval5->setText( QString::number(_scheme->moveValue(Move::push1with3)) ); + moveEval6->setText( QString::number(_scheme->moveValue(Move::push2)) ); + moveEval7->setText( QString::number(_scheme->moveValue(Move::out1with2)) ); + moveEval8->setText( QString::number(_scheme->moveValue(Move::out1with3)) ); + moveEval9->setText( QString::number(_scheme->moveValue(Move::out2)) ); + + // Position + posEval1->setText( QString::number(_scheme->ringValue(0)) ); + posEval2->setText( QString::number(_scheme->ringValue(1)) ); + posEval3->setText( QString::number(_scheme->ringValue(2)) ); + posEval4->setText( QString::number(_scheme->ringValue(3)) ); + posEval5->setText( QString::number(_scheme->ringValue(4)) ); + + diffEval2->setText( QString::number(_scheme->ringDiff(1)) ); + diffEval3->setText( QString::number(_scheme->ringDiff(2)) ); + diffEval4->setText( QString::number(_scheme->ringDiff(3)) ); + diffEval5->setText( QString::number(_scheme->ringDiff(4)) ); + + // InARow + rowEval2->setText( QString::number(_scheme->inARowValue(0)) ); + rowEval3->setText( QString::number(_scheme->inARowValue(1)) ); + rowEval4->setText( QString::number(_scheme->inARowValue(2)) ); + rowEval5->setText( QString::number(_scheme->inARowValue(3)) ); + + // Count + countEval1->setText( QString::number(_scheme->stoneValue(1)) ); + countEval2->setText( QString::number(_scheme->stoneValue(2)) ); + countEval3->setText( QString::number(_scheme->stoneValue(3)) ); + countEval4->setText( QString::number(_scheme->stoneValue(4)) ); + countEval5->setText( QString::number(_scheme->stoneValue(5)) ); + + updateEval(); +} + +void EvalDlgImpl::updateEval() +{ + int value; + + // set temporary the new scheme + _board->setEvalScheme(_scheme); + value = - _board->calcEvaluation(); + _board->setEvalScheme(_origScheme); + + kdDebug(12011) << "Updated Eval: " << value << endl; + + if (value<-15999 || value>15999) value=0; + actualEval->display(value); +} + +void EvalDlgImpl::updateMove() +{ + _scheme->setMoveValue(Move::move1, moveEval1->text().toInt()); + _scheme->setMoveValue(Move::move2, moveEval2->text().toInt()); + _scheme->setMoveValue(Move::left2, moveEval2->text().toInt()); + _scheme->setMoveValue(Move::right2, moveEval2->text().toInt()); + _scheme->setMoveValue(Move::move3, moveEval3->text().toInt()); + _scheme->setMoveValue(Move::left3, moveEval3->text().toInt()); + _scheme->setMoveValue(Move::right3, moveEval3->text().toInt()); + + _scheme->setMoveValue(Move::push1with2, moveEval4->text().toInt()); + _scheme->setMoveValue(Move::push1with3, moveEval5->text().toInt()); + _scheme->setMoveValue(Move::push2, moveEval6->text().toInt()); + + _scheme->setMoveValue(Move::out1with2, moveEval7->text().toInt()); + _scheme->setMoveValue(Move::out1with3, moveEval8->text().toInt()); + _scheme->setMoveValue(Move::out2, moveEval9->text().toInt()); + + updateEval(); +} + +void EvalDlgImpl::updateCount() +{ + _scheme->setStoneValue(1, countEval1->text().toInt()); + _scheme->setStoneValue(2, countEval2->text().toInt()); + _scheme->setStoneValue(3, countEval3->text().toInt()); + _scheme->setStoneValue(4, countEval4->text().toInt()); + _scheme->setStoneValue(5, countEval5->text().toInt()); + + updateEval(); +} + +void EvalDlgImpl::updateFields() +{ + _scheme->setRingValue(0, posEval1->text().toInt()); + _scheme->setRingValue(1, posEval2->text().toInt()); + _scheme->setRingValue(2, posEval3->text().toInt()); + _scheme->setRingValue(3, posEval4->text().toInt()); + _scheme->setRingValue(4, posEval5->text().toInt()); + _scheme->setRingDiff(1, diffEval2->text().toInt()); + _scheme->setRingDiff(2, diffEval3->text().toInt()); + _scheme->setRingDiff(3, diffEval4->text().toInt()); + _scheme->setRingDiff(4, diffEval5->text().toInt()); + + updateEval(); +} + +void EvalDlgImpl::updateInARow() +{ + _scheme->setInARowValue(0, rowEval2->text().toInt()); + _scheme->setInARowValue(1, rowEval3->text().toInt()); + _scheme->setInARowValue(2, rowEval4->text().toInt()); + _scheme->setInARowValue(3, rowEval5->text().toInt()); + + updateEval(); +} + + +void EvalDlgImpl::deleteEntry() +{ + int i = evalList->currentItem(); + // You cannot delete Pseudo Items 0 (Current) and 1 (Default) + + if (i>1) { + QString name = evalList->text(i); + evalList->removeItem(i); + + KConfig* config = kapp->config(); + config->setGroup("General"); + QStringList list = config->readListEntry("EvalSchemes"); + list.remove(name); + config->writeEntry("EvalSchemes", list); + config->sync(); + } +} + +void EvalDlgImpl::saveas() +{ + KLineEditDlg dlg(i18n("Name for scheme:"), QString::null, this); + dlg.setCaption(i18n("Save Scheme")); + + if (dlg.exec()) { + QString name=dlg.text(); + KConfig* config = kapp->config(); + config->setGroup("General"); + QStringList list = config->readListEntry("EvalSchemes"); + QListBoxItem *it = evalList->findItem(name); + if (!it) { + evalList->insertItem(name); + it = evalList->findItem(name); + list << name; + config->writeEntry("EvalSchemes", list); + } + evalList->setSelected(it, TRUE); + + EvalScheme savedScheme(*_scheme); + savedScheme.setName(name); + savedScheme.save(config); + config->sync(); + } +} + +void EvalDlgImpl::select(int i) +{ + QString name = evalList->text(i); + + delete _scheme; + _scheme = 0; + + // 2 fixed entries: 0 is Current (origScheme), 1 is Default + + if (i == 0) _scheme = new EvalScheme(*_origScheme); + else if (i==1) { + _scheme = new EvalScheme(name); + } + else { + // read in the Scheme from the config file + _scheme = new EvalScheme(name); + KConfig* config = kapp->config(); + _scheme->read(config); + } + + kdDebug(12011) << "Selected " << name << ", Index " << i << endl; + + disconnectEditLines(); + updateWidgets(); + connectEditLines(); +} +#include "EvalDlgImpl.moc" diff --git a/kenolaba/EvalDlgImpl.h b/kenolaba/EvalDlgImpl.h new file mode 100644 index 00000000..70c903fb --- /dev/null +++ b/kenolaba/EvalDlgImpl.h @@ -0,0 +1,44 @@ +/** + * Some Implementation details for configEval Dialog + * + */ + +#ifndef _EVALDLGIMPL_H_ +#define _EVALDLGIMPL_H_ + +#include "EvalDlg.h" + +class EvalScheme; +class Board; + +class EvalDlgImpl: public EvalDlg +{ + Q_OBJECT + + public: + EvalDlgImpl(QWidget* parent, Board* board); + ~EvalDlgImpl(); + + EvalScheme* evalScheme() { return _scheme; } + + public slots: + void deleteEntry(); + void saveas(); + void select(int i); + void updateCount(); + void updateMove(); + void updateFields(); + void updateInARow(); + + private: + void updateEval(); + void updateWidgets(); + void connectEditLines(); + void disconnectEditLines(); + + EvalScheme *_origScheme, *_scheme; + Board* _board; +}; + +#endif // _EVALDLGIMPL_H_ + diff --git a/kenolaba/EvalScheme.cpp b/kenolaba/EvalScheme.cpp new file mode 100644 index 00000000..18ba5b43 --- /dev/null +++ b/kenolaba/EvalScheme.cpp @@ -0,0 +1,231 @@ +/** + * EvalScheme + * + * Configuration options for a Evaluation Scheme. + * Evaluation Schemes are used for evalution of a Abalone board position + * + * (C) JW, 2000 + */ + +#include +#include + +#include "EvalScheme.h" + +// Default Values +static int defaultRingValue[] = { 45, 35, 25, 10, 0 }; +static int defaultRingDiff[] = { 0, 10, 10, 8, 5 }; +static int defaultStoneValue[]= { 0,-800,-1800,-3000,-4400,-6000 }; +static int defaultMoveValue[Move::typeCount] = { 40,30,30, 15,14,13, + 5,5,5, 2,2,2, 1 }; +static int defaultInARowValue[InARowCounter::inARowCount]= { 2, 5, 4, 3 }; + + +/** + * Constructor: Set Default values + */ +EvalScheme::EvalScheme(QString n) +{ + _name = n; + setDefaults(); +} + + +/** + * Copy Constructor + */ +EvalScheme::EvalScheme(EvalScheme& s) +{ + _name = s._name; + + for(int i=0;i<6;i++) + _stoneValue[i] = s._stoneValue[i]; + + for(int i=0;isetGroup(confSection); + + QStringList list; + QString tmp; + + list = config->readListEntry("StoneValues"); + if (list.count()>0) { + _stoneValue[0] = 0; + for(int i=1;i<6;i++) + _stoneValue[i] = list[i-1].toInt(); + } + + list = config->readListEntry("MoveValues"); + if (list.count()>0) { + for(int i=0;ireadListEntry("InARowValues"); + if (list.count()>0) { + for(int i=0;ireadListEntry("RingValues"); + if (list.count()>0) { + for(int i=0;i<5;i++) + _ringValue[i] = list[i].toInt(); + } + + list = config->readListEntry("RingDiffs"); + if (list.count()>0) { + for(int i=0;i<5;i++) + _ringDiff[i] = list[i].toInt(); + } +} + + +void EvalScheme::save(KConfig* config) +{ + QString confSection = QString("%1 Evaluation Scheme").arg(_name); + config->setGroup(confSection); + + QString entry; + + entry.sprintf("%d,%d,%d,%d,%d", _stoneValue[1], _stoneValue[2], + _stoneValue[3], _stoneValue[4], _stoneValue[5]); + config->writeEntry("StoneValues", entry); + + entry.sprintf("%d", _moveValue[0]); + for(int i=1;iwriteEntry("MoveValues", entry); + + entry.sprintf("%d", _inARowValue[0]); + for(int i=1;iwriteEntry("InARowValues", entry); + + entry.sprintf("%d,%d,%d,%d,%d", _ringValue[0], _ringValue[1], + _ringValue[2], _ringValue[3], _ringValue[4]); + config->writeEntry("RingValues", entry); + + entry.sprintf("%d,%d,%d,%d,%d", _ringDiff[0], _ringDiff[1], + _ringDiff[2], _ringDiff[3], _ringDiff[4]); + config->writeEntry("RingDiffs", entry); +} + +void EvalScheme::setRingValue(int ring, int value) +{ + if (ring >=0 && ring <5) + _ringValue[ring] = value; +} + +void EvalScheme::setRingDiff(int ring, int value) +{ + if (ring >=1 && ring <5) + _ringDiff[ring] = value; +} + +void EvalScheme::setStoneValue(int stoneDiff, int value) +{ + if (stoneDiff>0 && stoneDiff<6) + _stoneValue[stoneDiff] = value; +} + +void EvalScheme::setMoveValue(int type, int value) +{ + if (type>=0 && type=0 && stones=,,,,... (34 values) + * + */ + +EvalScheme* EvalScheme::create(QString scheme) +{ + int pos = scheme.find('='); + if (pos<0) return 0; + + EvalScheme* evalScheme = new EvalScheme( scheme.left(pos) ); + evalScheme->setDefaults(); + + QStringList list = QStringList::split( QString(","), scheme.right(pos+1) ); + + int i=0; + while(i_stoneValue[i+1] = list[i].toInt(); + else if (i<10) + evalScheme->_ringValue[i-5] = list[i].toInt(); + else if (i<15) + evalScheme->_ringDiff[i-10] = list[i].toInt(); + else if (i<15+Move::typeCount) + evalScheme->_moveValue[i-15] = list[i].toInt(); + else if (i<15+Move::typeCount+InARowCounter::inARowCount) + evalScheme->_inARowValue[i-15-Move::typeCount] = list[i].toInt(); + i++; + } + + return evalScheme; +} + +QString EvalScheme::ascii() +{ + QString res; + int i; + + res.sprintf("%s=%d", _name.ascii(), _stoneValue[1]); + for(i=1;i<6;i++) + res += QString(",%1").arg( _stoneValue[i] ); + for(i=0;i + +#include "Move.h" + +class KConfig; + +/* + * The constructor gets a name, and tries to read the scheme + * for the Kenolaba configuration file, if nothing found, use + * default values + */ + +class EvalScheme +{ + public: + EvalScheme(QString); + EvalScheme(EvalScheme&); + ~EvalScheme() {} + + void setDefaults(); + void read(KConfig*); + void save(KConfig*); + + static EvalScheme* create(QString); + QString ascii(); + + void setName(QString n) { _name = n; } + void setRingValue(int ring, int value); + void setRingDiff(int ring, int value); + void setStoneValue(int stoneDiff, int value); + void setMoveValue(int type, int value); + void setInARowValue(int stones, int value); + + QString name() { return _name; } + int ringValue(int r) { return (r>=0 && r<5) ? _ringValue[r] : 0; } + int ringDiff(int r) { return (r>0 && r<5) ? _ringDiff[r] : 0; } + int stoneValue(int s) { return (s>0 && s<6) ? _stoneValue[s] : 0; } + int moveValue(int t) { return (t>=0 && t=0 && s +#include + +#include + +#include + +#include "Move.h" +#include "Board.h" + +const QString nameOfDir(int dir) +{ + dir = dir % 6; + return + (dir == 1) ? i18n("Right") : + (dir == 2) ? i18n("RightDown") : + (dir == 3) ? i18n("LeftDown") : + (dir == 4) ? i18n("Left") : + (dir == 5) ? i18n("LeftUp") : + (dir == 0) ? i18n("RightUp") : QString("??"); +} + +QString nameOfPos(int p) +{ + static char tmp[3]; + tmp[0] = 'A' + (p-12)/11; + tmp[1] = '1' + (p-12)%11; + tmp[2] = 0; + + return QString( tmp ); +} + +QString Move::name() const +{ + QString s,tmp; + + /* sideway moves... */ + if (type == left3 || type == right3) { + int f1, f2, df; + + f1 = f2 = field; + df = 2* Board::fieldDiffOfDir(direction); + if (df > 0) + f2 += df; + else + f1 += df; + + s = nameOfPos( f1 ); + s += '-'; + s += nameOfPos( f2 ); + s+= '/'; + s+= (type == left3) ? nameOfDir(direction-1): nameOfDir(direction+1); + } + else if ( type == left2 || type == right2) { + int f1, f2, df; + + f1 = f2 = field; + df = Board::fieldDiffOfDir(direction); + if (df > 0) + f2 += df; + else + f1 += df; + + s = nameOfPos( f1 ); + s += '-'; + s += nameOfPos( f2 ); + s+= '/'; + s+= (type == left2) ? nameOfDir(direction-1): nameOfDir(direction+1); + } + else if (type == none) { + s = QString("??"); + } + else { + s = nameOfPos( field ); + s += '/'; + s += nameOfDir(direction); + + tmp = (type <3 ) ? i18n("Out") : + (type <6 ) ? i18n("Push") : QString(""); + if (!tmp.isEmpty()) { + s += '/'; + s += tmp; + } + } + return s; +} + +void Move::print() const +{ + printf("%s", name().ascii() ); +} + +MoveTypeCounter::MoveTypeCounter() +{ + init(); +} + +void MoveTypeCounter::init() +{ + for(int i=0;i < Move::typeCount;i++) + count[i] = 0; +} + +int MoveTypeCounter::sum() +{ + int sum = count[0]; + + for(int i=1;i < Move::typeCount;i++) + sum += count[i]; + + return sum; +} + + +InARowCounter::InARowCounter() +{ + init(); +} + +void InARowCounter::init() +{ + for(int i=0;i < inARowCount;i++) + count[i] = 0; +} + +MoveList::MoveList() +{ + clear(); +} + +void MoveList::clear() +{ + int i; + + for(i=0;i= Move::typeCount) return; + if (nextUnused == MaxMoves) return; + + assert( nextUnused < MaxMoves ); + + /* adjust queue */ + if (first[t] == -1) { + first[t] = last[t] = nextUnused; + } + else { + assert( last[t] < nextUnused ); + next[last[t]] = nextUnused; + last[t] = nextUnused; + } + + next[nextUnused] = -1; + move[nextUnused] = m; + nextUnused++; +} + +bool MoveList::isElement(int f) +{ + int i; + + for(i=0; i 0) && (mm.direction != m.direction)) + continue; + + /* if type is supplied it has to match */ + if ((m.type != Move::none) && (m.type != mm.type)) + continue; + + if (m.type == mm.type) { + /* exact match; eventually supply direction */ + m.direction = mm.direction; + if (del) mm.type = Move::none; + return true; + } + + switch(mm.type) { + case Move::left3: + case Move::right3: + if (startType == start3 || startType == all) { + m.type = mm.type; + m.direction = mm.direction; + if (del) mm.type = Move::none; + return true; + } + break; + case Move::left2: + case Move::right2: + if (startType == start2 || startType == all) { + m.type = mm.type; + m.direction = mm.direction; + if (del) mm.type = Move::none; + return true; + } + break; + default: + if (startType == start1 || startType == all) { + /* unexact match: supply type */ + m.type = mm.type; + m.direction = mm.direction; + if (del) mm.type = Move::none; + return true; + } + } + } + return false; +} + + +bool MoveList::getNext(Move& m, int maxType) +{ + if (actualType == Move::typeCount) return false; + + while(1) { + while(actualType < 0 || actual[actualType] == -1) { + actualType++; + if (actualType == Move::typeCount) return false; + actual[actualType] = first[actualType]; + if (actualType > maxType) return false; + } + m = move[actual[actualType]]; + actual[actualType] = next[actual[actualType]]; + if (m.type != Move::none) break; + } + + return true; +} + + diff --git a/kenolaba/Move.h b/kenolaba/Move.h new file mode 100644 index 00000000..1226d969 --- /dev/null +++ b/kenolaba/Move.h @@ -0,0 +1,132 @@ +/* Classes Move, MoveList + * - represents a move in the game of Abalone + * + * Josef Weidendorfer, 28.8.97 +*/ + +#ifndef _MOVE_H_ +#define _MOVE_H_ + +#include + +class Move +{ + public: + + /* Type of move: Moves are searched in this order */ + enum MoveType { out2 = 0, out1with3, out1with2, push2, + push1with3, push1with2, move3, left3, right3, + left2, right2, move2, move1, none }; + enum { typeCount = none }; + + Move() { type = none; } + Move(short f, char d, MoveType t) + { field = f; direction = d, type = t; } + + + bool isOutMove() const + { return type <= out1with2; } + bool isPushMove() const + { return type <= push1with2; } + static int maxOutType() + { return out1with2; } + static int maxPushType() + { return push1with2; } + static int maxMoveType() + { return move1; } + + QString name() const; + + void print() const; + + /* Directions */ + enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp }; + + short field; + unsigned char direction; + MoveType type; +}; + +/** + * Class MoveTypeCounter + * + * Used in Board evaluation to count types of board allowed + * in a position + */ +class MoveTypeCounter +{ + public: + MoveTypeCounter(); + ~MoveTypeCounter() {} + + void init(); + void incr(int t) { count[t]++; } + int get(int t) { return count[t]; } + int sum(); + + private: + int count[Move::typeCount]; +}; + +/** + * Class InARowCounter + * + * Used in Board evaluation to count connectiveness + * of some degrees in a position + */ +class InARowCounter +{ + public: + enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount }; + + InARowCounter(); + ~InARowCounter() {} + + void init(); + void incr(int c) { count[c]++; } + int get(int c) { return count[c]; } + + private: + int count[inARowCount]; +}; + + +/* MoveList stores a fixed number of moves (for efficince) + * returns reference of next move ordered according to type + * does nothing if there isn't enough free space + * + * Recommend usage (* means 0 or more times): + * [ clear() ; insert() * ; isElement() * ; getNext() * ] * + */ +class MoveList +{ + public: + MoveList(); + + enum { MaxMoves = 150 }; + + /* for isElement: search for moves starting with 1/2/3 fields */ + enum { all , start1, start2, start3 }; + + void clear(); + void insert(Move); + bool isElement(int f); + bool isElement(Move&, int startType, bool del=false); + void insert(short f, char d, Move::MoveType t) + { insert( Move(f,d,t) ); } + int getLength() + { return nextUnused; } + + bool getNext(Move&,int maxType); /* returns false if no more moves */ + + private: + Move move[MaxMoves]; + int next[MaxMoves]; + int first[Move::typeCount]; + int last[Move::typeCount]; + int actual[Move::typeCount]; + int nextUnused, actualType; +}; + +#endif /* _MOVE_H_ */ + diff --git a/kenolaba/Network.cpp b/kenolaba/Network.cpp new file mode 100644 index 00000000..e12f6b5e --- /dev/null +++ b/kenolaba/Network.cpp @@ -0,0 +1,193 @@ +#include + +#include "Network.h" + +#include +#include +#include +#include +#include +#include +#include + +Listener::Listener(const char* h, int p, struct sockaddr_in s,bool r) +{ + if (h==0) + host[0]=0; + else { + int l = strlen(h); + if (l>99) l=99; + strncpy(host, h, l); + host[l] = 0; + } + port = p; + sin = s; + reachable = r; +} + +Network::Network(int port) +{ + struct sockaddr_in name; + int i,j; + + listeners.setAutoDelete(TRUE); + + fd = ::socket (PF_INET, SOCK_STREAM, 0); + if (fd<0) return; + + for(i = 0; i<5;i++) { + name.sin_family = AF_INET; + name.sin_port = htons (port+i); + name.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (fd, (struct sockaddr *) &name, sizeof (name)) >= 0) + break; + // printf("...Port %d in use\n", port+i); + } + mySin = name; + // printf("I'm using Port %d\n", port+i); + if (i==5) { + printf("Error in bind to port %d\n", port); + close(fd); + fd = -1; + return; + } + for(j = 0; jreachable) + sendString( l->sin, tmp, len); + } + listeners.clear(); + + delete sn; +} + +void Network::gotConnection() +{ + static char tmp[1024]; + int len=0; + struct sockaddr_in sin; + kde_socklen_t sz = sizeof (sin); + + // printf("GotConnection: "); + int s = accept(fd,(struct sockaddr *)&sin, &sz); + if (s<0) { + printf("Error in accept\n"); + return; + } + while(read(s, tmp+len, 1)==1) len++; + close(s); + tmp[len]=0; len++; + // printf("Got: '%s'\n",tmp); + if (strncmp(tmp,"reg ",4)==0) { + int port = atoi(tmp+4); + sin.sin_port = htons( port ); + Listener *l = new Listener(0,0,sin); + // printf("Reg of 0x%x:%d\n", + // ntohl(sin.sin_addr.s_addr ), ntohs(sin.sin_port)); + listeners.append(l); + return; + } + + if (strncmp(tmp,"unreg ",6)==0) { + int port = atoi(tmp+6); + sin.sin_port = htons( port ); + Listener* l; + for(l=listeners.first(); l!=0; l=listeners.next()) + if (l->sin.sin_addr.s_addr == sin.sin_addr.s_addr && + l->sin.sin_port == sin.sin_port) break; + if (l==0) { + printf("Error: UnReg of 0x%x:%d. Not Found\n", + ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + return; + } + listeners.remove(l); + // printf("UnReg of 0x%x:%d\n", + // ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + return; + } + + if (strncmp(tmp,"pos ",4)==0) { + emit gotPosition(tmp+4); + } +} + +void Network::addListener(const char* host, int port) +{ + struct hostent *hostinfo; + struct sockaddr_in name; + + memset(&name, 0, sizeof(struct sockaddr_in)); + name.sin_family = AF_INET; + name.sin_port = htons (port); + hostinfo = gethostbyname (host); + if (hostinfo == NULL) { + printf ("Error in addListener: Unknown host %s.\n", host); + return; + } + name.sin_addr = *(struct in_addr *) hostinfo->h_addr; + + Listener *l = new Listener(host,port,name); +// printf("Added Listener %s, 0x%x:%d\n", +// host, ntohl(name.sin_addr.s_addr), ntohs(name.sin_port)); + listeners.append(l); + + char tmp[50]; + int len = sprintf(tmp, "reg %d", ntohs(mySin.sin_port)); + + if (!sendString( name, tmp, len)) + listeners.remove(l); +} + +void Network::broadcast(const char* pos) +{ + char tmp[1024]; + int len = sprintf(tmp,"pos %s", pos); + + for(Listener* l=listeners.first(); l!=0; l=listeners.next()) + if (l->reachable) + l->reachable = sendString(l->sin, tmp, len); +} + +bool Network::sendString(struct sockaddr_in sin, char* str, int len) +{ + int s = ::socket (PF_INET, SOCK_STREAM, 0); + if (s<0) { + printf("Error in sendString/socket ??\n"); + return false; + } + if (::connect (s, (struct sockaddr *)&sin, sizeof (sin)) <0) { + printf("Error in sendString/connect to socket 0x%x:%d\n", + ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port) ); + return false; + } + write(s, str, len); + close(s); + // printf("Send '%s' to 0x%x:%d\n", str, + // ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port) ); + return true; +} + +#include "Network.moc" diff --git a/kenolaba/Network.h b/kenolaba/Network.h new file mode 100644 index 00000000..d5251cc6 --- /dev/null +++ b/kenolaba/Network.h @@ -0,0 +1,60 @@ +/* + * Simple Network Support + * Install a listening socket; receive positions on incoming + * connections (incoming positions are treated as if pasted in) + */ + +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include +#include + +#include +#include +#include + +class Listener { + public: + Listener(const char*,int,struct sockaddr_in,bool=true); + + char host[100]; + int port; + struct sockaddr_in sin; + bool reachable; +}; + + +class Network: public QObject +{ + Q_OBJECT + + public: + enum { defaultPort = 23412 }; + + /* install listening TCP socket on port */ + Network(int port = defaultPort); + ~Network(); + + bool isOK() { return (fd>=0); } + void addListener(const char* host, int port); + void broadcast(const char* pos); + + signals: + void gotPosition(const char* pos); + + private slots: + void gotConnection(); + + private: + bool sendString(struct sockaddr_in sin, char* str, int len); + + QPtrList listeners; + struct sockaddr_in mySin; + int fd, myPort; + QSocketNotifier *sn; +}; + +#endif + + diff --git a/kenolaba/README b/kenolaba/README new file mode 100644 index 00000000..6d69911b --- /dev/null +++ b/kenolaba/README @@ -0,0 +1,23 @@ +Another kool game for KDE :) + +Kenolaba is a game like Abalone. You play against the computer on a +board. For rules look at the HTML manual. + +INSTALLATION: +If you find this directory (and README) in a kde package bundled with +other applications, there is nothing to do. By installing the package +Kenolaba should be installed too. + +Otherwise get the kdeapps package and unpack it. +Make the kenolaba/ directory (with this README) a subdirectory of +kdeapps/ and add "kenolaba" to the SUBDIRS variable in the toplevel +Makefile.in of the kdeapps package. By installing the package kdeapps now +Kenolaba should be installed too. + +Have fun... +...and remember: Your computer already is a real thinking machine ! + +Greetings, + +Josef Weidendorfer + diff --git a/kenolaba/Spy.cpp b/kenolaba/Spy.cpp new file mode 100644 index 00000000..07f17702 --- /dev/null +++ b/kenolaba/Spy.cpp @@ -0,0 +1,155 @@ +/* Class Spion + * + * Josef Weidendorfer, 10/97 + */ + + +#include +#include +#include + +#include +#include + +#include "BoardWidget.h" +#include "Spy.h" + +Spy::Spy(Board& b) + :board(b) +{ + int i; + + top = new QVBoxLayout(this, 5); + + QLabel *l = new QLabel(this); + l->setText( i18n("Actual examined position:") ); + l->setFixedHeight( l->sizeHint().height() ); + l->setAlignment( AlignVCenter | AlignLeft ); + top->addWidget( l ); + + QHBoxLayout* b1 = new QHBoxLayout(); + top->addLayout( b1, 10 ); + + for(i=0;iaddLayout( b2 ); + + actBoard[i] = new BoardWidget(board,this); + actLabel[i] = new QLabel(this); + actLabel[i]->setText("---"); + // actLabel[i]->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + actLabel[i]->setAlignment( AlignHCenter | AlignVCenter); + actLabel[i]->setFixedHeight( actLabel[i]->sizeHint().height() ); + + b2->addWidget( actBoard[i] ); + b2->addWidget( actLabel[i] ); + connect( actBoard[i], SIGNAL(mousePressed()), this, SLOT(nextStep()) ); + } + + l = new QLabel(this); + l->setText( i18n("Best move so far:") ); + l->setFixedHeight( l->sizeHint().height() ); + l->setAlignment( AlignVCenter | AlignLeft ); + top->addWidget( l ); + + b1 = new QHBoxLayout(); + top->addLayout( b1, 10 ); + + for(i=0;iaddLayout( b2 ); + + bestBoard[i] = new BoardWidget(board,this); + bestLabel[i] = new QLabel(this); + bestLabel[i]->setText("---"); + // bestLabel[i]->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + bestLabel[i]->setAlignment( AlignHCenter | AlignVCenter); + bestLabel[i]->setFixedHeight( bestLabel[i]->sizeHint().height() ); + + b2->addWidget( bestBoard[i] ); + b2->addWidget( bestLabel[i] ); + connect( bestBoard[i], SIGNAL(mousePressed()), this, SLOT(nextStep()) ); + } + + connect( &board, SIGNAL(update(int,int,Move&,bool)), + this, SLOT(update(int,int,Move&,bool)) ); + connect( &board, SIGNAL(updateBest(int,int,Move&,bool)), + this, SLOT(updateBest(int,int,Move&,bool)) ); + top->activate(); + setCaption(i18n("Spy")); + // KWM::setDecoration(winId(), 2); + resize(500,300); +} + +void Spy::keyPressEvent(QKeyEvent *) +{ + nextStep(); +} + +void Spy::nextStep() +{ + next = true; +} + +void Spy::clearActBoards() +{ + for(int i=0;iclearPosition(); + actBoard[i]->draw(); + actLabel[i]->setText("---"); + } +} + +void Spy::update(int depth, int value, Move& m, bool wait) +{ + next = false; + + if (depth>BoardCount-1) return; + actBoard[depth]->showMove(m,3); + // actBoard[depth]->showMove(m,0,false); + + if (!wait) { + actLabel[depth]->setText("---"); + return; + } + + if (depthupdatePosition(true); + actLabel[depth+1]->setNum(value); + board.takeBack(); + + if (depthclearPosition(); + actBoard[depth+2]->draw(); + } + } + + while(!next) + kapp->processEvents(); +} + +void Spy::updateBest(int depth, int value, Move& m, bool cutoff) +{ + if (depth>BoardCount-1) return; + bestBoard[depth]->showMove(m,3); + // board.showMove(m,0); + + if (depthupdatePosition(true); + + QString tmp; + tmp.setNum(value); + if (cutoff) tmp += " (CutOff)"; + bestLabel[depth+1]->setText(tmp); + board.takeBack(); + } +} + + + + + + +#include "Spy.moc" diff --git a/kenolaba/Spy.h b/kenolaba/Spy.h new file mode 100644 index 00000000..f69d99d3 --- /dev/null +++ b/kenolaba/Spy.h @@ -0,0 +1,46 @@ +/* Class Spion + * + * Josef Weidendorfer, 10/97 + */ + +#ifndef _SPY_H_ +#define _SPY_H_ + + +#include +#include "Board.h" + + +class BoardWidget; +class QLabel; + +class Spy: public QWidget +{ + Q_OBJECT + +public: + Spy(Board&); + ~Spy() {} + + enum { BoardCount = 5 }; + + void clearActBoards(); + + void keyPressEvent(QKeyEvent *e); + +public slots: + void update(int,int,Move&,bool); + void updateBest(int,int,Move&,bool); + void nextStep(); + +private: + bool next; + Board &board; + QBoxLayout *top; + BoardWidget *actBoard[BoardCount], *bestBoard[BoardCount]; + QLabel *actLabel[BoardCount], *bestLabel[BoardCount]; +}; + + + +#endif /* _SPION_H_ */ diff --git a/kenolaba/TODO b/kenolaba/TODO new file mode 100644 index 00000000..baad7913 --- /dev/null +++ b/kenolaba/TODO @@ -0,0 +1,8 @@ +TODO for Abalone > 1.05b + +* "Back" in Network mode +* Computer Character Editor (=Rating values) +* Search Inspector +* Computer playing in own process/thread +* 3 player mode +* OpenGL 3D board diff --git a/kenolaba/bitmaps/Arrow1 b/kenolaba/bitmaps/Arrow1 new file mode 100644 index 00000000..45c2ce41 --- /dev/null +++ b/kenolaba/bitmaps/Arrow1 @@ -0,0 +1,8 @@ +#define Arrow1_width 16 +#define Arrow1_height 16 +#define Arrow1_x_hot 7 +#define Arrow1_y_hot 7 +static unsigned char Arrow1_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x03, 0x00, 0x0f, + 0xfc, 0x3f, 0xfe, 0x7f, 0xfc, 0x3f, 0x00, 0x0f, 0x80, 0x03, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow1Mask b/kenolaba/bitmaps/Arrow1Mask new file mode 100644 index 00000000..2e50b48d --- /dev/null +++ b/kenolaba/bitmaps/Arrow1Mask @@ -0,0 +1,6 @@ +#define Arrow1Mask_width 16 +#define Arrow1Mask_height 16 +static unsigned char Arrow1Mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x03, 0xc0, 0x0f, 0xfc, 0x3f, + 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xfc, 0x3f, 0xc0, 0x0f, 0xc0, 0x03, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow2 b/kenolaba/bitmaps/Arrow2 new file mode 100644 index 00000000..47487a89 --- /dev/null +++ b/kenolaba/bitmaps/Arrow2 @@ -0,0 +1,8 @@ +#define Arrow2_width 16 +#define Arrow2_height 16 +#define Arrow2_x_hot 7 +#define Arrow2_y_hot 7 +static unsigned char Arrow2_bits[] = { + 0x00, 0x00, 0x10, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf0, 0x00, 0xf0, 0x08, + 0xe0, 0x0d, 0xc0, 0x0f, 0xc0, 0x0f, 0xf0, 0x0f, 0xe0, 0x0f, 0x80, 0x0f, + 0x00, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow2Mask b/kenolaba/bitmaps/Arrow2Mask new file mode 100644 index 00000000..121295e6 --- /dev/null +++ b/kenolaba/bitmaps/Arrow2Mask @@ -0,0 +1,6 @@ +#define Arrow2Mask_width 16 +#define Arrow2Mask_height 16 +static unsigned char Arrow2Mask_bits[] = { + 0x10, 0x00, 0x38, 0x00, 0x7c, 0x00, 0xfc, 0x00, 0xf8, 0x09, 0xf8, 0x1d, + 0xf0, 0x1f, 0xe0, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xe0, 0x1f, + 0x80, 0x1f, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow3 b/kenolaba/bitmaps/Arrow3 new file mode 100644 index 00000000..b511a017 --- /dev/null +++ b/kenolaba/bitmaps/Arrow3 @@ -0,0 +1,8 @@ +#define Arrow3_width 16 +#define Arrow3_height 16 +#define Arrow3_x_hot 7 +#define Arrow3_y_hot 7 +static unsigned char Arrow3_bits[] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x0f, 0x80, 0x07, 0x88, 0x07, + 0xd8, 0x03, 0xf8, 0x01, 0xf8, 0x01, 0xf8, 0x07, 0xf8, 0x03, 0xf8, 0x00, + 0x38, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow3Mask b/kenolaba/bitmaps/Arrow3Mask new file mode 100644 index 00000000..f4af9ccb --- /dev/null +++ b/kenolaba/bitmaps/Arrow3Mask @@ -0,0 +1,6 @@ +#define Arrow3Mask_width 16 +#define Arrow3Mask_height 16 +static unsigned char Arrow3Mask_bits[] = { + 0x00, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x80, 0x1f, 0xc8, 0x0f, 0xdc, 0x0f, + 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x07, 0xfc, 0x0f, 0xfc, 0x07, 0xfc, 0x03, + 0xfc, 0x00, 0x3c, 0x00, 0x0c, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow4 b/kenolaba/bitmaps/Arrow4 new file mode 100644 index 00000000..dfcdbd82 --- /dev/null +++ b/kenolaba/bitmaps/Arrow4 @@ -0,0 +1,8 @@ +#define Arrow4_width 16 +#define Arrow4_height 16 +#define Arrow4_x_hot 8 +#define Arrow4_y_hot 7 +static unsigned char Arrow4_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x01, 0xf0, 0x00, + 0xfc, 0x3f, 0xfe, 0x7f, 0xfc, 0x3f, 0xf0, 0x00, 0xc0, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow4Mask b/kenolaba/bitmaps/Arrow4Mask new file mode 100644 index 00000000..6c498fb5 --- /dev/null +++ b/kenolaba/bitmaps/Arrow4Mask @@ -0,0 +1,6 @@ +#define Arrow4Mask_width 16 +#define Arrow4Mask_height 16 +static unsigned char Arrow4Mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x03, 0xf0, 0x03, 0xfc, 0x3f, + 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xfc, 0x3f, 0xf0, 0x03, 0xc0, 0x03, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow5 b/kenolaba/bitmaps/Arrow5 new file mode 100644 index 00000000..72b93adc --- /dev/null +++ b/kenolaba/bitmaps/Arrow5 @@ -0,0 +1,8 @@ +#define Arrow5_width 16 +#define Arrow5_height 16 +#define Arrow5_x_hot 7 +#define Arrow5_y_hot 7 +static unsigned char Arrow5_bits[] = { + 0x00, 0x00, 0x08, 0x00, 0x38, 0x00, 0xf8, 0x00, 0xf8, 0x03, 0xf8, 0x07, + 0xf8, 0x01, 0xf8, 0x01, 0xd8, 0x03, 0x88, 0x07, 0x80, 0x07, 0x00, 0x0f, + 0x00, 0x0e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow5Mask b/kenolaba/bitmaps/Arrow5Mask new file mode 100644 index 00000000..da77ea00 --- /dev/null +++ b/kenolaba/bitmaps/Arrow5Mask @@ -0,0 +1,6 @@ +#define Arrow5Mask_width 16 +#define Arrow5Mask_height 16 +static unsigned char Arrow5Mask_bits[] = { + 0x0c, 0x00, 0x3c, 0x00, 0xfc, 0x00, 0xfc, 0x03, 0xfc, 0x07, 0xfc, 0x0f, + 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x07, 0xdc, 0x0f, 0xc8, 0x0f, 0x80, 0x1f, + 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow6 b/kenolaba/bitmaps/Arrow6 new file mode 100644 index 00000000..159770b4 --- /dev/null +++ b/kenolaba/bitmaps/Arrow6 @@ -0,0 +1,8 @@ +#define Arrow6_width 16 +#define Arrow6_height 16 +#define Arrow6_x_hot 7 +#define Arrow6_y_hot 7 +static unsigned char Arrow6_bits[] = { + 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x80, 0x0f, 0xe0, 0x0f, 0xf0, 0x0f, + 0xc0, 0x0f, 0xc0, 0x0f, 0xe0, 0x0d, 0xf0, 0x08, 0xf0, 0x00, 0x78, 0x00, + 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Arrow6Mask b/kenolaba/bitmaps/Arrow6Mask new file mode 100644 index 00000000..453ffde2 --- /dev/null +++ b/kenolaba/bitmaps/Arrow6Mask @@ -0,0 +1,6 @@ +#define Arrow6Mask_width 16 +#define Arrow6Mask_height 16 +static unsigned char Arrow6Mask_bits[] = { + 0x00, 0x18, 0x00, 0x1e, 0x80, 0x1f, 0xe0, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, + 0xf0, 0x1f, 0xe0, 0x1f, 0xf0, 0x1f, 0xf8, 0x1d, 0xf8, 0x09, 0xfc, 0x00, + 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00}; diff --git a/kenolaba/bitmaps/Makefile.am b/kenolaba/bitmaps/Makefile.am new file mode 100644 index 00000000..d25cc3b2 --- /dev/null +++ b/kenolaba/bitmaps/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = Arrow1 Arrow1Mask Arrow2 Arrow2Mask Arrow3 Arrow3Mask Arrow4 Arrow4Mask Arrow5 Arrow5Mask Arrow6 Arrow6Mask diff --git a/kenolaba/hi128-app-kenolaba.png b/kenolaba/hi128-app-kenolaba.png new file mode 100644 index 00000000..d645ff30 Binary files /dev/null and b/kenolaba/hi128-app-kenolaba.png differ diff --git a/kenolaba/hi16-app-kenolaba.png b/kenolaba/hi16-app-kenolaba.png new file mode 100644 index 00000000..44974a0f Binary files /dev/null and b/kenolaba/hi16-app-kenolaba.png differ diff --git a/kenolaba/hi22-app-kenolaba.png b/kenolaba/hi22-app-kenolaba.png new file mode 100644 index 00000000..d5b649f4 Binary files /dev/null and b/kenolaba/hi22-app-kenolaba.png differ diff --git a/kenolaba/hi32-app-kenolaba.png b/kenolaba/hi32-app-kenolaba.png new file mode 100644 index 00000000..9620d54b Binary files /dev/null and b/kenolaba/hi32-app-kenolaba.png differ diff --git a/kenolaba/hi48-app-kenolaba.png b/kenolaba/hi48-app-kenolaba.png new file mode 100644 index 00000000..2952e03e Binary files /dev/null and b/kenolaba/hi48-app-kenolaba.png differ diff --git a/kenolaba/hi64-app-kenolaba.png b/kenolaba/hi64-app-kenolaba.png new file mode 100644 index 00000000..9e5aa438 Binary files /dev/null and b/kenolaba/hi64-app-kenolaba.png differ diff --git a/kenolaba/kenolaba.cpp b/kenolaba/kenolaba.cpp new file mode 100644 index 00000000..e59aa9d7 --- /dev/null +++ b/kenolaba/kenolaba.cpp @@ -0,0 +1,71 @@ +/* Start point */ + +#include + +#include +#include +#include +#include + +#include + +#include "version.h" +#include "AbTop.h" + + +static const char description[] = + I18N_NOOP("Board game inspired by Abalone"); + +static KCmdLineOptions options[] = +{ + { "h", 0, 0}, + { "host ", I18N_NOOP("Use 'host' for network game"), 0 }, + { "p", 0, 0}, + { "port ", I18N_NOOP("Use 'port' for network game"), 0 }, + KCmdLineLastOption +}; + +AbTop *create(KCmdLineArgs *args) +{ + AbTop* top = new AbTop; + if (args->isSet("port")) + top->netPort( args->getOption("port").toInt() ); + if (args->isSet("host")) + top->netHost( args->getOption("host").data() ); + top->readConfig(); + return top; +} + +int main(int argc, char *argv[]) +{ + KAboutData aboutData( "kenolaba", I18N_NOOP("Kenolaba"), + KENOLABA_VERSION, description, KAboutData::License_GPL, + "(c) 1997-2000, Josef Weidendorfer"); + aboutData.addAuthor("Josef Weidendorfer",0, "Josef.Weidendorfer@gmx.de"); + aboutData.addAuthor("Robert Williams"); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. + + KApplication app; + KGlobal::locale()->insertCatalogue("libkdegames"); + + /* command line handling */ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + /* session management */ + if ( app.isRestored() ) { + uint n = 1; + while ( KMainWindow::canBeRestored(n) ) { + AbTop *top = create(args); + top->restore(n); + n++; + } + } else { + AbTop *top = create(args); + app.setMainWidget(top); + top->show(); + } + args->clear(); + return app.exec(); +} + diff --git a/kenolaba/kenolaba.desktop b/kenolaba/kenolaba.desktop new file mode 100644 index 00000000..add3fdda --- /dev/null +++ b/kenolaba/kenolaba.desktop @@ -0,0 +1,64 @@ +[Desktop Entry] +Name=Kenolaba +Name[ar]=لعبة Kenolaba +Name[be]=Абалон +Name[bn]=কেনোলাবা +Name[hi]=के-नोलाबा +Name[ne]=केनोलाबा +Name[pa]=ਕੀਨੋਲਾਬਾ +Name[ta]=கெனோப்ளா +Name[tg]=Кенолаба +Name[zh_TW]=Kenolaba 互推 +Name[zu]=I-Kenolaba +Icon=kenolaba +Type=Application +Exec=kenolaba %i %m -caption "%c" +DocPath=kenolaba/index.html +GenericName=Abalone-like Board Game +GenericName[be]=Настольная гульня тыпу Абалон +GenericName[bg]=Логическа игра +GenericName[bn]=অ্যাবালন-জাতীয় ছকভিত্তিক খেলা +GenericName[br]=Ur c'hoari taolenn a seurt gant Abalone +GenericName[bs]=Igra nalik na Abalone +GenericName[ca]=Jocs de taula similar a l'Abalone +GenericName[cs]=Deskové hry podobné Abalone +GenericName[cy]=Gêm Fwrdd sy'n debyg i Abalone +GenericName[da]=Abalone-lignende brætspil +GenericName[de]=Abalone-ähnliches Brettspiel +GenericName[el]=Επιτραπέζιο παιχνίδι παρόμοιο με το Abalone +GenericName[eo]=Abalone-simila bretludo +GenericName[es]=Juegos de tablero similar a Abalone +GenericName[et]=Abalone moodi lauamäng +GenericName[eu]=Abalone bezalako mahai-jokoa +GenericName[fa]=بازی Abalone-like Board +GenericName[fi]=Abalone-tyylinen lautapeli +GenericName[fr]=Jeu de plateau dans le style d'Abalone +GenericName[he]=חיקוי Abalon, משחק לוח +GenericName[hr]=Igra na ploči poput Abalonea +GenericName[hu]=Abalone-szerű táblás +GenericName[is]=Leikur sem líkist Abalone +GenericName[it]=Gioco da tavolo simile ad Abalone +GenericName[ja]=Abalone のようなボードゲーム +GenericName[km]=ល្បែង​ក្តារ​ដូច Abalone +GenericName[lv]=Abalone līdzīga galda spēle +GenericName[mk]=Игра на табла слична на Abalone +GenericName[nb]=Abalone-lignende brettspill +GenericName[nds]=Abalone-liek Brettspeel +GenericName[ne]=एबालोन जस्तै बोर्ड खेल +GenericName[nl]=Abalone-achtig bordspel +GenericName[nn]=Abalone-liknande brettspel +GenericName[pl]=Gra planszowa typu Abalone +GenericName[pt]=Jogo de Tabuleiro tipo Abalone +GenericName[pt_BR]=Jogo parecido com Abalone +GenericName[ru]=Абалоне +GenericName[se]=Abalone-lágan duolbbášspeallu +GenericName[sk]=Stolová hra typu Abalone +GenericName[sl]=Ploščadna igra, podobna Abalone +GenericName[sr]=Игра на табли налик на Abalone +GenericName[sr@Latn]=Igra na tabli nalik na Abalone +GenericName[sv]=Abalone-liknande brädspel +GenericName[uk]=Гра на дошці подібна до гри Abalone +GenericName[zh_TW]=類似 Abalone 的棋盤遊戲 +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Game;BoardGame; diff --git a/kenolaba/kenolabaui.rc b/kenolaba/kenolabaui.rc new file mode 100644 index 00000000..cf8c1626 --- /dev/null +++ b/kenolaba/kenolabaui.rc @@ -0,0 +1,53 @@ + + + + + &Game + + + &Move + + + + + &Edit + + + + + + &Settings + + + + + + + + + &Settings + + + + + + + + + + + + + + Main Toolbar + + + + + + + + + + + diff --git a/kenolaba/toolbar/Makefile.am b/kenolaba/toolbar/Makefile.am new file mode 100644 index 00000000..5fdccbb7 --- /dev/null +++ b/kenolaba/toolbar/Makefile.am @@ -0,0 +1,7 @@ +tb_DATA = new.xpm stop.xpm edit.xpm hint.xpm undo.xpm \ + redball.xpm yellowball.xpm noball.xpm warning.xpm ok.xpm \ + spy0.xpm spy1.xpm spy2.xpm spy3.xpm network.xpm +tbdir = $(kde_datadir)/kenolaba/pics + +EXTRA_DIST = $(tb_DATA) + diff --git a/kenolaba/toolbar/edit.xpm b/kenolaba/toolbar/edit.xpm new file mode 100644 index 00000000..20412f2e --- /dev/null +++ b/kenolaba/toolbar/edit.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char*ab[]={ +"22 22 13 1", +"j c #ffa858", +"d c #c0c0c0", +"c c #d6cdbb", +"g c #ffc0c0", +"h c #c05800", +"# c #000000", +"k c #ffdca8", +". c None", +"e c #c00000", +"b c #a0a0a4", +"a c #dcdcdc", +"i c #ffffff", +"f c #ff0000", +"......................", +"................#aa...", +"...............#aa#b..", +".............cc#aa#bc.", +"......#########aa#bb..", +".....#dddddddd#aa#bc..", +".....#dededed#aa#bb...", +"....#ddfgfgfg#aa#bcc..", +"....#ddddddd####bb.cc.", +"...#dddddde#aa##bc....", +"...#dddhdd#iia##b.....", +"..#ddddjkd#iab##b#c...", +"..#dddddd#iab##bb#c...", +"..c#ddhdd#ab##bb#c....", +"...#ddjk#ib##bbi#c....", +"...c#dd####bbbi#c.....", +"....#ddhbbbbddi#c.....", +"....c#djkjkjki#c......", +".....#iiiiiiii#c......", +".....c########c.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/help.xpm b/kenolaba/toolbar/help.xpm new file mode 100644 index 00000000..71348f4d --- /dev/null +++ b/kenolaba/toolbar/help.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * help_xpm[] = { +"22 22 4 1", +" c None", +". c #000000", +"X c #000086", +"o c #868286", +" ", +" ", +" ", +" ", +" . XXXXXo ", +" .. XX oXXo ", +" ... XXo XXX ", +" .... XXo XXX ", +" ..... oXX oXXo ", +" ...... XXo ", +" ....... XX ", +" ........ XXo ", +" ..... XXo ", +" .. .. ", +" . .. XXX ", +" .. XXX ", +" .. ", +" .. ", +" ", +" ", +" ", +" "}; diff --git a/kenolaba/toolbar/hint.xpm b/kenolaba/toolbar/hint.xpm new file mode 100644 index 00000000..399c7c07 --- /dev/null +++ b/kenolaba/toolbar/hint.xpm @@ -0,0 +1,31 @@ +/* XPM */ +static char * hint_xpm[] = { +"22 22 6 1", +" c None", +". c #000086", +"X c #868286", +"o c black", +"O c red", +"+ c yellow", +" ", +" ", +" .....X ", +" .. X..X ", +" ..X ... ", +" ..X ... ", +" X.. X..X ", +" ..X ", +" .. ", +" oooo ..X ", +" oooooooo ..X ", +" ooOOOOoooo ", +" oOOo oooo ... ", +" oOOo oo oooo... ", +" oOo oooo o+o ", +" oOo oooo o+o ", +" oooo oo o++o ", +" oooo o++o ", +" ooooo+++oo ", +" oooooooo ", +" oooo ", +" "}; diff --git a/kenolaba/toolbar/network.xpm b/kenolaba/toolbar/network.xpm new file mode 100644 index 00000000..0878c2bb --- /dev/null +++ b/kenolaba/toolbar/network.xpm @@ -0,0 +1,35 @@ +/* XPM */ +static char*net[]={ +"22 22 10 1", +". c None", +"b c #808080", +"f c #a0a0a0", +"a c #c3c3c3", +"# c #000000", +"e c #0000c0", +"h c #ffff00", +"d c #585858", +"c c #ffffff", +"g c #ff0000", +"......................", +"......................", +".....#######..........", +"...##aaaabbb##........", +"...#ccaaaaabbb##......", +"...#ddccaaaaabbb#.....", +"...#eeddccaaabbbb#....", +"...#eeeeddcaadbbb#....", +"...#eeeeeecbbdbbb#....", +"...#eeeeeecbbdbbb#....", +"...#aeeeeecbbdbbb#....", +"....#aaeeecbbdbb#.....", +"....###aaecbb###......", +"....#aa##aa##dd#......", +".....##aa##dd##.......", +"..###..##ad##..d##d...", +".##aa##..##.#.##aa##..", +".#aaaaa##..#.#fgagaf#.", +"..##daaaa##..#aaaaaa##", +"....##daa#...#ahaaha#.", +"......###.....##ah##..", +"...............d##d..."}; diff --git a/kenolaba/toolbar/new.xpm b/kenolaba/toolbar/new.xpm new file mode 100644 index 00000000..e5aa03fc --- /dev/null +++ b/kenolaba/toolbar/new.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char*ab[]={ +"22 22 11 1", +"h c #ffa858", +"d c #d6cdbb", +"b c #c0c0c0", +"f c #ffc0c0", +"g c #c05800", +"# c #000000", +"i c #ffdca8", +". c None", +"c c #c00000", +"a c #ffffff", +"e c #ff0000", +"......................", +"................#a....", +"................#a....", +".............#a.#a.#a.", +"......#######.#a#a#a..", +".....#bbbbbbbb.#.#....", +".....#bcbcbcba.d......", +"....#bbefefefb#a#a#a..", +"....#bbbbbbbb#a.#a.#a.", +"...#bbbbbbcbcbb.#a....", +"...#bbbgbbefefba#a....", +"..#bbbbhibbbbbbba#d...", +"..#bbbbbbbbbbcbba#d...", +"..d#bbgbbbgbbefa#d....", +"...#bbhibbhibbba#d....", +"...d#bbbbbbbbba#d.....", +"....#bbgbgbgbba#d.....", +"....d#bhihihia#d......", +".....#aaaaaaaa#d......", +".....d########d.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/noball.xpm b/kenolaba/toolbar/noball.xpm new file mode 100644 index 00000000..14673de6 --- /dev/null +++ b/kenolaba/toolbar/noball.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char*noball[]={ +"16 16 3 1", +"# c #808080", +". c None", +"a c #ffffff", +".....#####......", +"...#########....", +"..###aaaaa###...", +".###a.....a###a.", +".##a........##a.", +"##a..........##a", +"##a..........##a", +"##a..........##a", +"##a..........##a", +"##a..........##a", +".##a........##a.", +".###.......###a.", +"..###.....###a..", +"...#########a...", +"...aa#####aa....", +".....aaaaa......"}; diff --git a/kenolaba/toolbar/ok.xpm b/kenolaba/toolbar/ok.xpm new file mode 100644 index 00000000..290d4657 --- /dev/null +++ b/kenolaba/toolbar/ok.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char*ok[]={ +"16 16 6 1", +"d c #00ff00", +"b c #004000", +"# c #c0c0ff", +"a c #000000", +". c None", +"c c #ffffff", +".....#####......", +"...#######......", +"..#######.abbc..", +".#######.abbbc..", +".######.abbdbc..", +"#######.abdbc.#.", +"######.abdbc.##.", +"##.###.abbc.###.", +"#.ac#.abdc.####.", +"#abc..abbc.####.", +"..bbcabbc.####..", +".#.bcbbc.#####..", +"...abbc.#####...", +"....bbc#####....", +"....ac.###......", +"................"}; diff --git a/kenolaba/toolbar/redball.xpm b/kenolaba/toolbar/redball.xpm new file mode 100644 index 00000000..24450be5 --- /dev/null +++ b/kenolaba/toolbar/redball.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char*redball[]={ +"16 16 6 1", +"# c #000000", +"a c #400000", +"b c #800000", +". c None", +"d c #ffffff", +"c c #ff0000", +".....#####......", +"...##aaaaa##....", +"..##aabbbbb##...", +".##aabbbbbbb##..", +".#aabbbbbbbbb#..", +"#aabbbbbbbbbbb#.", +"#aabbbbbcccbbb#.", +"#aabbbbcccccbb#.", +"#aabbbcccccccb#.", +"#aabbbccccdccb#.", +".#aabbcccdddc#..", +".##aabbcccdc##..", +"..##aabbccc##...", +"...##aaaaa##....", +".....#####......", +"................"}; diff --git a/kenolaba/toolbar/spy0.xpm b/kenolaba/toolbar/spy0.xpm new file mode 100644 index 00000000..a6cbb1c5 --- /dev/null +++ b/kenolaba/toolbar/spy0.xpm @@ -0,0 +1,39 @@ +/* XPM */ +static char*spy0[]={ +"22 22 14 1", +"a c #808080", +"j c #ffa858", +"l c #d6cdbb", +"c c #c0c0c0", +"g c #ffc0c0", +"i c #c05800", +"# c #000000", +". c None", +"k c #ffdca8", +"d c #c00000", +"h c #585858", +"e c #dcdcdc", +"b c #ffffff", +"f c #ff0000", +"......................", +"...........####.......", +"..........#....#......", +".........#.aaaa.#.....", +"......####baaaa.#b....", +".....#ccc#baaaa.#b....", +".....#cdc#eaaaa.#b....", +"....#ccfgf#ebbe#b.....", +"....#cccccc#####h.....", +"...#ccccccdcdcc.hb....", +"...#ccciccfgfgc.#h....", +"..#ccccjkccccccc.hb...", +"..#ccccccccccdcc.#h...", +"..l#cciccciccfgb#.hb..", +"...#ccjkccjkcccb#..h..", +"...l#cccccccccb#l..h..", +"....#cciciciccb#l.....", +"....l#cjkjkjkb#l......", +".....#bbbbbbbb#l......", +".....l########l.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/spy1.xpm b/kenolaba/toolbar/spy1.xpm new file mode 100644 index 00000000..24baa2ba --- /dev/null +++ b/kenolaba/toolbar/spy1.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char*spy1[]={ +"22 22 13 1", +"i c #ffa858", +"k c #d6cdbb", +"e c #c0c0c0", +"g c #ffc0c0", +"h c #c05800", +"# c #000000", +". c None", +"j c #ffdca8", +"f c #c00000", +"d c #a0a0a4", +"a c #dcdcdc", +"b c #ffffff", +"c c #ff0000", +"......................", +"...........####.......", +"..........#abba#......", +".........#ac##ca#.....", +"......####bdccbb#b....", +".....#eee#bbccbb#b....", +".....#efe#acbbca#b....", +"....#eecgc#abba#bb....", +"....#eeeeee######b....", +"...#eeeeeefefee##bb...", +"...#eeeheecgcge###b...", +"..#eeeeijeeeeeee##b...", +"..#eeeeeeeeeefee###b..", +"..k#eeheeeheecgbb#....", +"...#eeijeeijeeebb.....", +"...k#eeeeeeeeeb#k.....", +"....#eeheheheeb#k.....", +"....k#eijijijb#k......", +".....#bbbbbbbb#k......", +".....k########k.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/spy2.xpm b/kenolaba/toolbar/spy2.xpm new file mode 100644 index 00000000..cd2cb150 --- /dev/null +++ b/kenolaba/toolbar/spy2.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static char*spy2[]={ +"22 22 15 1", +"j c #ffa858", +"g c #c3c3c3", +"l c #d6cdbb", +"e c #c0c0c0", +"m c #ffc0c0", +"i c #c05800", +"# c #000000", +". c None", +"h c #800000", +"k c #ffdca8", +"f c #c00000", +"d c #a0a0a4", +"a c #dcdcdc", +"b c #ffffff", +"c c #ff0000", +"......................", +"...........####.......", +".........##abba##.....", +".........#ac##ca#.....", +"......####bdccbb##....", +".....#ee#b#bccb#b#....", +".....#ef#gachhcab#....", +"....#eec#bhhhhhhb#....", +"....#eee##ehhhhb##....", +"...#eeeee#gggbgg#bb...", +"...#eeeie##bbbb###b...", +"..#eeeejkee#######bb..", +"..#eeeeeeeeeefee###b..", +"..l#eeieeeieecmbb#....", +"...#eejkeejkeeebb.....", +"...l#eeeeeeeeeb#l.....", +"....#eeieieieeb#l.....", +"....l#ejkjkjkb#l......", +".....#bbbbbbbb#l......", +".....l########l.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/spy3.xpm b/kenolaba/toolbar/spy3.xpm new file mode 100644 index 00000000..b19cbdcc --- /dev/null +++ b/kenolaba/toolbar/spy3.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char*spy3[]={ +"22 22 13 1", +"j c #ffa858", +"d c #c3c3c3", +"h c #d6cdbb", +"f c #c0c0c0", +"i c #c05800", +"# c #000000", +". c None", +"g c #800000", +"k c #ffdca8", +"e c #a0a0a4", +"a c #dcdcdc", +"b c #ffffff", +"c c #ff0000", +"...........####.......", +".........########.....", +"........###abba###....", +".......###ac##ca###...", +"......###dbeccbbd##...", +".....#f##b#cccc#b##...", +".....###ddacggcabd##..", +"....#f##dbggggggbd##..", +"....#f##d###gg###d##..", +"...#ff##dd#cccc#dd##..", +"...#ff###ddbccbdd##...", +"..#ffff###dddddd###...", +"..#ffffd####dd####....", +"..h#ffifd######b#.....", +"...#ffjkfdd######.....", +"...h#fffffffffb#h.....", +"....#ffifififfb#h.....", +"....h#fjkjkjkb#h......", +".....#bbbbbbbb#h......", +".....h########h.......", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/stop.xpm b/kenolaba/toolbar/stop.xpm new file mode 100644 index 00000000..c8e641c6 --- /dev/null +++ b/kenolaba/toolbar/stop.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char * ab_stop_xpm[] = { +"22 22 5 1", +" c none", +". c black", +"X c white", +"o c red", +"O c #820782078207", +" ", +" ", +" ", +" ....... ", +" ......... ", +" ..XXXXXX... ", +" ..X o o o ... ", +" ..X o o o o ... ", +" ..Xo o o o oO.. ", +" ..X o o o o O.. ", +" ..Xo o o o oO.. ", +" ..X o o o o O.. ", +" ..Xo o o o oO.. ", +" ... o o o o O.. ", +" ... o o o O.. ", +" ...OOOOOO.. ", +" ......... ", +" ....... ", +" ", +" ", +" ", +" "}; diff --git a/kenolaba/toolbar/undo.xpm b/kenolaba/toolbar/undo.xpm new file mode 100644 index 00000000..9b002026 --- /dev/null +++ b/kenolaba/toolbar/undo.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static char*undo[]={ +"22 22 2 1", +"# c #000080", +". c None", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................", +"..........######......", +".........########.....", +"........####....##....", +"........###...........", +".......###............", +".....#######..........", +"......#####...........", +".......###............", +"........#.............", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................"}; diff --git a/kenolaba/toolbar/warning.xpm b/kenolaba/toolbar/warning.xpm new file mode 100644 index 00000000..b2674f2a --- /dev/null +++ b/kenolaba/toolbar/warning.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char*warning[]={ +"16 16 7 1", +"e c #d6cdbb", +"# c #c0c0ff", +"a c #000000", +". c None", +"c c #400000", +"b c #ffffff", +"d c #ff0000", +"................", +"...##.aaab.#....", +"..##.accccb.#...", +".###.accdcb.##..", +".###.accdcb.##..", +"####..adcb.####.", +"#####.accb.####.", +"######.ab.#####.", +"######.ab.#####.", +"######.b.######.", +".######..#####..", +".#####.ab.####..", +"..###.adcb.##...", +"...###.cbe##....", +".....#.be#......", +"................"}; diff --git a/kenolaba/toolbar/yellowball.xpm b/kenolaba/toolbar/yellowball.xpm new file mode 100644 index 00000000..fc986c52 --- /dev/null +++ b/kenolaba/toolbar/yellowball.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char*yellowball[]={ +"16 16 6 1", +"b c #c0c000", +"a c #808000", +"# c #000000", +"c c #ffff00", +". c None", +"d c #ffffff", +".....#####......", +"...##aaaaa##....", +"..##aaaaaaa##...", +".##aaaabbbaa##..", +".#aaaabbbbbaa#..", +"#aaaabbbbbbbaa#.", +"#aaabbbbbbbbba#.", +"#aaabbbccccbba#.", +"#aaabbbcccccba#.", +"#aaaabbcccdcaa#.", +".#aaaabccddda#..", +".##aaaabccdc##..", +"..##aaaaaaa##...", +"...##aaaaa##....", +".....#####......", +"................"}; diff --git a/kenolaba/version.h b/kenolaba/version.h new file mode 100644 index 00000000..90e8ddd1 --- /dev/null +++ b/kenolaba/version.h @@ -0,0 +1 @@ +#define KENOLABA_VERSION "1.06b" -- cgit v1.2.1