ksquares
aicontroller.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "aicontroller.h"
00011
00012 #include <ctime>
00013 #include <kdebug.h>
00014
00015 #include "settings.h"
00016
00017 aiController::aiController(int newPlayerId, const QList<bool> &newLines, const QList<int> &newSquareOwners, int newWidth, int newHeight) : squareOwners(newSquareOwners), lines(newLines), playerId(newPlayerId), width(newWidth), height(newHeight)
00018 {
00019 srand( (unsigned)time( NULL ) );
00020 kDebug() << "AI: Starting AI...";
00021 }
00022
00023 QList<int> aiController::autoFill(int safeMovesLeft)
00024 {
00025 QList<int> fillLines;
00026
00027
00028 QList<int> next;
00029
00030 while( !( (next = safeMoves()).isEmpty() ) )
00031 {
00032 int nextLine = next[rand() % next.size()];
00033 lines[nextLine] = true;
00034
00035 fillLines << nextLine;
00036 }
00037
00038
00039 for (int i = 0; i<safeMovesLeft; ++i)
00040 {
00041 if (fillLines.isEmpty()) break;
00042 int index = rand() % fillLines.size();
00043 fillLines.removeAt(index);
00044 }
00045
00046 return fillLines;
00047 }
00048
00049 int aiController::chooseLine() const
00050 {
00051 QList<int> choiceList;
00052 for(int i=0; i<lines.size(); i++)
00053 {
00054 if(!lines.at(i))
00055 {
00056 QList<int> adjacentSquares = squaresFromLine(i);
00057 for(int j=0; j<adjacentSquares.size(); j++)
00058 {
00059
00060 if(countBorderLines(adjacentSquares.at(j), lines) == 3)
00061 {
00062 choiceList.append(i);
00063
00064 }
00065 }
00066 }
00067 }
00068 if(choiceList.size() != 0)
00069 {
00070 float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
00071 int randChoice = (short)(randomFloat)/1;
00072 kDebug() << "AI: 1. Drawing line at index:" << choiceList.at(randChoice);
00073 return choiceList.at(randChoice);
00074 }
00075
00076 choiceList = safeMoves();
00077
00078 if(choiceList.size() != 0)
00079 {
00080 float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
00081 int randChoice = (short)(randomFloat)/1;
00082 kDebug() << "AI: 2. Drawing line at index:" << choiceList.at(randChoice);
00083 return choiceList.at(randChoice);
00084 }
00085
00086 choiceList.clear();
00087 for(int i=0; i<lines.size(); i++)
00088 {
00089 if(!lines.at(i))
00090 {
00091 QList<int> adjacentSquares = squaresFromLine(i);
00092 for(int j=0; j<adjacentSquares.size(); j++)
00093 {
00094
00095 if(countBorderLines(adjacentSquares.at(j), lines) == 2)
00096 {
00097 choiceList.append(i);
00098
00099 }
00100 }
00101 }
00102 }
00103 if(Settings::difficulty() == 1)
00104 {
00105 QList<int> goodChoiceList = chooseLeastDamaging(choiceList);
00106 if(goodChoiceList.size() != 0)
00107 {
00108 float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(goodChoiceList.size()-1);
00109 int randChoice = (short)(randomFloat)/1;
00110 kDebug() << "AI: 3. Drawing line at index:" << goodChoiceList.at(randChoice);
00111 return goodChoiceList.at(randChoice);
00112 }
00113 }
00114 QList<int> goodcChoiceList = chooseLeastDamaging(choiceList);
00115 if(choiceList.size() != 0)
00116 {
00117 float randomFloat = ((float) rand()/(RAND_MAX + 1.0))*(choiceList.size()-1);
00118 int randChoice = (short)(randomFloat)/1;
00119 kDebug() << "AI: 3. Drawing line at index:" << choiceList.at(randChoice);
00120 return choiceList.at(randChoice);
00121 }
00122 return 0;
00123 }
00124
00125 QList<int> aiController::safeMoves() const
00126 {
00127 QList<int> safeLines;
00128 for(int i=0; i<lines.size(); i++)
00129 {
00130 if(!lines.at(i))
00131 {
00132 QList<int> adjacentSquares = squaresFromLine(i);
00133 int badCount = 0;
00134 for(int j=0; j<adjacentSquares.size(); j++)
00135 {
00136 if(countBorderLines(adjacentSquares.at(j), lines) == 2)
00137 {
00138 badCount++;
00139 }
00140 }
00141 if(badCount == 0)
00142 {
00143 safeLines.append(i);
00144
00145 }
00146 }
00147 }
00148 return safeLines;
00149 }
00150
00151 QList<int> aiController::chooseLeastDamaging(const QList<int> &choiceList) const
00152 {
00153
00154 QMap<int,int> linePointDamage;
00155 for(int i=0; i<choiceList.size(); i++)
00156 {
00157 QList<int> squaresCopy = squareOwners;
00158 QList<bool> linesCopy = lines;
00159 linesCopy[choiceList.at(i)] = true;
00160
00161
00162 int count = 0;
00163 bool squareFound = false;
00164 do
00165 {
00166 for(int currentSquare=0; currentSquare<squaresCopy.size(); currentSquare++)
00167 {
00168 if(countBorderLines(currentSquare, linesCopy) == 3)
00169 {
00170 count++;
00171 squareFound = true;
00172
00173 QList<int> sidesOfSquare = linesFromSquare(currentSquare);
00174 for(int sideOfSquare=0; sideOfSquare<=3; sideOfSquare++)
00175 {
00176 linesCopy[sidesOfSquare.at(sideOfSquare)] = true;
00177
00178 }
00179 break;
00180 }
00181 else
00182 {
00183 squareFound = false;
00184 }
00185 }
00186 } while(squareFound == true);
00187 linePointDamage.insertMulti(count, choiceList.at(i));
00188 }
00189
00190 QList<int> bestMoves = linePointDamage.values(linePointDamage.begin().key());
00191 return bestMoves;
00192 }
00193
00194 int aiController::countBorderLines(int squareIndex, const QList<bool> &linesList) const
00195 {
00196 int count = 0;
00197
00198 QList<int> tempLineList = linesFromSquare(squareIndex);
00199
00200
00201 if(linesList.at(tempLineList.at(0)) == true)
00202 count++;
00203 if(linesList.at(tempLineList.at(1)) == true)
00204 count++;
00205 if(linesList.at(tempLineList.at(2)) == true)
00206 count++;
00207 if(linesList.at(tempLineList.at(3)) == true)
00208 count++;
00209
00210 return count;
00211 }
00212
00213 QList<int> aiController::squaresFromLine(int lineIndex) const
00214 {
00215
00216 QList<int> squareList;
00217 if (lineDirection(lineIndex) == KSquares::HORIZONTAL)
00218 {
00219 squareList.append(lineIndex - ( (width+1) * (lineIndex/((width*2)+1)) ));
00220 squareList.append(squareList.at(0) - width);
00221 if(squareList.at(1) < 0)
00222 squareList.removeAt(1);
00223 if(squareList.at(0) >= (width*height))
00224 squareList.removeAt(0);
00225
00226 }
00227 else if (lineDirection(lineIndex) == KSquares::VERTICAL)
00228 {
00229 squareList.append(lineIndex - ( (lineIndex/((width*2)+1))*width + (lineIndex/((width*2)+1)) + width ));
00230 squareList.append(squareList.at(0) - 1);
00231 if(lineIndex%((2*width)+1) == width)
00232 squareList.removeAt(1);
00233 if(lineIndex%((2*width)+1) == 2*width)
00234 squareList.removeAt(0);
00235 }
00236
00237
00238 return squareList;
00239 }
00240
00241 QList<int> aiController::linesFromSquare(int squareIndex) const
00242 {
00243 QList<int> tempLineList;
00244 int index1 = (squareIndex/width) * ((2*width) + 1) + (squareIndex%width);
00245 int index2 = index1 + width;
00246 int index3 = index2 + 1;
00247 int index4 = index3 + width;
00248 tempLineList.append(index1);
00249 tempLineList.append(index2);
00250 tempLineList.append(index3);
00251 tempLineList.append(index4);
00252 return tempLineList;
00253 }
00254
00255 KSquares::Direction aiController::lineDirection(int lineIndex) const
00256 {
00257 int index2 = lineIndex % ((2*width) + 1);
00258 KSquares::Direction dir;
00259 if(index2 < width)
00260 dir = KSquares::HORIZONTAL;
00261 else
00262 dir = KSquares::VERTICAL;
00263
00264 return dir;
00265 }