• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegames API Reference
  • KDE Home
  • Contact Us
 

ksquares

  • sources
  • kde-4.14
  • kdegames
  • ksquares
  • src
aicontroller.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2006 by Matthew Williams <matt@milliams.com> *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 2 of the License, or *
7  * (at your option) any later version. *
8  ***************************************************************************/
9 
10 #include "aicontroller.h"
11 
12 #include <ctime>
13 #include <kdebug.h>
14 
15 #include <QSet>
16 
17 #include "settings.h"
18 
19 aiController::aiController(int newPlayerId, const QList<bool> &newLines, const QList<int> &newSquareOwners, int newWidth, int newHeight) : squareOwners(newSquareOwners), playerId(newPlayerId), width(newWidth), height(newHeight)
20 {
21  linesSize = newLines.count();
22  lines = new bool[linesSize];
23  for (int i = 0; i < linesSize; ++i) lines[i] = newLines[i];
24  srand( (unsigned)time( NULL ) );
25  kDebug() << "AI: Starting AI level" << Settings::difficulty();
26 }
27 
28 aiController::~aiController()
29 {
30  delete[] lines;
31 }
32 
33 QList<int> aiController::autoFill(int safeMovesLeft)
34 {
35  QList<int> fillLines;
36 
37  // add a random safe moves while there are safe moves left
38  QList<int> next;
39  //kDebug() << safeMoves().isEmpty();
40  while( !( (next = safeMoves()).isEmpty() ) )
41  {
42  int nextLine = next[rand() % next.size()];
43  lines[nextLine] = true;
44  //kDebug() << nextLine;
45  fillLines << nextLine;
46  }
47 
48  // safeMovesLeft times delete a line from fillLines
49  for (int i = 0; i<safeMovesLeft; ++i)
50  {
51  if (fillLines.isEmpty()) break;
52  int index = rand() % fillLines.size();
53  fillLines.removeAt(index);
54  }
55 
56  return fillLines;
57 }
58 
59 int aiController::chooseLine() const
60 {
61  QList<int> choiceList;
62  for(int i=0; i<linesSize; i++) //trying to get points. looking for squares with 3 lines
63  {
64  if(!lines[i])
65  {
66  QList<int> adjacentSquares = squaresFromLine(i);
67  for(int j=0; j<adjacentSquares.size(); j++)
68  {
69 
70  if(countBorderLines(adjacentSquares.at(j), lines) == 3) //if 3 lines, draw there to get points!
71  {
72  choiceList.append(i);
73  //kDebug() << "AI: 1. Adding" << i << "to choices";
74  }
75  }
76  }
77  }
78  if(choiceList.size() != 0)
79  {
80  if(Settings::difficulty() == 2) // to play good ai has to look into the future game
81  {
82  QList<int> openLines; // list of not yet drawn lines
83  for(int i = 0; i < linesSize; i++)
84  {
85  if(!lines[i])
86  {
87  openLines.append(i);
88  }
89  }
90  QList<int> choices=chooseLeastDamaging(openLines); // run extended damage control
91  if(choices.size() > 0)
92  {
93  kDebug() << "AI: 4. Drawing line at index:" << choices.at(0);
94  return choices.at(0);
95  }
96  }
97  float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
98  int randChoice = (short)(randomFloat)/1;
99  kDebug() << "AI: 1. Drawing line at index:" << choiceList.at(randChoice);
100  return choiceList.at(randChoice);
101  }
102 
103  choiceList = safeMoves();
104 
105  if(choiceList.size() != 0)
106  {
107  float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
108  int randChoice = (short)(randomFloat)/1;
109  kDebug() << "AI: 2. Drawing line at index:" << choiceList.at(randChoice);
110  return choiceList.at(randChoice);
111  }
112 
113  choiceList.clear();
114  for(int i=0; i<linesSize; i++) //have to take what's left
115  {
116  if(!lines[i])
117  {
118  QList<int> adjacentSquares = squaresFromLine(i);
119  for(int j=0; j<adjacentSquares.size(); j++)
120  {
121 
122  if(countBorderLines(adjacentSquares.at(j), lines) == 2) //if 2 lines (they're all that's left!)
123  {
124  choiceList.append(i);
125  //kDebug() << "AI: 3. Adding" << i << "to choices";
126  }
127  }
128  }
129  }
130  if(Settings::difficulty() >= 1) //Hard(2/3) //do some damage control :)
131  {
132  QList<int> goodChoiceList = chooseLeastDamaging(choiceList);
133  if(goodChoiceList.size() != 0)
134  {
135  float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(goodChoiceList.size()-1);
136  int randChoice = (short)(randomFloat)/1;
137  kDebug() << "AI: 3. Drawing line at index:" << goodChoiceList.at(randChoice);
138  return goodChoiceList.at(randChoice);
139  }
140  }
141 
142  if(choiceList.size() != 0)
143  {
144  float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
145  int randChoice = (short)(randomFloat)/1;
146  kDebug() << "AI: 3. Drawing line at index:" << choiceList.at(randChoice);
147  return choiceList.at(randChoice);
148  }
149  return 0;
150 }
151 
152 QList<int> aiController::safeMoves() const
153 {
154  QList<int> safeLines;
155  for(int i=0; i<linesSize; i++) //finding totally safe moves. avoiding squares with 2 lines
156  {
157  if(!lines[i])
158  {
159  QList<int> adjacentSquares = squaresFromLine(i);
160  int badCount = 0;
161  for(int j=0; j<adjacentSquares.size(); j++)
162  {
163  if(countBorderLines(adjacentSquares.at(j), lines) == 2) //don't want to make 3 lines around a square
164  {
165  badCount++;
166  }
167  }
168  if(badCount == 0)
169  {
170  safeLines.append(i);
171  //kDebug() << "AI: 2. Adding" << i << "to choices";
172  }
173  }
174  }
175  return safeLines;
176 }
177 
178 QList<int> aiController::chooseLeastDamaging(const QList<int> &choiceList) const
179 {
180  //kDebug() << "AI: Checking" << choiceList.size() << "possible moves";
181  QMap<int,int> linePointDamage; //this will be a list of how damaging a certain move will be. Key = damage of move, Value = index of line
182  QScopedArrayPointer<bool> linesCopy(new bool[linesSize]); //make temporary local copies of lists
183  int sidesOfSquare[4];
184 
185  QMap<int, QSet<int> > chains; // this is a raw list of chains (which are sets of lines). key = random element of chain
186  QMap<int, QSet<int> > chainSet; // same thing as chains but with unique chains
187  QList<QList<int> > ownChains; // chains that ai will get in this run. those chains are taken in myLines.
188  QList<int> ownMoves; // contains lines of chain that the ai will take first (this will contain the returned move)
189  QScopedArrayPointer<bool> myLines(new bool[linesSize]); //make temporary local copies of lists
190  int ownLinesCnt = 0; // count of how many lines ai will take in this run
191  int ownSquaresCnt = 0; // count of how many squares ai will get in this run
192 
193  if (Settings::difficulty() > 1)
194  {
195  memcpy(myLines.data(), lines, linesSize); // lines --> myLines (complete own chains) --> linesCopy (analyze damage/chains for next runs)
196  bool chainFound;
197  // since chooseLeastDamaging will be called early during the game if playing against hard ai, we need to finish open chains in linesCopy before computing the number of residual chains
198  do // this loop completes all chains the opponent gave to ai
199  {
200  chainFound = false;
201  for(int curSquare = 0; curSquare < squareOwners.size(); curSquare++) // walk through squares and search for start of chain
202  {
203  QList<int> ownChain; // remember completed chain lines
204  int chainSquare = curSquare;
205  bool squareFound;
206  do { // this loop walks through a chain square by square
207  squareFound = false;
208  if(countBorderLines(sidesOfSquare, chainSquare, &(*myLines)) == 3) // found a square for ai
209  {
210  for(int sideOfSquare = 0; sideOfSquare <= 3; sideOfSquare++)
211  {
212  if(!myLines[sidesOfSquare[sideOfSquare]]) // found missing line of square
213  {
214  ownLinesCnt++;
215 
216  int nextSquareFound=-1;
217  QList<int> adjacentSquares = squaresFromLine(sidesOfSquare[sideOfSquare]);
218  for(int i = 0; i < adjacentSquares.size(); i++)
219  {
220  int chainSquareBorderCnt = countBorderLines(adjacentSquares.at(i), &(*myLines));
221  if(chainSquare != adjacentSquares.at(i) &&
222  chainSquareBorderCnt == 3) // check if a second square will be completed by this line
223  {
224  ownSquaresCnt++; // add extra square
225  }
226  if(chainSquareBorderCnt == 2) // look for next square in chain
227  {
228  nextSquareFound = adjacentSquares.at(i);
229  }
230 
231  }
232  myLines[sidesOfSquare[sideOfSquare]] = true; // complete line
233  if(nextSquareFound >= 0)
234  {
235  chainSquare = nextSquareFound;
236  }
237  ownChain.append(sidesOfSquare[sideOfSquare]);
238  }
239  }
240  squareFound = true;
241  chainFound = true;
242  ownSquaresCnt++;
243  }
244  } while(squareFound);
245  if(chainFound)
246  {
247  ownChains.append(ownChain);
248  break;
249  }
250  }
251  } while (chainFound);
252  //kDebug() << "ownChains:" << ownChains;
253 
254  // complete the shortest chain first if there is more than one chain. this is needed to stop alternating between two chains because that works against the hard ai move which takes the next chain by sacrificing 2/4 squares. when alternating between two chains it's possible that there are 3 remaining open lines in both chains combined which triggers the evil move too late because the chains were completed in the wrong order
255  int minChain=-1;
256  int tmp=width*height*10;
257  for(int i = 0; i < ownChains.size(); i++)
258  {
259  if(tmp > ownChains.at(i).size())
260  {
261  tmp = ownChains.at(i).size();
262  minChain = i;
263  }
264  }
265  if(minChain >= 0)
266  {
267  ownMoves=ownChains.at(minChain);
268  }
269  //kDebug() << "ownMoves:" << ownMoves;
270  }
271 
272  for(int i = 0; i < choiceList.size(); i++) //cycle through all the possible moves
273  {
274  QList<int> squaresCopy = squareOwners; //make temporary local copies of lists
275  QSet<int> chain; // set of lines that are given to opponent by move choiceList.at(i)
276 
277  if (Settings::difficulty() > 1)
278  {
279  memcpy(linesCopy.data(), myLines.data(), linesSize); //make temporary local copies of lists
280  if (linesCopy[choiceList.at(i)]) continue; // already covered. ai will get this line
281  } else {
282  memcpy(linesCopy.data(), lines, linesSize); //make temporary local copies of lists
283  }
284 
285  linesCopy[choiceList.at(i)] = true; //we're going to try drawing a line here
286 
287  //now it would be the next player's turn so we're going to count how many squares they would be able to get.
288  int count = 0; //this is how many points the next player will ge if you draw a line at choiceList.at(i)
289  bool squareFound = false;
290  chain.insert(choiceList.at(i));
291  do
292  {
293  for(int currentSquare=0; currentSquare<squaresCopy.size(); currentSquare++) //cycle through the grid (by squares):
294  {
295  if(countBorderLines(sidesOfSquare, currentSquare, &(*linesCopy)) == 3) //if we've found a square with three sides drawn:
296  {
297  count++;
298  squareFound = true; //we found a square so we will look again for the next
299 
300  for(int sideOfSquare=0; sideOfSquare<=3; sideOfSquare++) //make the square complete in linesCopy
301  {
302  if(Settings::difficulty() > 1 && !linesCopy[sidesOfSquare[sideOfSquare]])
303  {
304  chain.insert(sidesOfSquare[sideOfSquare]);
305  QList<int> adjacentSquares = squaresFromLine(sidesOfSquare[sideOfSquare]);
306  for(int adjsq = 0; adjsq < adjacentSquares.size(); adjsq++)
307  {
308  if(currentSquare == adjacentSquares.at(adjsq)) continue;
309  if(countBorderLines(adjacentSquares.at(adjsq), &(*myLines)) == 3)
310  { // line will complete two squares
311  count++;
312  }
313  }
314  }
315  linesCopy[sidesOfSquare[sideOfSquare]] = true; //draw at this squares
316  } //now current square is completed by the second player.
317  break; //since we found a square with 3 sides completed (now = 4), we break the 'for(currentSquare)' loop
318  }
319  else
320  {
321  squareFound = false; //we couldn't find a square this time round so we'll try the next 'i'
322  }
323  }
324  } while(squareFound == true); //while we're still finding squares
325  linePointDamage.insertMulti(count, choiceList.at(i)); //insert a pair with Key=count, Value=i
326  chains.insert(choiceList.at(i), chain);
327  }
328 
329  //kDebug() << "linePointDamage:" << linePointDamage;
330 
331  if(Settings::difficulty() < 2) // middle ai won't analyze the game further
332  {
333  QList<int> bestMoves = linePointDamage.values(linePointDamage.begin().key()); //this is a list of the indices of the lines that are the least damaging. linePointDamage.begin() returns the 1st pair in the QMap, sorted in ascending order by Key (damage of move)
334  return bestMoves;
335  }
336 
337  //kDebug() << chains;
338  // remove double entries from chains to get chainSet
339  QMapIterator<int, QSet<int> > j(chains);
340  while(j.hasNext()) // walk through chains and add chain to chainSet (if not already contained)
341  {
342  j.next();
343  bool newChain = true;
344  QSet<int> chainCheck = j.value(); // this is the chain we might add
345  QMapIterator<int, QSet<int> > chainSetIt(chainSet);
346  while(chainSetIt.hasNext()) // walk through chainSet and look for chainCheck
347  {
348  chainSetIt.next();
349  QSet<int> chainSetI = chainSetIt.value();
350  if(chainSetI == chainCheck) // found chainCheck in chainSet, don't add
351  {
352  newChain = false;
353  break;
354  }
355  }
356  if (newChain) // chainCheck not in chainSet
357  {
358  chainSet.insert(j.key(), chainCheck);
359  }
360  }
361  //kDebug() << "chainSet:" << chainSet;
362 
363  // analyze chains
364  // TODO: find loop chains to calculate sacrifices (loopChains are a subset of longChains)
365  int shortChains = 0; // chains <= 2 lines
366  int longChains = 0; // exploitable chains
367  QMapIterator<int, QSet<int> > chainSetIt(chainSet);
368  while(chainSetIt.hasNext())
369  {
370  chainSetIt.next();
371  QSet<int> chainSetI = chainSetIt.value();
372  if (chainSetI.size() <= 3)
373  {
374  shortChains++;
375  } else
376  {
377  longChains++;
378  }
379  }
380  //kDebug() << "short chains:" << shortChains << ", long chains: " << longChains;
381 
382  if(
383  (
384  (ownLinesCnt == 2) || // sacrifice 2 squares squares to opponent to get next chain.
385  (ownLinesCnt == 3 && ownSquaresCnt == 4) // this is for loop chains which require a sacrifice of 4 squares
386  )
387  &&
388  longChains > 0 // only do it if there is at least one chain to steal
389  &&
390  safeMoves().size() == 0 // only do it in endgames
391  )
392  {
393  kDebug() << "HAHA, our chance to do the evil thing!";
394  int magicLine = -1; // line in own moves that is used to get the next chain (draw there to give 2/4 squares to opponent)
395  // formal definition of magicLine: line that when completed will leave at least one other line in own moves that completes two squares at once
396  // the opposite of magic line will be used in the hard hearted handout to make sure that the opponent won't be able to do the evil move
397  for(int i = 0; i < ownMoves.size(); i++)
398  {
399  memcpy(myLines.data(), lines, linesSize); // we want to look one line into the future game
400  myLines[ownMoves.at(i)] = true; // try ownMove i (one line in chain that ai will get)
401  for(int j = 0; j < ownMoves.size(); j++) // test other lines in own moves
402  {
403  if (i == j) continue;
404  int leftSquares = 0; // count squares that can be completed by other line (j)
405  QList<int> adjacentSquares = squaresFromLine(ownMoves.at(j));
406  for(int k = 0; k < adjacentSquares.size(); k++)
407  {
408  if (countBorderLines(adjacentSquares.at(k), &(*myLines)) == 3)
409  {
410  leftSquares++;
411  }
412  }
413  if (leftSquares == 2) // we found a line that will yield another line in own moves that completes two squares
414  {
415  magicLine = i;
416  }
417  }
418  }
419  kDebug() << "Magic Line index:" << magicLine;
420  QList<int> bestMoves;
421  if(ownMoves.size() > 1)
422  {
423  int ownMove = 1;
424  if(magicLine >= 0 && magicLine < ownMoves.size())
425  {
426  ownMove=magicLine;
427  }
428  bestMoves.append(ownMoves.at(ownMove)); // choose the second line found! in case of 2 squares for ai this will choose the line at the end of the chain. in case of 4 squares this will be the line in the middle, leaving two lines that complete two squares each. FIX: 1 doesn't work in some cases because the algorithm doesn't detect chains by spatial connectedness. ie if there are two ends of a chain the search algorithm can jump between those two ends, messing up the order in ownMoves list. solution is magicLine
429  return bestMoves;
430  }
431  }
432 
433  if(ownMoves.size() > 0) // complete own chain
434  {
435  QList<int> bestMoves;
436  bestMoves.append(ownMoves.at(0));
437  return bestMoves;
438  }
439 
440  if(linePointDamage.begin().key() == 2) // opponent will get 2 squares
441  {
442  int handoutLine = -1;
443  QList<int> opponentChain;
444  QMapIterator<int, QSet<int> > chainSetIt(chainSet);
445  while(chainSetIt.hasNext())
446  {
447  chainSetIt.next();
448  QSet<int> chainSetI = chainSetIt.value();
449  if(chainSetI.contains(linePointDamage.begin().value()))
450  {
451  opponentChain = chainSetI.values();
452  }
453  }
454  for(int i = 0; i < opponentChain.size(); i++)
455  {
456  memcpy(myLines.data(), lines, linesSize); // we want to look one line into the future game
457  myLines[opponentChain.at(i)] = true; // try move in chain for opponent
458  for(int j = 0; j < opponentChain.size(); j++) // test other lines in chain
459  {
460  if (i == j) continue;
461  int badSquares = 0; // count squares with two open lines (those are dangerous)
462  QList<int> adjacentSquares = squaresFromLine(opponentChain.at(j));
463  for(int k = 0; k < adjacentSquares.size(); k++)
464  {
465  if(countBorderLines(adjacentSquares.at(k), &(*myLines)) != 3)
466  {
467  badSquares++;
468  }
469  }
470  if(badSquares == 0)
471  {
472  handoutLine = i;
473  }
474  }
475  }
476  if(handoutLine >= 0)
477  {
478  //kDebug() << "Hard hearted handout at" << opponentChain.at(handoutLine);
479  QList<int> retMove;
480  retMove.append(opponentChain.at(handoutLine));
481  return retMove;
482  }
483  }
484 
485  // fallback to middle ai move
486  QList<int> bestMoves = linePointDamage.values(linePointDamage.begin().key()); //this is a list of the indices of the lines that are the least damaging. linePointDamage.begin() returns the 1st pair in the QMap, sorted in ascending order by Key (damage of move)
487  return bestMoves;
488 }
489 
490 int aiController::countBorderLines(int *sidesOfSquare, int squareIndex, const bool *linesList) const
491 {
492  int count = 0;
493 
494  linesFromSquare(sidesOfSquare, squareIndex);
495 
496  //TODO: replace this with a QList 'count' type function?
497  if(linesList[sidesOfSquare[0]] == true)
498  count++;
499  if(linesList[sidesOfSquare[1]] == true)
500  count++;
501  if(linesList[sidesOfSquare[2]] == true)
502  count++;
503  if(linesList[sidesOfSquare[3]] == true)
504  count++;
505  //kDebug() << "AI: Square" << squareIndex << "is bordered by" << count << "lines";
506  return count;
507 }
508 
509 int aiController::countBorderLines(int squareIndex, const bool *linesList) const
510 {
511  int tempLineList[4];
512  return countBorderLines(tempLineList, squareIndex, linesList);
513 }
514 
515 QList<int> aiController::squaresFromLine(int lineIndex) const
516 {
517  //kDebug() << "Line:" << lineIndex;
518  QList<int> squareList;
519  if (lineDirection(lineIndex) == KSquares::HORIZONTAL)
520  {
521  squareList.append(lineIndex - ( (width+1) * (lineIndex/((width*2)+1)) ));
522  squareList.append(squareList.at(0) - width);
523  if(squareList.at(1) < 0)
524  squareList.removeAt(1);
525  if(squareList.at(0) >= (width*height))
526  squareList.removeAt(0);
527 
528  }
529  else if (lineDirection(lineIndex) == KSquares::VERTICAL)
530  {
531  squareList.append(lineIndex - ( (lineIndex/((width*2)+1))*width + (lineIndex/((width*2)+1)) + width ));
532  squareList.append(squareList.at(0) - 1);
533  if(lineIndex%((2*width)+1) == width)
534  squareList.removeAt(1);
535  if(lineIndex%((2*width)+1) == 2*width)
536  squareList.removeAt(0);
537  }
538  //kDebug() << "Size:" << squareList.size();
539  //kDebug() << "squares:" << squareList.at(0) << " " << squareList.at(1);
540  return squareList;
541 }
542 
543 void aiController::linesFromSquare(int *linesFromSquare, int squareIndex) const
544 {
545  int index1 = (squareIndex/width) * ((2*width) + 1) + (squareIndex%width);
546  int index2 = index1 + width;
547  int index3 = index2 + 1;
548  int index4 = index3 + width;
549  linesFromSquare[0] = index1;
550  linesFromSquare[1] = index2;
551  linesFromSquare[2] = index3;
552  linesFromSquare[3] = index4;
553 }
554 
555 KSquares::Direction aiController::lineDirection(int lineIndex) const
556 {
557  int index2 = lineIndex % ((2*width) + 1);
558  KSquares::Direction dir;
559  if(index2 < width)
560  dir = KSquares::HORIZONTAL;
561  else
562  dir = KSquares::VERTICAL;
563 
564  return dir;
565 }
QList::clear
void clear()
aiController::linesFromSquare
void linesFromSquare(int *sidesOfSquare, int squareIndex) const
Definition: aicontroller.cpp:543
QMap::values
QList< T > values() const
QSet::size
int size() const
aiController::safeMoves
QList< int > safeMoves() const
Definition: aicontroller.cpp:152
QList::at
const T & at(int i) const
QMap
QList::removeAt
void removeAt(int i)
KSquares::VERTICAL
Definition: aicontroller.h:15
QSet::insert
const_iterator insert(const T &value)
QList::size
int size() const
KSquares::HORIZONTAL
Definition: aicontroller.h:15
aiController::lineDirection
KSquares::Direction lineDirection(int lineIndex) const
Definition: aicontroller.cpp:555
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
QMap::insertMulti
iterator insertMulti(const Key &key, const T &value)
aiController::lines
bool * lines
Definition: aicontroller.h:112
QMapIterator
QSet::values
QList< T > values() const
QMapIterator::next
Item next()
aiController::squaresFromLine
QList< int > squaresFromLine(int lineIndex) const
Definition: aicontroller.cpp:515
QList::isEmpty
bool isEmpty() const
aiController::~aiController
~aiController()
Definition: aicontroller.cpp:28
QSet
QList< bool >
Settings::difficulty
static int difficulty()
Get Difficulty.
Definition: settings.h:144
QMapIterator::key
const Key & key() const
QMapIterator::value
const T & value() const
QMap::begin
iterator begin()
aiController::height
int height
Height of the game board.
Definition: aicontroller.h:118
QScopedPointer::data
T * data() const
QSet::contains
bool contains(const T &value) const
aiController::countBorderLines
int countBorderLines(int squareIndex, const bool *linesList) const
Definition: aicontroller.cpp:509
aicontroller.h
settings.h
aiController::autoFill
QList< int > autoFill(int safeMovesLeft)
Finds lines that can be filled without causing squares to be surrounded by 3 lines as a result...
Definition: aicontroller.cpp:33
KSquares::Direction
Direction
Definition: aicontroller.h:15
QScopedArrayPointer
aiController::width
int width
Width of the game board.
Definition: aicontroller.h:116
QMap::insert
iterator insert(const Key &key, const T &value)
aiController::linesSize
int linesSize
List of which lines are complete.
Definition: aicontroller.h:111
aiController::squareOwners
QList< int > squareOwners
List of the owners of each square.
Definition: aicontroller.h:109
aiController::aiController
aiController(int newPlayerId, const QList< bool > &newLines, const QList< int > &newSquareOwners, int newWidth, int newHeight)
Create a new AI controller.
Definition: aicontroller.cpp:19
aiController::chooseLine
int chooseLine() const
Choses where to draw the line: Creates a list of all the squares which are surrounded by 3 lines and ...
Definition: aicontroller.cpp:59
aiController::chooseLeastDamaging
QList< int > chooseLeastDamaging(const QList< int > &choiceList) const
Definition: aicontroller.cpp:178
QMapIterator::hasNext
bool hasNext() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:18:39 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

ksquares

Skip menu "ksquares"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegames API Reference

Skip menu "kdegames API Reference"
  • granatier
  • kapman
  • kblackbox
  • kgoldrunner
  • kigo
  • kmahjongg
  • KShisen
  • ksquares
  • libkdegames
  •   highscore
  •   libkdegamesprivate
  •     kgame
  • libkmahjongg
  • palapeli
  •   libpala

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal