summaryrefslogtreecommitdiffstats
path: root/kenolaba
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitc90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch)
tree6d8391395bce9eaea4ad78958617edb20c6a7573 /kenolaba
downloadtdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.tar.gz
tdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.zip
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
Diffstat (limited to 'kenolaba')
-rw-r--r--kenolaba/AbTop.cpp988
-rw-r--r--kenolaba/AbTop.h152
-rw-r--r--kenolaba/Ball.cpp492
-rw-r--r--kenolaba/Ball.h155
-rw-r--r--kenolaba/Board.cpp1493
-rw-r--r--kenolaba/Board.h198
-rw-r--r--kenolaba/BoardWidget.cpp1027
-rw-r--r--kenolaba/BoardWidget.h116
-rw-r--r--kenolaba/ChangeLog35
-rw-r--r--kenolaba/EvalDlg.ui1760
-rw-r--r--kenolaba/EvalDlgImpl.cpp299
-rw-r--r--kenolaba/EvalDlgImpl.h44
-rw-r--r--kenolaba/EvalScheme.cpp231
-rw-r--r--kenolaba/EvalScheme.h61
-rw-r--r--kenolaba/Makefile.am21
-rw-r--r--kenolaba/Move.cpp261
-rw-r--r--kenolaba/Move.h132
-rw-r--r--kenolaba/Network.cpp193
-rw-r--r--kenolaba/Network.h60
-rw-r--r--kenolaba/README23
-rw-r--r--kenolaba/Spy.cpp155
-rw-r--r--kenolaba/Spy.h46
-rw-r--r--kenolaba/TODO8
-rw-r--r--kenolaba/bitmaps/Arrow18
-rw-r--r--kenolaba/bitmaps/Arrow1Mask6
-rw-r--r--kenolaba/bitmaps/Arrow28
-rw-r--r--kenolaba/bitmaps/Arrow2Mask6
-rw-r--r--kenolaba/bitmaps/Arrow38
-rw-r--r--kenolaba/bitmaps/Arrow3Mask6
-rw-r--r--kenolaba/bitmaps/Arrow48
-rw-r--r--kenolaba/bitmaps/Arrow4Mask6
-rw-r--r--kenolaba/bitmaps/Arrow58
-rw-r--r--kenolaba/bitmaps/Arrow5Mask6
-rw-r--r--kenolaba/bitmaps/Arrow68
-rw-r--r--kenolaba/bitmaps/Arrow6Mask6
-rw-r--r--kenolaba/bitmaps/Makefile.am1
-rw-r--r--kenolaba/hi128-app-kenolaba.pngbin0 -> 15572 bytes
-rw-r--r--kenolaba/hi16-app-kenolaba.pngbin0 -> 879 bytes
-rw-r--r--kenolaba/hi22-app-kenolaba.pngbin0 -> 1369 bytes
-rw-r--r--kenolaba/hi32-app-kenolaba.pngbin0 -> 2388 bytes
-rw-r--r--kenolaba/hi48-app-kenolaba.pngbin0 -> 4346 bytes
-rw-r--r--kenolaba/hi64-app-kenolaba.pngbin0 -> 6254 bytes
-rw-r--r--kenolaba/kenolaba.cpp71
-rw-r--r--kenolaba/kenolaba.desktop64
-rw-r--r--kenolaba/kenolabaui.rc53
-rw-r--r--kenolaba/toolbar/Makefile.am7
-rw-r--r--kenolaba/toolbar/edit.xpm38
-rw-r--r--kenolaba/toolbar/help.xpm29
-rw-r--r--kenolaba/toolbar/hint.xpm31
-rw-r--r--kenolaba/toolbar/network.xpm35
-rw-r--r--kenolaba/toolbar/new.xpm36
-rw-r--r--kenolaba/toolbar/noball.xpm22
-rw-r--r--kenolaba/toolbar/ok.xpm25
-rw-r--r--kenolaba/toolbar/redball.xpm25
-rw-r--r--kenolaba/toolbar/spy0.xpm39
-rw-r--r--kenolaba/toolbar/spy1.xpm38
-rw-r--r--kenolaba/toolbar/spy2.xpm40
-rw-r--r--kenolaba/toolbar/spy3.xpm38
-rw-r--r--kenolaba/toolbar/stop.xpm30
-rw-r--r--kenolaba/toolbar/undo.xpm27
-rw-r--r--kenolaba/toolbar/warning.xpm26
-rw-r--r--kenolaba/toolbar/yellowball.xpm25
-rw-r--r--kenolaba/version.h1
63 files changed, 8735 insertions, 0 deletions
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 <qpopupmenu.h>
+#include <qtimer.h>
+#include <qclipboard.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdialogbase.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kstdaccel.h>
+#include <kglobal.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kstdgameaction.h>
+#include <kdebug.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+
+// #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; i<Nb_Levels; i++)
+ list.append( i18n(LEVEL[i].label) );
+ levelAction->setItems(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; i<Nb_IPlays; i++)
+ list.append( i18n(IPLAY[i].label) );
+ iplayAction->setItems(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<QPopupMenu*> (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; i<Nb_Levels; i++)
+ if ( entry==LEVEL[i].key ) setLevel(i);
+
+ entry = config->readEntry("Computer");
+ for (uint i=0; i<Nb_IPlays; i++)
+ if ( entry==IPLAY[i].key ) setIPlay(i);
+
+ showMoveLong = config->readBoolEntry("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 <stop search>, <hint>, <take back> 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) ? (vv<v) : (vv>v) );
+ }
+ 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 <m>
+ * If <update> 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 <kmainwindow.h>
+
+#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 <qtimer.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <math.h>
+#include <stdio.h>
+
+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 &pm;
+}
+
+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;y<sizeY;y++) {
+ yy = (2.*y-sizeY)/(sizeY-2) *zoom;
+ for(x=0;x<sizeX;x++) {
+ xx = (2.*x-sizeX)/(sizeX-2) *zoom;
+
+ /* Change only if inside the ball */
+ zz = 1 - (xx*xx + yy*yy);
+
+ if (zz>flip) 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_POSITION;i++)
+ positions[i] = 0;
+
+ for(i=0;i<MAX_ANIMATION;i++)
+ animations[i] = 0;
+
+ freq = _freq;
+ isRunning = false;
+ ballFraction = bFr;
+ realSize = -1;
+ timer = new QTimer(this);
+ connect( timer, SIGNAL(timeout()), SLOT(animate()) );
+}
+
+BallWidget::~BallWidget()
+{
+ if (timer !=0)
+ delete timer;
+}
+
+void BallWidget::createBlending(int no, int s, Ball* b1, Ball* b2)
+{
+ if (no<0 || no>= 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;i<MAX_POSITION;i++) {
+ p = positions.at(i);
+ if (p==0) continue;
+
+ 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( 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;i<MAX_POSITION;i++) {
+ p = positions.at(i);
+ if (p==0) continue;
+
+ if (p->actType == 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 <kapplication.h>
+
+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 <qpixmap.h>
+#include <qimage.h>
+#include <qcolor.h>
+#include <qwidget.h>
+#include <qptrlist.h>
+
+/* 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<Ball> 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<BallPosition*> positions;
+ QMemArray<BallAnimation*> 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 <stdio.h>
+
+#include <qdatetime.h>
+#include <qstrlist.h>
+
+#include <kconfig.h>
+#include <krandomsequence.h>
+
+#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;i<maxDepth;i++)
+ for(j=0;j<maxDepth;j++) {
+ move[i][j].type = Move::none;
+ }
+ actMaxDepth = (d<maxDepth) ? d:maxDepth-1;
+}
+
+void PrincipalVariation::update(int d, Move& m)
+{
+ int i;
+
+ if (d>actMaxDepth) 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<AllFields;i++)
+ field[i] = startBoard[i];
+ storedFirst = storedLast = 0;
+ color = startColor;
+ color1Count = color2Count = 14;
+ random.setSeed(0); // Initialize random sequence
+}
+
+void Board::clear()
+{
+ int i;
+
+ for(i=0;i<AllFields;i++)
+ field[i] = (startBoard[i] == out) ? out: free;
+ storedFirst = storedLast = 0;
+ color1Count = color2Count = 0;
+}
+
+/* generate moves starting at field <startField> */
+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<RealFields;f++) {
+ actField = order[f];
+ if ( field[actField] == color)
+ generateFieldMoves(actField, list);
+ }
+}
+
+
+
+void Board::playMove(const Move& m)
+{
+ int f, dir, dir2;
+ int opponent = (color == color1) ? color2:color1;
+
+ CHECK( isConsistent() );
+
+ if (++storedLast == MvsStored) storedLast = 0;
+
+ /* Buffer full -> 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;i<AllFields;i++) {
+ j=field[i];
+ if (j == color1) c1++;
+ if (j == color2) c2++;
+ if (j == color)
+ countFrom( i, color, tc, cc);
+ }
+
+ color1Count = c1;
+ color2Count = c2;
+ moveCount = tc.sum();
+
+ if (c1==0 && c2==0)
+ res = empty;
+ else if (c1>8 && 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;i<RealFields;i++) {
+ j=field[f=order[i]];
+ if (j == free) continue;
+ if (j == color) {
+ countFrom( f, j, tcColor, ccColor );
+ fieldValueSum -= fieldValue[i];
+ }
+ else {
+ countFrom( f, j, tcOpponent, ccOpponent );
+ fieldValueSum += fieldValue[i];
+ }
+ }
+
+ /* If color can't do any moves, opponent wins... */
+ if (tcColor.sum() == 0)
+ valueSum = 16000;
+ else {
+
+ for(int t=0;t < Move::typeCount;t++)
+ moveValueSum += _evalScheme->moveValue(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;i<RealFields;i++) {
+ j=field[order[i]];
+ if (j == color1) c1++;
+ if (j == color2) c2++;
+ }
+ return (color1Count == c1 && color2Count == c2);
+}
+
+void Board::changeEvaluation()
+{
+ int i,tmp;
+
+ /* innermost ring */
+ tmp=fieldValue[1];
+ for(i=1;i<6;i++)
+ fieldValue[i] = fieldValue[i+1];
+ fieldValue[6] = tmp;
+
+ tmp=fieldValue[7];
+ for(i=7;i<18;i++)
+ fieldValue[i] = fieldValue[i+1];
+ fieldValue[18] = tmp;
+
+ tmp=fieldValue[19];
+ for(i=19;i<36;i++)
+ fieldValue[i] = fieldValue[i+1];
+ fieldValue[36] = tmp;
+
+ /* the outermost ring */
+ tmp=fieldValue[37];
+ for(i=37;i<60;i++)
+ fieldValue[i] = fieldValue[i+1];
+ fieldValue[60] = tmp;
+}
+
+/*
+void Board::showHist()
+{
+ Move m1, m2;
+
+ printf("After playing ");
+ (m1=lastMove()).print();
+ print();
+ printf("TakeBack "); m1.print();
+ takeBack(); print();
+ printf("TakeBack ");
+ (m2=lastMove()).print();
+ takeBack(); print();
+ printf("Play "); m2.print();
+ playMove(m2); print();
+ printf("Play "); m1.print();
+ playMove(m1); print();
+ getchar();
+}
+*/
+
+
+
+/*
+ * We always try the maximize the board value
+ */
+int Board::search(int depth, int alpha, int beta)
+{
+ int actValue= -14999+depth, value;
+ Move m;
+ MoveList list;
+ bool depthPhase, doDepthSearch;
+
+ searchCalled++;
+
+ /* We make a depth search for the following move types... */
+ int maxType = (depth < maxDepth-1) ? Move::maxMoveType() :
+ (depth < maxDepth) ? Move::maxPushType() :
+ Move::maxOutType();
+
+ generateMoves(list);
+
+#ifdef MYTRACE
+
+ int oldRatedPositions;
+ int oldWonPositions;
+ int oldSearchCalled;
+ int oldMoveCount;
+ int oldNormalCount;
+ int oldPushCount;
+ int oldOutCount;
+ int oldCutoffCount;
+
+ spyDepth = depth;
+
+ moveCount += list.getLength();
+
+ /*
+ if (spyLevel>1) {
+ 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) {
+ c = state[index].latin1();
+ if (c !=' ') break;
+ }
+
+ if (c=='.') field[f++] = 0;
+ else if (c=='o' || c=='O') {
+ // printf(".. F %d: O\n", f);
+ field[f++] = 1;
+ color1Count++;
+ }
+ else if (c=='x' || c=='X') {
+ // printf(".. F %d: X\n", f);
+ field[f++] = 2;
+ color2Count++;
+ }
+ else {
+ if (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 <qobject.h>
+#include <krandomsequence.h>
+#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 <color>
+ * Returns a calculated value for actual position */
+ void generateMoves(MoveList& list);
+
+ /* Functions handling moves
+ * played moves can be taken back (<MvsStored> 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 <qbitmap.h>
+#include <qpainter.h>
+#include <qcursor.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#ifdef HAVE_KIR
+#include <kimgrender.h>
+#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; i<lineWidth; i++) {
+ p->drawLine( 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; i<lineWidth; i++) {
+ p->drawLine( 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 <board> member.
+ * If <updateGUI> is true, draw widget
+ */
+void BoardWidget::updatePosition(bool updateGUI)
+{
+ for(int i=0; i<Board::AllFields;i++)
+ field[i] = board[i];
+ color1Count = board.getColor1Count();
+ color2Count = board.getColor2Count();
+ color = board.actColor();
+ boardOK = true;
+
+ if (updateGUI) draw();
+}
+
+
+bool BoardWidget::setEditMode(bool mode)
+{
+ if (editMode == false && mode==true) {
+ editMode = true;
+ }
+ else if (editMode == true && mode == false) {
+ editMode = false;
+
+ for(int i=0; i<Board::AllFields;i++)
+ board.setField( i, field[i]);
+ board.setColor1Count(color1Count);
+ board.setColor2Count(color2Count);
+
+ }
+ return editMode;
+}
+
+
+void BoardWidget::clearPosition()
+{
+ for(int i=0; i<Board::AllFields;i++)
+ field[i] = 0;
+ color1Count = color2Count = 0;
+}
+
+void BoardWidget::showMove(const Move& mm, int step, bool updateGUI)
+{
+ int f, dir, dir2;
+ int opponentNew, colorNew;
+ bool afterMove;
+ static Move lastMove;
+ Move m;
+
+ if (boardOK) {
+ /* board ok means: board has the normal state
+ * (e.g. no highlighting)
+ */
+ if (step == 0)
+ return; /* nothing to be done */
+ }
+ boardOK = (step == 0) ? true:false;
+
+ if (step == 0)
+ m = lastMove;
+ else {
+ m = lastMove = mm;
+ }
+
+ if (color == Board::color1) {
+ colorNew = (step<2) ? Board::color1 :
+ (step>2) ? 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 <pos> is a valid start position for a allowed move
+ * If yes, set
+ * <startField>, <actMove> and <startType>
+ */
+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 <pos> is a valid end position for a move
+ * regarding <startPos>
+ * If yes, set <actMove>
+ */
+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; i<Board::AllFields;i++)
+ if (field[i] == Board::color1bright ||
+ field[i] == Board::color2bright) {
+ //printf(" Found %d\n",i);
+ field[i] = editColor;
+ }
+
+ for(i=0; i<Board::AllFields;i++)
+ board.setField( i, field[i]);
+
+ int vState = board.validState(); // set color1/2Count
+ color1Count = board.getColor1Count();
+ color2Count = board.getColor2Count();
+
+ draw();
+
+ emit edited(vState);
+ return;
+ }
+
+ if (!startValid) return;
+
+ int pos = positionOf( pEvent->x(), 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 <qwidget.h>
+#include <qpixmap.h>
+
+#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 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>EvalDlg</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>EvalDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>350</width>
+ <height>388</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Configure Evaluation</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>TabWidget2</cstring>
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>moves</cstring>
+ </property>
+ <attribute name="title">
+ <string>Moves</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout17</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="2">
+ <property name="name">
+ <cstring>Layout35</cstring>
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="5">
+ <property name="name">
+ <cstring>moveEval1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="4">
+ <property name="name">
+ <cstring>PixmapLabel3_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="5">
+ <property name="name">
+ <cstring>moveEval2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="5">
+ <property name="name">
+ <cstring>moveEval3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="4">
+ <property name="name">
+ <cstring>PixmapLabel3_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="3">
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_2_6</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_2_4</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>PixmapLabel3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>PixmapLabel1_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>TextLabel4_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Push Out</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer9_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>TextLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Push</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="2">
+ <property name="name">
+ <cstring>Layout37</cstring>
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <widget class="QLabel" row="2" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="6">
+ <property name="name">
+ <cstring>PixmapLabel3_3_2_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="6">
+ <property name="name">
+ <cstring>PixmapLabel3_3_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="7">
+ <property name="name">
+ <cstring>moveEval4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="7">
+ <property name="name">
+ <cstring>moveEval5</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="6">
+ <property name="name">
+ <cstring>PixmapLabel3_3_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="4">
+ <property name="name">
+ <cstring>PixmapLabel2_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>PixmapLabel1_3_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLineEdit" row="2" column="7">
+ <property name="name">
+ <cstring>moveEval6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_4</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_4_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="4">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_4_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>Spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="2" column="2">
+ <property name="name">
+ <cstring>Layout38</cstring>
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <widget class="QLabel" row="0" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2_4</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>PixmapLabel1_3_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="4">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLineEdit" row="0" column="7">
+ <property name="name">
+ <cstring>moveEval7</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_2_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="4">
+ <property name="name">
+ <cstring>PixmapLabel2_2_2_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="7">
+ <property name="name">
+ <cstring>moveEval9</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_4_2_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2_3_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="7">
+ <property name="name">
+ <cstring>moveEval8</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>PixmapLabel1_4_3_2</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="3">
+ <property name="name">
+ <cstring>PixmapLabel1_4_4</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>PixmapLabel1_2_5_2_4</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2_3_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="5">
+ <property name="name">
+ <cstring>PixmapLabel2_2_3</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Normal</string>
+ </property>
+ <property name="alignment">
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>For every move possible the given points are added to the Evaluation.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>position</cstring>
+ </property>
+ <attribute name="title">
+ <string>Position</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout63</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout62</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Inner ring 3:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>posEval3</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>posEval5</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>posEval2</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Outermost ring:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="3">
+ <property name="name">
+ <cstring>diffEval2</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="3">
+ <property name="name">
+ <cstring>diffEval3</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>posEval4</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Middle position:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="3">
+ <property name="name">
+ <cstring>diffEval5</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>posEval1</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Inner ring 2:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>TextLabel3_4</cstring>
+ </property>
+ <property name="text">
+ <string>+/-</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>TextLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>+/-</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="3">
+ <property name="name">
+ <cstring>diffEval4</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>+/-</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Innermost ring:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>+/-</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>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.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>inarow</cstring>
+ </property>
+ <attribute name="title">
+ <string>In-A-Row</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout64</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout42</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>rowEval3</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>rowEval2</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>rowEval5</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>rowEval4</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Three in-a-row:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Two in-a-row:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Four in-a-row:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_4</cstring>
+ </property>
+ <property name="text">
+ <string>Five in-a-row:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>For a number of balls In-a-Row, the given points are added to the evaluation</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>count</cstring>
+ </property>
+ <attribute name="title">
+ <string>Count</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout66</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout65</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>countEval2</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_4_2</cstring>
+ </property>
+ <property name="text">
+ <string>4 Balls more:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>countEval5</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>countEval4</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>3 Balls more:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_4_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>5 Balls more:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>countEval1</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>2 Balls more:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>countEval3</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>40</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>AlignLeft</set>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2_2_3_5</cstring>
+ </property>
+ <property name="text">
+ <string>1 Ball more:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel6_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>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.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer6_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Evaluation Schemes</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>evalList</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>evalSaveAs</cstring>
+ </property>
+ <property name="text">
+ <string>Save As...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>evalDelete</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Your evaluation scheme, defined in all other tabs of this dialog, can be stored here.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel9</cstring>
+ </property>
+ <property name="text">
+ <string>Evaluation of actual position:</string>
+ </property>
+ </widget>
+ <widget class="QLCDNumber">
+ <property name="name">
+ <cstring>actualEval</cstring>
+ </property>
+ <property name="segmentStyle">
+ <enum>Flat</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="409">789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade6523234530022630543251d2e253d856405bffcbc54105b19c856b630b630b43006711341dc343000ab0401651000b3f4a062ca30801003721241002208160309817525825950318810d8108818921058901662d8ecd583fb4a0fe13eb820c4f1e8fe4d448401d8ab204f23850b483431116a9352ad351700a1cd4f38</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="454">789c6dd0410ac2301005d07d4e3124bb20ad4511413c82e2521017e9c4a28b56d0ba10f1ee66664cda6a3fa1cc7f9436496e61bfdb80cdd5bd75ed0501cfee06d63feafa7938ae5f4a170b082b3cf444e90c10b6d7e644b309b39972a83aaaf322d692ea72162b52adaa58bd540a7f9662283c655f33c65144c5884a0a235b2241b14401c5fa44d83744fc3544c6bea1e4cf7c32f92f91f76806fbe3f7d2fe3aecce317aded17b1944bf57ea03b18f6cb9</data>
+ </image>
+ <image name="image2">
+ <data format="XPM.GZ" length="454">789c6dd04d0ac2301005e07d4e3124bb20ad452c05f1088a4b415c24138b2e5a41eb42c4bb9bc9246a208f52e67d94fcb4d6b0df6d40d7e23e99e98280677303ed1ec3f03c1cd72f219b16fce35f7226640508dbeb78a259f959cd43a81aaadda26bb85aaab8c4962b52ed7db8ba54fb3e2c4b51943055d194321456b648118331596b19d9220564fb1163329b921bfa940cffcd047398d68bfb7a72cea8fc7cf4ddf77ca57b14ef5bfc2f59e47b253ec60c6d67</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>TabWidget2</tabstop>
+ <tabstop>moveEval1</tabstop>
+ <tabstop>moveEval2</tabstop>
+ <tabstop>moveEval3</tabstop>
+ <tabstop>moveEval4</tabstop>
+ <tabstop>moveEval5</tabstop>
+ <tabstop>moveEval6</tabstop>
+ <tabstop>moveEval7</tabstop>
+ <tabstop>moveEval8</tabstop>
+ <tabstop>moveEval9</tabstop>
+ <tabstop>posEval1</tabstop>
+ <tabstop>posEval2</tabstop>
+ <tabstop>diffEval2</tabstop>
+ <tabstop>posEval3</tabstop>
+ <tabstop>diffEval3</tabstop>
+ <tabstop>posEval4</tabstop>
+ <tabstop>diffEval4</tabstop>
+ <tabstop>posEval5</tabstop>
+ <tabstop>diffEval5</tabstop>
+ <tabstop>rowEval2</tabstop>
+ <tabstop>rowEval3</tabstop>
+ <tabstop>rowEval4</tabstop>
+ <tabstop>rowEval5</tabstop>
+ <tabstop>countEval1</tabstop>
+ <tabstop>countEval2</tabstop>
+ <tabstop>countEval3</tabstop>
+ <tabstop>countEval4</tabstop>
+ <tabstop>countEval5</tabstop>
+ <tabstop>evalList</tabstop>
+ <tabstop>evalDelete</tabstop>
+ <tabstop>evalSaveAs</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
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 <qvalidator.h>
+#include <qlineedit.h>
+#include <qlcdnumber.h>
+#include <klineeditdlg.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+
+#include <kconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#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;i<list.count();i++)
+ evalList->insertItem(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 <kapplication.h>
+#include <kconfig.h>
+
+#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;i<Move::typeCount;i++)
+ _moveValue[i] = s._moveValue[i];
+
+ for(int i=0;i<InARowCounter::inARowCount;i++)
+ _inARowValue[i] = s._inARowValue[i];
+
+ for(int i=0;i<5;i++)
+ _ringValue[i] = s._ringValue[i];
+
+ for(int i=0;i<5;i++)
+ _ringDiff[i] = s._ringDiff[i];
+}
+
+
+void EvalScheme::setDefaults()
+{
+ for(int i=0;i<6;i++)
+ _stoneValue[i] = defaultStoneValue[i];
+
+ for(int i=0;i<Move::typeCount;i++)
+ _moveValue[i] = defaultMoveValue[i];
+
+ for(int i=0;i<InARowCounter::inARowCount;i++)
+ _inARowValue[i] = defaultInARowValue[i];
+
+ for(int i=0;i<5;i++)
+ _ringValue[i] = defaultRingValue[i];
+
+ for(int i=0;i<5;i++)
+ _ringDiff[i] = defaultRingDiff[i];
+}
+
+
+void EvalScheme::read(KConfig *config)
+{
+ QString confSection = QString("%1 Evaluation Scheme").arg(_name);
+ config->setGroup(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;i<Move::typeCount;i++)
+ _moveValue[i] = list[i].toInt();
+ }
+
+ list = config->readListEntry("InARowValues");
+ if (list.count()>0) {
+ for(int i=0;i<InARowCounter::inARowCount;i++)
+ _inARowValue[i] = list[i].toInt();
+ }
+
+ list = config->readListEntry("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;i<Move::typeCount;i++)
+ entry += QString(", %1").arg( _moveValue[i] );
+ config->writeEntry("MoveValues", entry);
+
+ entry.sprintf("%d", _inARowValue[0]);
+ for(int i=1;i<InARowCounter::inARowCount;i++)
+ entry += QString(", %1").arg( _inARowValue[i] );
+ config->writeEntry("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<Move::typeCount)
+ _moveValue[type] = value;
+}
+
+void EvalScheme::setInARowValue(int stones, int value)
+{
+ if (stones>=0 && stones<InARowCounter::inARowCount)
+ _inARowValue[stones] = value;
+}
+
+/**
+ * Create a EvalScheme out of a String of format
+ *
+ * <SchemeName>=<v1>,<v2>,<v3>,<v4>,... (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<list.count()) {
+ if (i<5)
+ evalScheme->_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<Move::typeCount;i++)
+ res += QString(",%1").arg( _moveValue[i] );
+ for(i=0;i<InARowCounter::inARowCount;i++)
+ res += QString(",%1").arg( _inARowValue[i] );
+ for(i=0;i<5;i++)
+ res += QString(",%1").arg( _ringValue[i] );
+ for(i=0;i<5;i++)
+ res += QString(",%1").arg( _ringDiff[i] );
+
+ return res;
+}
diff --git a/kenolaba/EvalScheme.h b/kenolaba/EvalScheme.h
new file mode 100644
index 00000000..0efcafb8
--- /dev/null
+++ b/kenolaba/EvalScheme.h
@@ -0,0 +1,61 @@
+/**
+ * EvalScheme
+ *
+ * Configuration options for a Evaluation Scheme.
+ * Evaluation Schemes are used for evalution of a Abalone board position
+ *
+ * (C) JW, 2000
+ */
+
+#ifndef _EVALSCHEME_H_
+#define _EVALSCHEME_H_
+
+#include <qstring.h>
+
+#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<Move::typeCount) ? _moveValue[t] : 0;}
+ int inARowValue(int s) { return (s>=0 && s<InARowCounter::inARowCount) ? _inARowValue[s]:0; }
+
+ private:
+ int _ringValue[5], _ringDiff[5];
+ int _stoneValue[6], _moveValue[Move::none];
+ int _inARowValue[InARowCounter::inARowCount];
+
+ QString _name;
+};
+
+#endif // _EVALSCHEME_H_
diff --git a/kenolaba/Makefile.am b/kenolaba/Makefile.am
new file mode 100644
index 00000000..b35b1061
--- /dev/null
+++ b/kenolaba/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = toolbar bitmaps
+
+INCLUDES = -I$(top_srcdir)/libkdegames $(all_includes)
+METASOURCES = AUTO
+KDE_ICON = kenolaba
+
+bin_PROGRAMS = kenolaba
+kenolaba_SOURCES = Board.cpp Move.cpp BoardWidget.cpp AbTop.cpp \
+ kenolaba.cpp Spy.cpp Ball.cpp Network.cpp EvalDlg.ui \
+ EvalDlgImpl.cpp EvalScheme.cpp
+kenolaba_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kenolaba_LDADD = $(LIB_KDEGAMES)
+kenolaba_DEPENDENCIES = $(LIB_KDEGAMES_DEP)
+
+xdg_apps_DATA = kenolaba.desktop
+
+rcdir = $(kde_datadir)/kenolaba
+rc_DATA = kenolabaui.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kenolaba.pot
diff --git a/kenolaba/Move.cpp b/kenolaba/Move.cpp
new file mode 100644
index 00000000..40bc3938
--- /dev/null
+++ b/kenolaba/Move.cpp
@@ -0,0 +1,261 @@
+/* Classes Move, MoveList
+ * - represents a move in the game of Abalone
+ *
+ * Josef Weidendorfer, 28.8.97
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <qstring.h>
+
+#include <klocale.h>
+
+#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;i++)
+ first[i] = actual[i] = -1;
+
+ nextUnused = 0;
+ actualType = -1;
+}
+
+void MoveList::insert(Move m)
+{
+ int t = m.type;
+
+ /* valid and possible ? */
+ if (t <0 || t >= 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<nextUnused; i++)
+ if (move[i].field == f)
+ return true;
+
+ return false;
+}
+
+
+bool MoveList::isElement(Move &m, int startType,bool del)
+{
+ int i;
+
+ for(i=0; i<nextUnused; i++) {
+ Move& mm = move[i];
+ if (mm.field != m.field)
+ continue;
+
+ /* if direction is supplied it has to match */
+ if ((m.direction > 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 <qstring.h>
+
+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)
+ * <getNext> returns reference of next move ordered according to type
+ * <insert> 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 <config.h>
+
+#include "Network.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+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; j<i;j++)
+ addListener("127.0.0.1", port+j);
+
+ if (::listen(fd,5)<0) {
+ printf("Error in listen\n");
+ close(fd);
+ fd = -1;
+ return;
+ }
+
+ sn = new QSocketNotifier( fd, QSocketNotifier::Read );
+ QObject::connect( sn, SIGNAL(activated(int)),
+ this, SLOT(gotConnection()) );
+}
+
+Network::~Network()
+{
+ if (fd<0) return;
+ close(fd);
+
+ char tmp[50];
+ int len = sprintf(tmp, "unreg %d", ntohs(mySin.sin_port));
+
+ Listener* l;
+ for(l=listeners.first(); l!=0; l=listeners.next()) {
+ if (l->reachable)
+ 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 <sys/types.h>
+#include <netinet/in.h>
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qsocketnotifier.h>
+
+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<Listener> 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 <qgroupbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+
+#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;i<BoardCount;i++) {
+ QVBoxLayout *b2 = new QVBoxLayout();
+ b1->addLayout( 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;i<BoardCount;i++) {
+ QVBoxLayout *b2 = new QVBoxLayout();
+ b1->addLayout( 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;i<BoardCount;i++) {
+ actBoard[i]->clearPosition();
+ 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 (depth<BoardCount-1) {
+ board.playMove(m);
+ actBoard[depth+1]->updatePosition(true);
+ actLabel[depth+1]->setNum(value);
+ board.takeBack();
+
+ if (depth<BoardCount-2) {
+ actBoard[depth+2]->clearPosition();
+ 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 (depth<BoardCount-1) {
+ board.playMove(m);
+ bestBoard[depth+1]->updatePosition(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 <qlayout.h>
+#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
--- /dev/null
+++ b/kenolaba/hi128-app-kenolaba.png
Binary files differ
diff --git a/kenolaba/hi16-app-kenolaba.png b/kenolaba/hi16-app-kenolaba.png
new file mode 100644
index 00000000..44974a0f
--- /dev/null
+++ b/kenolaba/hi16-app-kenolaba.png
Binary files differ
diff --git a/kenolaba/hi22-app-kenolaba.png b/kenolaba/hi22-app-kenolaba.png
new file mode 100644
index 00000000..d5b649f4
--- /dev/null
+++ b/kenolaba/hi22-app-kenolaba.png
Binary files differ
diff --git a/kenolaba/hi32-app-kenolaba.png b/kenolaba/hi32-app-kenolaba.png
new file mode 100644
index 00000000..9620d54b
--- /dev/null
+++ b/kenolaba/hi32-app-kenolaba.png
Binary files differ
diff --git a/kenolaba/hi48-app-kenolaba.png b/kenolaba/hi48-app-kenolaba.png
new file mode 100644
index 00000000..2952e03e
--- /dev/null
+++ b/kenolaba/hi48-app-kenolaba.png
Binary files differ
diff --git a/kenolaba/hi64-app-kenolaba.png b/kenolaba/hi64-app-kenolaba.png
new file mode 100644
index 00000000..9e5aa438
--- /dev/null
+++ b/kenolaba/hi64-app-kenolaba.png
Binary files 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 <qobject.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kcmdlineargs.h>
+
+#include <kaboutdata.h>
+
+#include "version.h"
+#include "AbTop.h"
+
+
+static const char description[] =
+ I18N_NOOP("Board game inspired by Abalone");
+
+static KCmdLineOptions options[] =
+{
+ { "h", 0, 0},
+ { "host <host>", I18N_NOOP("Use 'host' for network game"), 0 },
+ { "p", 0, 0},
+ { "port <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, "[email protected]");
+ 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 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kenolaba" version="5">
+
+ <MenuBar>
+ <Menu name="game"><text>&amp;Game</text>
+ <Action name="game_net"/>
+ </Menu>
+ <Menu name="move"><text>&amp;Move</text>
+ <Action name="move_stop"/>
+ <Action name="move_back"/>
+ <Action name="move_forward"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_modify"/>
+ <Separator/>
+ <Action name="edit_save"/>
+ <Action name="edit_restore"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="options_iplay" append="save_merge"/>
+ <Action name="options_moveSlow" append="save_merge"/>
+ <Action name="options_renderBalls" append="save_merge"/>
+ <Action name="options_showSpy" append="save_merge"/>
+ </Menu>
+ </MenuBar>
+
+ <Menu name="rmbPopup">
+ <Menu name="rmbSettings"><text>&amp;Settings</text>
+ <Action name="options_show_menubar"/>
+ <Action name="options_show_toolbar"/>
+ <Action name="options_show_statusbar"/>
+ <Separator/>
+ <Action name="options_save_options"/>
+ </Menu>
+ <Separator/>
+ <Action name="game_new"/>
+ <Action name="move_back"/>
+ <Action name="move_hint"/>
+ <Action name="move_stop"/>
+ </Menu>
+
+ <ToolBar noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="game_new"/>
+ <Action name="edit_modify"/>
+ <Separator/>
+ <Action name="move_back"/>
+ <Action name="move_hint"/>
+ <Action name="move_stop"/>
+ <Separator/>
+ <Action name="game_net"/>
+ </ToolBar>
+
+</kpartgui>
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"