File indexing completed on 2024-05-12 07:58:30
0001 /*************************************************************************** 0002 * KBlocks, a falling blocks game by KDE * 0003 * SPDX-FileCopyrightText: 2010 University Freiburg <squall.leonhart.cai@gmail.com> * 0004 * * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 ***************************************************************************/ 0007 #include "KBlocksAIEvaluation.h" 0008 #include "KBlocksAIFeature.h" 0009 #include "KBlocksAILog.h" 0010 0011 /****************************************************************************** 0012 ******** Aggregate Function ********************************************** 0013 *******************************************************************************/ 0014 struct SFeature { 0015 SpecialFeatureEnumeration id; 0016 double weight; 0017 }; 0018 struct Feature { 0019 FeatureEnumeration id; 0020 double weight; 0021 }; 0022 0023 bool getDecisionFeature(const DecisionFeatureEnumeration id, KBlocksField *field) 0024 { 0025 bool result = false; 0026 0027 switch (id) { 0028 case DF_HEIGHT_MAX: 0029 set_ground_line(0); 0030 update_board_signature(field); 0031 result = (getFeature(FEATURE_MAX_HEIGHT, field) > (field->getHeight() * 0.6)); 0032 break; 0033 0034 case DF_PEEKS_COUNT: 0035 set_ground_line(0); 0036 update_board_signature(field); 0037 result = (getFeature(FEATURE_NARROW_COUNT, field) >= 2); 0038 break; 0039 0040 case DF_BLOCK_SCAN: 0041 set_ground_line(0); 0042 update_board_signature(field); 0043 break; 0044 0045 case DF_DEEP_NARROW: 0046 set_ground_line(0); 0047 update_board_signature(field); 0048 result = ((getFeature(FEATURE_MAX_HEIGHT_DIFFERENT, field) >= 5) && (getFeature(FEATURE_NARROW_COUNT, field) == 1)); 0049 break; 0050 0051 case DF_LAYER_SCAN: 0052 set_ground_line(0); 0053 update_board_signature(field); 0054 result = ((getFeature(FEATURE_MAX_HEIGHT, field) >= 8) && (getFeature(FEATURE_MAX_HEIGHT_DIFFERENT, field) <= 2)); 0055 break; 0056 0057 case DF_CREATING_TETRIS: 0058 set_ground_line(0); 0059 update_board_signature(field); 0060 result = ((getFeature(FEATURE_HOLES_COUNT, field) <= 5) && (getFeature(FEATURE_MAX_HEIGHT, field) <= 6)); 0061 break; 0062 0063 case DF_REMOVE_TETRIS: 0064 set_ground_line(0); 0065 update_board_signature(field); 0066 result = (getFeature(FEATURE_NARROW_COUNT, field) == 1); 0067 break; 0068 0069 default: 0070 break; 0071 } 0072 0073 return result; 0074 } 0075 0076 /*######################################################### 0077 * SECTION ANALYSIS EVALUATION ############################ 0078 *########################################################## */ 0079 HalfBaseEvaluation *HalfBaseEvaluation::_instance = nullptr; 0080 double HalfBaseEvaluation::evaluate(KBlocksField *field) 0081 { 0082 int line = getFeature(FEATURE_MAX_HEIGHT, field) - 6; 0083 if (line < 0) { 0084 line = 0; 0085 } 0086 set_ground_line(line); 0087 return BaseEvaluation::instance()->evaluate(field); 0088 } 0089 /*######################################################### 0090 * BASIC EVALUATION ###################################### 0091 *########################################################## */ 0092 BaseEvaluation *BaseEvaluation::_instance = nullptr; 0093 double BaseEvaluation::evaluate(KBlocksField *field) 0094 { 0095 double res = 0; 0096 Feature features [] = { 0097 {FEATURE_MAX_HEIGHT, -0.05}, 0098 {FEATURE_HOLES_COUNT, -2.25}, 0099 {FEATURE_WEIGHTED_BLOCKS_COUNT, -0.005}, 0100 {FEATURE_MAX_KONTUR_LENGTH, 0.5}, 0101 {FEATURE_MAX_HEIGHT_DIFFERENT, -1}, 0102 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1}, 0103 {FEATURE_BLOCKS_OVER_HOLES_COUNT, -0.01}, 0104 {FEATURE_WELLS_COUNT, -0.01}, 0105 {FEATURE_PREDICTION_COUNT, 0.01}, 0106 {FEATURE_NARROW_COUNT, -5}, 0107 }; 0108 /* 0109 Feature features [] = 0110 { 0111 {FEATURE_MAX_HEIGHT,-1.8}, 0112 {FEATURE_HOLES_COUNT,-2.25 }, 0113 {FEATURE_BLOCKS_COUNT,-0.5}, 0114 {FEATURE_AVERAGE_HEIGHT,-1}, 0115 }; 0116 */ 0117 /* 0118 Feature features [] = 0119 { 0120 {FEATURE_MAX_HEIGHT,-1.5}, 0121 {FEATURE_HOLES_COUNT,-3.25 }, 0122 {FEATURE_BLOCKS_COUNT,-0.005}, 0123 {FEATURE_AVERAGE_HEIGHT,-0.7}, 0124 }; 0125 */ 0126 /* 0127 Feature features [] = 0128 { 0129 {FEATURE_MAX_HEIGHT,-2.5}, 0130 {FEATURE_HOLES_COUNT,-1.25 }, 0131 {FEATURE_BLOCKS_COUNT,-0.005}, 0132 {FEATURE_AVERAGE_HEIGHT,-1}, 0133 }; 0134 */ 0135 /* 0136 0137 Feature features [] = 0138 { 0139 {FEATURE_MAX_HEIGHT,-1.5}, 0140 {FEATURE_HOLES_COUNT,-3.25 }, 0141 {FEATURE_BLOCKS_COUNT,-0.005}, 0142 {FEATURE_AVERAGE_HEIGHT,-0.7}, 0143 {FEATURE_NARROW_COUNT,-20}, 0144 }; 0145 */ 0146 /* 0147 Feature features [] = 0148 { 0149 {FEATURE_MAX_HEIGHT,-1.5}, 0150 {FEATURE_HOLES_COUNT,-3.25 }, 0151 {FEATURE_BLOCKS_COUNT,-0.005}, 0152 {FEATURE_AVERAGE_HEIGHT,-0.7}, 0153 {FEATURE_NARROW_COUNT,-20}, 0154 {FEATURE_MAX_HEIGHT_DIFFERENT,-3}, 0155 }; 0156 */ 0157 /* 0158 Feature features [] = 0159 { 0160 {FEATURE_MAX_HEIGHT,-1.5}, 0161 {FEATURE_HOLES_COUNT,-3.25 }, 0162 {FEATURE_BLOCKS_COUNT,-0.005}, 0163 {FEATURE_AVERAGE_HEIGHT,-0.7}, 0164 {FEATURE_NARROW_COUNT,-20}, 0165 {FEATURE_MAX_HEIGHT_DIFFERENT,-3}, 0166 {FEATURE_PREDICTION_COUNT,0.005}, 0167 }; 0168 */ 0169 unsigned int n = sizeof(features) / sizeof(Feature); 0170 0171 update_board_signature(field); 0172 0173 for (unsigned int i = 0; i < n; i++) { 0174 res += getFeature(features[i].id, field) * features[i].weight; 0175 } 0176 0177 return res; 0178 } 0179 0180 /*######################################################### 0181 * WELLS STOPPER ########################################## 0182 *########################################################## */ 0183 WellsFillerEvaluation *WellsFillerEvaluation::_instance = nullptr; 0184 double WellsFillerEvaluation::evaluate(KBlocksField *field) 0185 { 0186 double res = 0; 0187 0188 Feature features [] = { 0189 {FEATURE_MAX_KONTUR_LENGTH, 1.0}, 0190 {FEATURE_NARROW_COUNT, -1.0}, 0191 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1.1}, 0192 }; 0193 0194 unsigned int n = sizeof(features) / sizeof(Feature); 0195 0196 update_board_signature(field); 0197 0198 for (unsigned int i = 0; i < n; i++) { 0199 res += getFeature(features[i].id, field) * features[i].weight; 0200 } 0201 0202 return res; 0203 } 0204 0205 /*######################################################### 0206 * HEIGHT ELIMINIATOR ##################################### 0207 *########################################################## */ 0208 HeightKillerEvaluation *HeightKillerEvaluation::_instance = nullptr; 0209 double HeightKillerEvaluation::evaluate(KBlocksField *field) 0210 { 0211 double res = 0; 0212 0213 Feature features [] = { 0214 {FEATURE_MAX_HEIGHT, -2.05}, 0215 {FEATURE_HOLES_COUNT, -1.95}, 0216 {FEATURE_WEIGHTED_BLOCKS_COUNT, -0.05}, 0217 {FEATURE_MAX_HEIGHT_DIFFERENT, -1.0}, 0218 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1}, 0219 {FEATURE_WELLS_COUNT, -0.01}, 0220 {FEATURE_PREDICTION_COUNT, 0.001}, 0221 }; 0222 0223 unsigned int n = sizeof(features) / sizeof(Feature); 0224 0225 update_board_signature(field); 0226 0227 for (unsigned int i = 0; i < n; i++) { 0228 res += getFeature(features[i].id, field) * features[i].weight; 0229 } 0230 0231 return res; 0232 } 0233 0234 /*######################################################### 0235 * BLOCK ELIMINATION ##################################### 0236 *########################################################## */ 0237 BlockRemoverEvaluation *BlockRemoverEvaluation::_instance = nullptr; 0238 double BlockRemoverEvaluation::evaluate(KBlocksField *field) 0239 { 0240 double res = 0; 0241 0242 // ### reenable the two following #if 0 comments when the features array is not empty 0243 #if 0 0244 Feature features [] = {}; 0245 0246 unsigned int n = sizeof(features) / sizeof(Feature); 0247 #endif 0248 0249 update_board_signature(field); 0250 0251 #if 0 0252 for (unsigned int i = 0; i < n; i++) { 0253 res += getFeature(features[i].id, field) * features[i].weight; 0254 } 0255 #endif 0256 0257 return res; 0258 } 0259 0260 /*######################################################### 0261 * DEEP NARROW ELIMINATION ################################ 0262 *########################################################## */ 0263 DeepNarrowRemoverEvaluation *DeepNarrowRemoverEvaluation::_instance = nullptr; 0264 double DeepNarrowRemoverEvaluation::evaluate(KBlocksField *field) 0265 { 0266 double res = 0; 0267 0268 Feature features [] = { 0269 {FEATURE_MAX_HEIGHT, -1.05}, 0270 {FEATURE_WEIGHTED_BLOCKS_COUNT, -0.15}, 0271 {FEATURE_MAX_KONTUR_LENGTH, 0.5}, 0272 {FEATURE_MAX_HEIGHT_DIFFERENT, -1}, 0273 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1}, 0274 {FEATURE_PREDICTION_COUNT, 0.001}, 0275 }; 0276 0277 unsigned int n = sizeof(features) / sizeof(Feature); 0278 0279 update_board_signature(field); 0280 0281 for (unsigned int i = 0; i < n; i++) { 0282 res += getFeature(features[i].id, field) * features[i].weight; 0283 } 0284 0285 return res; 0286 } 0287 0288 /*######################################################### 0289 * TETRIS CREATOR ######################################## 0290 *########################################################## */ 0291 TetrisPreparingEvaluation *TetrisPreparingEvaluation::_instance = nullptr; 0292 double TetrisPreparingEvaluation::evaluate(KBlocksField *field) 0293 { 0294 double res = 0; 0295 0296 Feature features [] = { 0297 {FEATURE_MAX_HEIGHT, -0.15}, 0298 {FEATURE_HOLES_COUNT, -3.95}, 0299 {FEATURE_MAX_KONTUR_LENGTH, 1.5}, 0300 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1.75}, 0301 {FEATURE_NARROW_COUNT, 0.2}, 0302 {FEATURE_PREDICTION_COUNT, 0.002}, 0303 }; 0304 0305 unsigned int n = sizeof(features) / sizeof(Feature); 0306 0307 update_board_signature(field); 0308 0309 for (unsigned int i = 0; i < n; i++) { 0310 res += getFeature(features[i].id, field) * features[i].weight; 0311 } 0312 0313 return res; 0314 } 0315 0316 /*######################################################### 0317 * TETRIS REMOVER ######################################## 0318 *########################################################## */ 0319 TetrisEliminationEvaluation *TetrisEliminationEvaluation::_instance = nullptr; 0320 double TetrisEliminationEvaluation::evaluate(KBlocksField *field) 0321 { 0322 double res = 0; 0323 0324 Feature features [] = { 0325 {FEATURE_MAX_HEIGHT, -0.75}, 0326 {FEATURE_BLOCKS_COUNT, -2.00}, 0327 {FEATURE_HOLES_COUNT, -1.25}, 0328 {FEATURE_MAX_HEIGHT_DIFFERENT, -1}, 0329 {FEATURE_AVERAGE_HEIGHT_DIFFERENT, -1}, 0330 {FEATURE_NARROW_COUNT, -0.5}, 0331 {FEATURE_PREDICTION_COUNT, 0.002}, 0332 }; 0333 0334 unsigned int n = sizeof(features) / sizeof(Feature); 0335 0336 update_board_signature(field); 0337 0338 for (unsigned int i = 0; i < n; i++) { 0339 res += getFeature(features[i].id, field) * features[i].weight; 0340 } 0341 0342 return res; 0343 } 0344 0345 /*######################################################### 0346 * NBS EVALUATION ######################################### 0347 *########################################################## */ 0348 NBSEvaluation *NBSEvaluation::_instance = nullptr; 0349 double NBSEvaluation::evaluate(KBlocksField *field) 0350 { 0351 Feature features [] = { 0352 {FEATURE_MAX_HEIGHT, -62709}, //1 0353 {FEATURE_HOLES_COUNT, -30271}, //2 0354 {FEATURE_CLOSED_HOLES_COUNT, 0}, //3 0355 {FEATURE_MAX_HEIGHT_DIFFERENT, 35395}, //5 0356 {FEATURE_MAX_WELL_DEPTH, -12}, //6 0357 {FEATURE_WELLS_COUNT, -43810}, //7 0358 {FEATURE_BLOCKS_COUNT, 0}, //9 0359 {FEATURE_WEIGHTED_BLOCKS_COUNT, -4041}, //10 0360 {FEATURE_ROW_TRANSITION_COUNT, -44262}, //11 0361 {FEATURE_COLUMN_TRANSITION_COUNT, -5832}, //12 0362 }; 0363 0364 SFeature sfeatures [] = { 0365 {FEATURE_REMOVE_LINES, 13344}, //4 0366 {FEATURE_LANDING_HEIGHT, 0}, //8 0367 }; 0368 0369 unsigned int n1 = sizeof(features) / sizeof(Feature); 0370 0371 unsigned int n2 = sizeof(sfeatures) / sizeof(SFeature); 0372 0373 update_board_signature(field); 0374 0375 double res = 0; 0376 0377 for (unsigned int i = 0; i < n1; i++) { 0378 res += getFeature(features[i].id, field) * features[i].weight; 0379 } 0380 0381 for (unsigned int i = 0; i < n2; i++) { 0382 res += getSpecialFeature(sfeatures[i].id, field, mpField, mpPiece) * sfeatures[i].weight; 0383 } 0384 0385 return res; 0386 }