File indexing completed on 2023-11-26 04:09:35
0001 /* 0002 This file is part of the KDE games kwin4 program 0003 SPDX-FileCopyrightText: 2000 Martin Heni <kde@heni-online.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kwin4proc.h" 0009 0010 // KDEGames 0011 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API 0012 #include <libkdegamesprivate/kgame/kgamemessage.h> 0013 // Qt 0014 #include <QByteArray> 0015 #include <QDataStream> 0016 #include <QElapsedTimer> 0017 #include <QFile> 0018 #include <QMutex> 0019 #include <QRandomGenerator> 0020 #include <QWaitCondition> 0021 // Std 0022 #include <cstdio> 0023 #include <cstdlib> 0024 #include <string> 0025 0026 // Algorithm defines 0027 #define MIN_TIME 1000 // min time in milli sec for move 0028 //#define MIN_TIME 10 // min time in milli sec for move 0029 0030 // Board and game geometry 0031 #define MAX_PIECES_COL 6 // Max 6 pieces per column 0032 #define WIN4 4 // 4 in a row won 0033 #define MAX_MOVE 42 // Maximum so many moves possible 0034 #define FIELD_OFFSET 10 // Offset 0035 0036 // AI rating and routines 0037 #define LOWERT -999999999L // Init variables with this value 0038 #define VICTORY_VALUE 9999999L // Win or loss value 0039 #define MAX_EXTRA_RECURSION 15 // Maximum so many extra recursions 0040 #define PERCENT_FOR_INC_ITERATION 40 // If less than this amount of estimated moves are 0041 #define EVAL_RANDOM \ 0042 2500 // Randomize position evaluation by this 0043 // calculated increase recursion 0044 0045 // AI Learning 0046 #define LEARN_DELTA -15000L // Learn if position drops by more than this 0047 #define MAX_LEARNED_POSITIONS 100000 // Learn not more than this positions 0048 #define MIN_LEARN_LEVEL 3 // Use learning only >= this level 0049 #define BRAIN_VERSION 1 // Version number 0050 0051 // Constructor: Setup AI 0052 KComputer::KComputer() 0053 { 0054 const char *s1 = "7777776666666123456654321123456654321"; 0055 const char *s2 = "0000000000000000000123456000000123456"; 0056 unsigned int i; 0057 0058 // Init variables 0059 for (i = 0; i < strlen(s1); ++i) 0060 mRowLengths[i] = s1[i] - '0'; 0061 for (i = 0; i < strlen(s2); ++i) 0062 mStartOfRows[i] = s2[i] - '0'; 0063 0064 // Unknown yet how fast AI calculates 0065 mCalcPosPerMS = -1.0; 0066 0067 // No brain loaded yet 0068 mBrainLoaded = false; 0069 mBrainUsed = 0; 0070 0071 // Connect signals of KGame framework 0072 connect(&proc, &KGameProcess::signalCommand, this, &KComputer::slotCommand); 0073 connect(&proc, &KGameProcess::signalInit, this, &KComputer::slotInit); 0074 connect(&proc, &KGameProcess::signalTurn, this, &KComputer::slotTurn); 0075 } 0076 0077 // Received init command (unused) 0078 void KComputer::slotInit(QDataStream & /*in */, int /*id*/) 0079 { 0080 /* 0081 QByteArray buffer; 0082 QDataStream out(buffer,QIODevice::WriteOnly); 0083 int msgid=KGameMessage::IdProcessQuery; 0084 out << (int)1; 0085 proc.sendSystemMessage(out,msgid,0); 0086 */ 0087 } 0088 0089 // Received turn command 0090 void KComputer::slotTurn(QDataStream &in, bool turn) 0091 { 0092 QByteArray buffer; 0093 QDataStream out(&buffer, QIODevice::WriteOnly); 0094 // fprintf(stderr," KComputer::slotTurn(turn=%d)\n",turn); 0095 // fflush(stderr); 0096 if (turn) { 0097 // Create a move 0098 0099 MoveResult result = think(in, out, false); 0100 int id = KGameMessage::IdPlayerInput; 0101 proc.sendSystemMessage(out, id, 0); 0102 sendValue(result.value, mCurMoveNo); 0103 // fprintf(stderr," KComputer::slotTurn sending value (value=%ld)\n",result.value); 0104 // fflush(stderr); 0105 } 0106 } 0107 0108 // Send position data back to main program 0109 void KComputer::sendValue(long value, int moveNo) 0110 { 0111 qint8 cid = 1; // notifies our KGameIO that this is a value message 0112 int id = KGameMessage::IdProcessQuery; 0113 QByteArray buffer; 0114 QDataStream out(&buffer, QIODevice::WriteOnly); 0115 out << cid << (qint32)value << (qint32)moveNo << (qint32)mLevel << mMaxAIBoard; 0116 proc.sendSystemMessage(out, id, 0); 0117 // fprintf(stderr," KComputer::sendValue (value=%ld)\n",value); 0118 // fflush(stderr); 0119 } 0120 0121 // Load brain position cache 0122 void KComputer::loadBrain() 0123 { 0124 QFile file(mBrainDir + QStringLiteral("kwin4.brain")); 0125 if (!file.open(QIODevice::ReadOnly)) { 0126 fprintf(stderr, " KComputer::Brain file cannot be opened.\n"); 0127 fflush(stderr); 0128 return; 0129 } 0130 0131 QDataStream in(&file); 0132 qint32 version; 0133 in >> version; 0134 if (version != (qint32)BRAIN_VERSION) { 0135 fprintf(stderr, " KComputer::Loading brain version error %ld\n", (long)version); 0136 fflush(stderr); 0137 file.close(); 0138 return; 0139 } 0140 0141 qint32 noOfItems; 0142 in >> noOfItems; 0143 fprintf(stderr, " KComputer::Loading %ld brain data\n", (long)noOfItems); 0144 fflush(stderr); 0145 0146 bool erase = false; 0147 if (noOfItems > MAX_LEARNED_POSITIONS) 0148 erase = true; 0149 0150 for (int cnt = 0; cnt < noOfItems; ++cnt) { 0151 AIBoard board; 0152 AIValue value; 0153 in >> board >> value; 0154 0155 // Forget 10% positions in case of overload 0156 if (erase && cnt % 10 != 0) { 0157 mBrain.insert(board, value); 0158 } 0159 } 0160 fflush(stderr); 0161 qint32 check; 0162 in >> check; 0163 file.close(); 0164 0165 if (check != (qint32)0x18547237) { 0166 fprintf(stderr, " KComputer::Loading brain CRC error %ld cnt=%d\n", (long)check, noOfItems); 0167 fflush(stderr); 0168 mBrain.clear(); 0169 return; 0170 } 0171 fprintf(stderr, " KComputer::Loading brain (%d items) succeeded\n", (int)noOfItems); 0172 fflush(stderr); 0173 } 0174 0175 // Save brain position cache 0176 void KComputer::saveBrain() 0177 { 0178 QFile file(mBrainDir + QStringLiteral("kwin4.brain")); 0179 if (!file.open(QIODevice::WriteOnly)) { 0180 fprintf(stderr, " KComputer::saving brain failed.\n"); 0181 fflush(stderr); 0182 return; 0183 } 0184 0185 QDataStream out(&file); 0186 out << (qint32)BRAIN_VERSION; // Version 0187 out << (qint32)mBrain.size(); 0188 0189 QHashIterator<AIBoard, AIValue> it(mBrain); 0190 while (it.hasNext()) { 0191 it.next(); 0192 AIBoard board = it.key(); 0193 AIValue value = it.value(); 0194 out << board << value; 0195 } 0196 out << (qint32)0x18547237; // Checksum 0197 file.close(); 0198 fprintf(stderr, " KComputer:: Brain saved.\n"); 0199 fflush(stderr); 0200 } 0201 0202 // Received a command from the main program 0203 void KComputer::slotCommand(QDataStream &in, int msgid, int /*receiver*/, int /*sender*/) 0204 { 0205 // fprintf(stderr,"KComputer::slotCommand(Msgid=%d)\n",msgid); 0206 // fflush(stderr); 0207 QByteArray buffer; 0208 QDataStream out(&buffer, QIODevice::WriteOnly); 0209 switch (msgid) { 0210 case 2: // hint 0211 { 0212 qint8 cid = 2; 0213 quint32 recv = 0; 0214 out << cid; 0215 MoveResult result = think(in, out, true); 0216 out << (qint32)result.value; 0217 int id = KGameMessage::IdProcessQuery; 0218 proc.sendSystemMessage(out, id, recv); 0219 } break; 0220 case 3: // AI board value changed, maybe learn 0221 { 0222 AIBoard aiBoard; 0223 qint32 value, level, delta; 0224 in >> aiBoard >> value >> delta >> level; 0225 // Only learn big changes 0226 if (mIsLearning && delta < LEARN_DELTA && level >= MIN_LEARN_LEVEL && level < MIN_LEARN_LEVEL + AIValue::NO_OF_LEVELS) { 0227 fprintf(stderr, "KComputer:: LEARNING Received AI board for value %ld delta %ld level %ld\n", (long)value, (long)delta, (long)level); 0228 aiBoard.print(); 0229 0230 // Learn board? 0231 AIValue aiValue; 0232 // Do we already store board? 0233 if (mBrain.contains(aiBoard)) { 0234 aiValue = mBrain.value(aiBoard); 0235 } 0236 // Do we store mirror board? 0237 else if (mBrain.contains(aiBoard.mirror())) { 0238 aiBoard = aiBoard.mirror(); 0239 aiValue = mBrain.value(aiBoard); 0240 } 0241 // Set not set or decreased values in value structure 0242 if (!aiValue.isSet((int)level - MIN_LEARN_LEVEL) || aiValue.value((int)level - MIN_LEARN_LEVEL) > (long)value) { 0243 aiValue.setValue((int)level - MIN_LEARN_LEVEL, (long)value); 0244 mBrain.insert(aiBoard, aiValue); 0245 saveBrain(); 0246 fprintf(stderr, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 0247 fprintf(stderr, "$ LEARNING $\n"); 0248 fprintf(stderr, "$ Setting board level %d to value = %ld\n", (int)level, (long)value); 0249 fprintf(stderr, "$ mBrain size=%d\n", mBrain.size()); 0250 fprintf(stderr, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 0251 fflush(stderr); 0252 } else // TODO: Remove else 0253 { 0254 fprintf(stderr, "NOT LEARNING $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); 0255 fprintf(stderr, 0256 " REASON: %d %ld %ld\n", 0257 aiValue.isSet((int)level - MIN_LEARN_LEVEL), 0258 aiValue.value((int)level - MIN_LEARN_LEVEL), 0259 (long)value); 0260 fflush(stderr); 0261 } 0262 } // end delta 0263 } break; 0264 default: 0265 fprintf(stderr, "KComputer:: unknown command (msgid=%d)\n", msgid); 0266 fflush(stderr); 0267 } 0268 } 0269 0270 // Think up a move (plus reading data from stream) 0271 KComputer::MoveResult KComputer::think(QDataStream &in, QDataStream &out, bool /*hint*/) 0272 { 0273 qint32 pl; 0274 qint32 move; 0275 qint32 tmp; 0276 COLOUR secondPlayer; 0277 // Which color's move is to come 0278 COLOUR currentPlayer; 0279 // Which player started the game 0280 COLOUR startPlayer; 0281 0282 // Read command data stream into local variables 0283 in >> pl; 0284 in >> tmp; 0285 mCurMoveNo = tmp; 0286 in >> tmp; 0287 currentPlayer = (COLOUR)(tmp); 0288 in >> tmp; 0289 startPlayer = (COLOUR)(tmp); 0290 in >> tmp; 0291 secondPlayer = (COLOUR)(tmp); 0292 in >> tmp; 0293 mLevel = tmp; 0294 in >> tmp; 0295 mIsLearning = tmp; 0296 in >> mBrainDir; 0297 0298 // Check proper learning level. If not proper switch learning off. 0299 if (mLevel < MIN_LEARN_LEVEL || mLevel >= MIN_LEARN_LEVEL + AIValue::NO_OF_LEVELS) { 0300 mIsLearning = false; 0301 fprintf(stderr, "KComputer:: Switching off learning for level %d\n", mLevel); 0302 } 0303 0304 fprintf(stderr, 0305 "KComputer::think: pl=%d, mCurMoveNo=%d currentPlayer=%d begin=%d secondPlayer=%d level=%d learn=%d\n", 0306 pl, 0307 mCurMoveNo, 0308 currentPlayer, 0309 startPlayer, 0310 secondPlayer, 0311 mLevel, 0312 mIsLearning); 0313 // fprintf(stderr,"KComputer::learning=%d path=%s\n",mIsLearning,mBrainDir.toLatin1().data()); 0314 0315 // Brain loaded? 0316 if (!mBrainLoaded && mIsLearning) { 0317 mBrainLoaded = true; 0318 loadBrain(); 0319 } 0320 0321 // Setup board (init) 0322 // The game board prepared for the AI 0323 FARBE fieldMatrix[SIZE_Y_ALL + 1][SIZE_X + 1]; 0324 // Amount of pieces on the game board 0325 char numberMatrix[SIZE_Y_ALL + 1]; 0326 0327 for (int y = 0; y <= SIZE_Y_ALL; ++y) { 0328 numberMatrix[y] = 0; 0329 } 0330 0331 for (int y = 0; y <= SIZE_Y; ++y) { 0332 for (int x = 0; x <= SIZE_X; ++x) { 0333 fieldMatrix[y][x] = (FARBE)(y + FIELD_OFFSET); 0334 fieldMatrix[6 + x][y] = (FARBE)(y + FIELD_OFFSET); 0335 fieldMatrix[13 + x + y][x] = (FARBE)(y + FIELD_OFFSET); 0336 fieldMatrix[30 + x - y][x] = (FARBE)(y + FIELD_OFFSET); 0337 } // next x 0338 } // next y 0339 0340 // Field comes as 42 qint8's representing moves 0341 int i, j; 0342 for (i = 0; i <= SIZE_Y; ++i) { 0343 for (j = 0; j <= SIZE_X; ++j) { 0344 qint8 col; 0345 in >> col; 0346 DoMove(j, (COLOUR)col, fieldMatrix, numberMatrix); 0347 } 0348 } 0349 0350 // Check final checksum 0351 in >> tmp; 0352 if ((long)tmp != 421256L) { 0353 fprintf(stderr, "CHECKSUM=%ld [should be 421256]\n", (long)tmp); 0354 fflush(stderr); 0355 } 0356 0357 // Estimated number of positions to evaluate (MAX) 0358 int estimated = 0; 0359 for (int i = 1; i <= mLevel + 1; ++i) { 0360 estimated += int(pow(7., i)); 0361 } 0362 0363 // Measure time of move and positions evaluated 0364 QElapsedTimer timer; 0365 timer.start(); 0366 mPosEvaluations = 0; 0367 0368 // Get move 0369 int gameOver = 0; 0370 int extraRecurstion = 0; 0371 MoveResult result; 0372 0373 // Loop movement if not many positions are evaluated (end game) 0374 // to look ahead a bit more 0375 do { 0376 // Actually calculate move 0377 result = MinMax(currentPlayer, fieldMatrix, numberMatrix, mLevel + extraRecurstion, mCurMoveNo, true); 0378 result.value = -result.value; 0379 0380 // Do not recalculate for (nearly finished) games 0381 // if (result.value >= VICTORY_VALUE*0.95 || result.value <= -VICTORY_VALUE *0.95) gameOver = 1; 0382 extraRecurstion++; 0383 } while (PERCENT_FOR_INC_ITERATION / 10 * mPosEvaluations <= estimated && !gameOver && extraRecurstion < MAX_EXTRA_RECURSION); 0384 0385 // Measure elapsed time 0386 int elapsed = timer.elapsed(); 0387 if (elapsed < 1) 0388 elapsed = 1; 0389 mCalcPosPerMS = (float)mPosEvaluations / (float)elapsed; 0390 0391 // Debug 0392 fprintf(stderr, 0393 "AI MOVE to %d value=%ld level %d took time=%d ms and evals=%d estimated=%d pos/ms=%f brain=%ld\n", 0394 result.move, 0395 result.value, 0396 mLevel, 0397 elapsed, 0398 mPosEvaluations, 0399 estimated, 0400 mCalcPosPerMS, 0401 mBrainUsed); 0402 0403 // Sleep a minimum amount to slow down moves 0404 if (elapsed < MIN_TIME) { 0405 // is usleep(1000*(MIN_TIME-elapsed)); 0406 QMutex mutex; 0407 QWaitCondition cond; 0408 mutex.lock(); 0409 cond.wait(&mutex, MIN_TIME - elapsed); 0410 0411 elapsed = timer.elapsed(); 0412 fprintf(stderr, "AI after sleeping time elapsed=%d\n", elapsed); 0413 } 0414 fflush(stderr); 0415 0416 // Send out move 0417 move = result.move; 0418 out << pl << move; 0419 return result; 0420 } 0421 0422 // Min-Max AI algorithm 0423 KComputer::MoveResult KComputer::MinMax(COLOUR color, FARBE field[][SIZE_X + 1], char numbers[], int reklev, int moveNo, bool first) 0424 { 0425 // Modify move value 0426 static long gauss[] = {10, 50, 300, 500, 300, 50, 10}; 0427 0428 // Local board 0429 FARBE locField[SIZE_Y_ALL + 1][SIZE_X + 1]; 0430 char locNumbers[SIZE_Y_ALL + 1]; 0431 0432 // Result of move 0433 MoveResult result; 0434 result.move = -1; // No move found 0435 result.value = LOWERT; 0436 0437 for (int x = 0; x <= SIZE_X; ++x) { 0438 long wert; 0439 if (numbers[6 + x] >= MAX_PIECES_COL) 0440 continue; 0441 0442 // Perform test move 0443 memcpy(locNumbers, numbers, sizeof(locNumbers)); 0444 memcpy(locField, field, sizeof(locField)); 0445 DoMove(x, color, locField, locNumbers); 0446 0447 // Count evaluations 0448 mPosEvaluations++; 0449 0450 // Check for game over 0451 COLOUR winner = isGameOver(field, numbers); 0452 if (winner != Nobody) { 0453 // Choose tree with fastest victory or slowest loss 0454 if (winner == color) 0455 wert = VICTORY_VALUE + reklev * 5000; 0456 else 0457 wert = -VICTORY_VALUE - reklev * 5000; 0458 } 0459 // Drawn / Remis 0460 else if (moveNo >= MAX_MOVE) { 0461 wert = 0; 0462 } 0463 // End of recursion reached 0464 else if (reklev <= 0) { 0465 wert = PositionEvaluation(color, field); 0466 // wert += gauss[x]; // TODO: Gauss should be here 0467 // No need for filling the test board here 0468 } 0469 // MinMax calculation for next recursion level 0470 else { 0471 // Check learning 0472 AIBoard testBoard(color, locField); 0473 // Found cached board or not 0474 bool haveToCalculate = true; 0475 0476 // Check for learned board 0477 if (mIsLearning && mBrain.contains(testBoard)) { 0478 AIValue testValue = mBrain.value(testBoard); 0479 if (testValue.isSet(mLevel - MIN_LEARN_LEVEL)) { 0480 wert = testValue.value(mLevel - MIN_LEARN_LEVEL); 0481 mBrainUsed++; 0482 haveToCalculate = false; 0483 fprintf(stderr, "$$$$$$ Board[%d] found in cache value = %ld used=%ld\n", mLevel, wert, mBrainUsed); 0484 fflush(stderr); 0485 } 0486 } 0487 // Check for learned mirror board 0488 else if (mIsLearning && mBrain.contains(testBoard.mirror())) { 0489 testBoard = testBoard.mirror(); 0490 AIValue testValue = mBrain.value(testBoard); 0491 if (testValue.isSet(mLevel - MIN_LEARN_LEVEL)) { 0492 wert = testValue.value(mLevel - MIN_LEARN_LEVEL); 0493 mBrainUsed++; 0494 haveToCalculate = false; 0495 fprintf(stderr, "$$$$$$ MIRROR 2 Board[%d] found in cache value = %ld used=%ld\n", mLevel, wert, mBrainUsed); 0496 fflush(stderr); 0497 } 0498 } 0499 0500 // Real calculation necessary 0501 if (haveToCalculate) { 0502 // Swap color for next move 0503 COLOUR nextColor; 0504 if (color == Red) 0505 nextColor = Yellow; 0506 else 0507 nextColor = Red; 0508 MoveResult minmaxResult = MinMax(nextColor, locField, locNumbers, reklev - 1, moveNo + 1, false); 0509 wert = minmaxResult.value + gauss[x]; // TODO: Remove gauss here 0510 } 0511 } // end else MinMax 0512 0513 // New maximum? 0514 if (wert >= result.value) { 0515 result.value = wert; 0516 result.move = x; 0517 if (first) 0518 mMaxAIBoard.fromField(color, false, locField); 0519 // if (result.value >= VICTORY_VALUE) break; 0520 } 0521 } // next x 0522 0523 // MinMax 0524 result.value = -result.value; 0525 return result; 0526 } // end MinMax 0527 0528 // Position evaluation 0529 long KComputer::PositionEvaluation(COLOUR curColor, FARBE field[][SIZE_X + 1]) 0530 { 0531 /* Abstand: 0 1 2 3 4 5 */ 0532 static long myWERT[] = {2200, 600, 300, 75, 20, 0}; 0533 // static long myWERT[]={0,0,0,0,0,0}; 0534 /* How many ofCOLOUR: 0 1 2 3 4 */ 0535 static long steinWERT[4][5] = { 0536 {0, 500L, 40000L, 200000L, VICTORY_VALUE}, // Leerfelder=0 0537 {0, 500L, 8000L, 40000L, VICTORY_VALUE}, // =1 0538 {0, 00L, 4000L, 25000L, VICTORY_VALUE}, // =2 0539 {0, 00L, 2000L, 12500L, VICTORY_VALUE}, // =3 0540 }; 0541 0542 // Initial values 0543 long yellow_value = random(EVAL_RANDOM); 0544 long red_value = random(EVAL_RANDOM); 0545 0546 for (int y = 0; y <= SIZE_Y_ALL; ++y) { 0547 if (mRowLengths[y] < WIN4) 0548 continue; 0549 for (int i = 0; i <= (mRowLengths[y] - WIN4); ++i) { 0550 COLOUR color = Nobody; 0551 long value = 0; 0552 int cntcol = 0; 0553 int cnt = 0; 0554 for (int j = 0; j < WIN4; ++j) { 0555 FARBE checkField = field[y][i + j + mStartOfRows[y]]; 0556 if ((COLOUR)checkField == Red) { 0557 if (color == Yellow) { 0558 color = Nobody; 0559 break; 0560 } 0561 cntcol++; 0562 color = Red; 0563 } else if ((COLOUR)checkField == Yellow) { 0564 if (color == Red) { 0565 color = Nobody; 0566 break; 0567 } 0568 cntcol++; 0569 color = Yellow; 0570 } else { 0571 cnt += checkField - FIELD_OFFSET; 0572 value += myWERT[checkField - FIELD_OFFSET]; 0573 } 0574 } /*next j */ 0575 if (cnt > 3) 0576 cnt = 3; 0577 if (color == Red) 0578 red_value += (value + steinWERT[cnt][cntcol]); 0579 else if (color == Yellow) 0580 yellow_value += (value + steinWERT[cnt][cntcol]); 0581 } /*next i*/ 0582 } /*next y*/ 0583 0584 // Return value 0585 if (curColor == Red) 0586 return red_value - yellow_value; 0587 else 0588 return yellow_value - red_value; 0589 } 0590 0591 // Check for game over 0592 COLOUR KComputer::isGameOver(FARBE field[][SIZE_X + 1], char numbers[]) 0593 { 0594 for (int y = 0; y <= SIZE_Y_ALL; ++y) { 0595 if (numbers[y] < WIN4) 0596 continue; 0597 if (mRowLengths[y] < WIN4) 0598 continue; 0599 0600 int cnt = 0; 0601 COLOUR thiscolor = Nobody; 0602 for (int x = 0; x < mRowLengths[y]; ++x) { 0603 COLOUR checkField = (COLOUR)field[y][x + mStartOfRows[y]]; 0604 if (checkField == thiscolor) 0605 ++cnt; 0606 else { 0607 cnt = 1; 0608 thiscolor = checkField; 0609 } 0610 if ((cnt >= WIN4) && ((thiscolor == Yellow) || (thiscolor == Red))) 0611 return thiscolor; 0612 } // next x 0613 } // next y 0614 return Nobody; 0615 } 0616 0617 // Execute move on given board 0618 void KComputer::DoMove(int move, COLOUR color, FARBE field[][SIZE_X + 1], char numbers[]) 0619 { 0620 if (color == Tip || color == Nobody) 0621 return; // no real move 0622 int x = move; 0623 int y = numbers[6 + move]; 0624 field[y][x] = color; 0625 0626 field[6 + x][y] = color; 0627 field[13 + x + y][x] = color; 0628 field[30 + x - y][x] = color; 0629 numbers[y]++; 0630 numbers[6 + x]++; 0631 numbers[13 + x + y]++; 0632 numbers[30 + x - y]++; 0633 for (int i = y + 1; i <= SIZE_Y; ++i) { 0634 field[i][x]--; 0635 field[6 + x][i]--; 0636 field[13 + x + i][x]--; 0637 field[30 + x - i][x]--; 0638 } 0639 } 0640 0641 // Retrieve random number 0..max 0642 int KComputer::random(int max) 0643 { 0644 // return 0; 0645 return proc.random()->bounded(max); 0646 } 0647 0648 // Main startup 0649 int main() 0650 { 0651 // This is the computer player...it should do the calculation 0652 // It doesn't do much here 0653 fprintf(stderr, "AI process starts up\n"); 0654 fflush(stderr); 0655 KComputer comp; 0656 // And start the event loop 0657 comp.proc.exec(); 0658 fprintf(stderr, "AI process exists.\n"); 0659 fflush(stderr); 0660 return 1; 0661 } 0662 0663 #include "moc_kwin4proc.cpp"