File indexing completed on 2024-04-28 04:01:56

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 }