IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Choisir une bonne représentation/encapsulation des données


Sujet :

C++

  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut Choisir une bonne représentation/encapsulation des données
    Bonjour,

    Pour la lisibilité du code on parle souvent des commentaires, du nommage des variables et des classes, de la responsabilité unique, etc...

    Mais je n'ai pas souvent entendu parler du choix de la représentation de données.

    Ces derniers jours, je travaillais sur un algorithme assez compliqué et j'ai décidé de faire deux classes :
    TheoricPlinthGroup qui représente un groupe de socle et TheoricPlinth qui représente un socle.
    J'ai essayé de faire en sorte d'accéder le plus facilement aux données en les "dupliquant", en effet, un TheoricPlinth possède la liste de ses TheoricPlinth voisins et TheoricPlinthGroup possède la liste de ses TheoricPlinthGroup voisins ainsi que la liste des TheoricPlinth qui constituent ses frontières avec un autre groupe.

    Lorsque j'ai dû codé cela, ça a été un véritable enfer, pleins de bugs à corriger, etc... :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    class TheoricPlinthGroup
            {
            public:
                enum TeamType {EMPTY, FRIEND, ADV, ADV_LIVING};
                TheoricPlinthGroup(PlinthGroup * group,
                                   std::map<PlinthGroup *, TheoricPlinthGroup *> & link,
                                   TeamType team,
                                   std::set<TheoricPlinthGroup *> & m_list_th_plg);
                TheoricPlinthGroup(TheoricPlinth * th_pl,
                                   std::set<TheoricPlinthGroup *> &frontier,
                                   std::set<TheoricPlinthGroup *> & list_th_plg);
                TheoricPlinthGroup(std::set<TheoricPlinthGroup *> & list_th_plg)
                    : m_team(EMPTY),
                      m_list_th_plg(list_th_plg){ m_list_th_plg.insert(this); }
                ~TheoricPlinthGroup(void);
                static void eatADV(std::set<TheoricPlinthGroup *> &list_th_plg);
                static void eat(TheoricPlinthGroup * );
                static void fill(std::set<TheoricPlinth *> &plinth_to_fill);
                TeamType team(void){ return m_team; }
     
                TheoricPlinthGroup * add(TheoricPlinth * th_pl, std::set<TheoricPlinthGroup *> &frontier,
                                         bool handleSplit = true);
                static TheoricPlinthGroup * fusion(TheoricPlinth * th_pl,
                                                   std::set<TheoricPlinthGroup *> &frontier,
                                                   std::set<TheoricPlinthGroup *> & neight_frontier);
                void movePlinthTo(TheoricPlinth *, TheoricPlinthGroup *, bool handleSplit);
     
                std::set<TheoricPlinthGroup *> & list(void){ return m_list_th_plg; }
     
                static bool canLive(std::set<TheoricPlinthGroup *> & list_th_plg);
            private :
                std::set<TheoricPlinthGroup *> m_neigths;
                TeamType m_team;
                std::map<TheoricPlinthGroup *, std::set<TheoricPlinth *> > m_frontiers;
                std::set<TheoricPlinth *> m_pls;
                std::set<TheoricPlinthGroup *> & m_list_th_plg;
            };
     
            class TheoricPlinth
            {
            public :
                typedef std::set<TheoricPlinth *> Frontier;
                TheoricPlinth(Plinth * pl, TheoricPlinthGroup * gp);
                Frontier *getFrontierWith(TheoricPlinthGroup *gp);
                ~TheoricPlinth(void);
                void eraseMe(TheoricPlinthGroup *);
                void fill(void);
                TheoricPlinthGroup * group(void){ return m_group; }
                void newGroupIs(TheoricPlinthGroup * gp);
                std::set<TheoricPlinthGroup *> frontier(void);
                bool isEye(void);
            private:
                Plinth * m_pl;
                TheoricPlinthGroup * m_group;
                std::map<TheoricPlinthGroup *, Frontier> m_frontier;
                static std::map<Plinth *, TheoricPlinth *> m_real_pls;
            };
     
     
     
     
     
    TheoricPlinthGroup::TheoricPlinthGroup(PlinthGroup * group,
                                                   std::map<PlinthGroup *, TheoricPlinthGroup *> & link,
                                                   TeamType team, std::set<TheoricPlinthGroup *> & list_th_plg)
                : m_team(team),
                  m_list_th_plg(list_th_plg)
            {
                m_list_th_plg.insert(this);
     
                //add plinths
                for(Plinth * pl : group->plinths() )
                    m_pls.insert(new TheoricPlinth(pl, this) );
     
                //add neightbourghood.
                for( PlinthGroup * plg : group->neightbourg() )
                {
                    auto it = link.find(plg);
                    if( it != link.end() )
                    {
                        m_neigths.insert(it->second);
                        it->second->m_neigths.insert(this);
     
                        // search frontier
                        for( TheoricPlinth * th_pl : m_pls)
                        {
                            TheoricPlinth::Frontier * frontier = th_pl->getFrontierWith(it->second);
                            if( frontier )
                            {
                                m_frontiers[it->second].insert(th_pl);
                                for( TheoricPlinth * t_th_pl : *frontier )
                                    it->second->m_frontiers[this].insert(t_th_pl);
                            }
                        }
                    }
                }
                link[group] = this;
            }
     
            TheoricPlinthGroup::TheoricPlinthGroup(TheoricPlinth * th_pl,
                                                   std::set<TheoricPlinthGroup *> & frontier,
                                                   std::set<TheoricPlinthGroup *> &list_th_plg)
                : m_team(FRIEND),
                  m_list_th_plg(list_th_plg)
            {
                m_list_th_plg.insert(this);
                add(th_pl, frontier);
            }
     
            TheoricPlinthGroup * TheoricPlinthGroup::add(TheoricPlinth * th_pl,
                                                         std::set<TheoricPlinthGroup *> & frontier,
                                                         bool handleSplit)
            {
                th_pl->group()->movePlinthTo(th_pl, this, handleSplit);
                m_pls.insert(th_pl);
                m_neigths.insert(frontier.begin(), frontier.end() );
     
                for( TheoricPlinthGroup * th_plg : frontier)
                {
                    m_frontiers[th_plg].insert(th_pl );
                }
     
                return this;
            }
     
            void TheoricPlinthGroup::movePlinthTo(TheoricPlinth * pl, TheoricPlinthGroup * plg,
                                                  bool handleSplit)
            {
                //update frontier group adj.
                std::cerr << m_neigths.size() << std::endl;
                for( TheoricPlinthGroup * th_plg : m_neigths)
                {
                    bool isNeight = false;
     
                    std::set<TheoricPlinth *> list = m_frontiers[this];
     
                    for(TheoricPlinth * th_pl : list)
                    {
                        if( th_pl->getFrontierWith(this)->count(pl) )
                        {
                            if( th_pl->getFrontierWith(this)->size() == 1 )
                            {
                                auto it = th_plg->m_frontiers.find(this);
                                it->second.erase(th_pl);
                                if( ! it->second.size() )
                                    th_plg->m_frontiers.erase(it);
                            }
                            else
                                isNeight = true;
                            if( th_plg != plg)
                                th_plg->m_frontiers[plg].insert( th_pl);
                        }
                        else
                            isNeight = true; // other
                    }
     
                    if( ! isNeight )
                    {
                        th_plg->m_neigths.erase(this);
                        m_neigths.erase(th_plg);
                    }
                }
     
                auto it = m_frontiers.begin();
                auto end = m_frontiers.end();
                while( it != end )
                {
                    auto t_it = it->second.find(pl);
                    if( t_it != it->second.end() )
                    {
                        it->second.erase(t_it);
                    }
                    if( ! it->second.size() )
                        it = m_frontiers.erase(it);
                    else
                        ++it;
                }
     
                TheoricPlinthGroup * oldGroup = pl->group();
                std::cerr << oldGroup << ":" << this << std::endl;
                pl->newGroupIs(plg);
     
                if(handleSplit)
                {
                    auto tbase = pl->getFrontierWith(this);
                    std::set<TheoricPlinth *> base(tbase->begin(), tbase->end() );
                    std::cerr << base.size() << std::endl;
                    if(base.size() > 1)
                    {
                        bool oneGroup = true;
                        while( ! base.empty() )
                        {
                            std::set<TheoricPlinth *> linkedPlinth;
                            std::stack<TheoricPlinth *> plinthToHandle;
                            plinthToHandle.push( *base.begin() );
                            linkedPlinth.insert( *base.begin() );
                            base.erase( base.begin() );
                            std::cerr << "new size" << base.size() << std::endl;
                            while( ! plinthToHandle.empty() )
                            {
                                TheoricPlinth * th_pl = plinthToHandle.top();
                                plinthToHandle.pop();
     
                                for(TheoricPlinth * temp : *th_pl->getFrontierWith(oldGroup) )
                                {
                                    if(linkedPlinth.find(temp) == linkedPlinth.end() )
                                    {
                                        linkedPlinth.insert(temp);
                                        plinthToHandle.push(temp);
                                        base.erase(temp);
                                        std::cerr << "new size" << base.size() << std::endl;
                                        if( oneGroup && base.empty() )
                                            goto end;
                                    }
                                }
                            }
                            if( ! oneGroup)
                            {
                                TheoricPlinthGroup * newG = new TheoricPlinthGroup(oldGroup->m_list_th_plg);
                                for(TheoricPlinth * plinth : linkedPlinth)
                                {
                                    std::set<TheoricPlinthGroup *> front = plinth->frontier();
                                    front.erase(newG);
                                    newG->add(plinth, front,false);
                                }
                            }
                            else
                                oneGroup = false;
                        }
                        end : ;//there is only one group
                    }
                }
     
                m_pls.erase(pl);
     
                if( m_pls.size() == 0)
                    delete this;
            }
     
            TheoricPlinthGroup * TheoricPlinthGroup::fusion(TheoricPlinth * th_pl,
                                                            std::set<TheoricPlinthGroup *> &frontier,
                                                            std::set<TheoricPlinthGroup *> & neight_frontier)
            {
                TheoricPlinthGroup * finalGroup = *neight_frontier.begin();
                finalGroup->add(th_pl, frontier);
     
                // pas très optimisé mais la flemme (et puis c'est trop enquiquinant :cry:)
                for(TheoricPlinthGroup * th_plg : neight_frontier)
                {
                    while( ! th_plg->m_pls.empty() )
                    {
                        TheoricPlinth * pl = *th_plg->m_pls.begin();
                        std::set<TheoricPlinthGroup * > t_frontier;
                        for( TheoricPlinthGroup * plg : pl->frontier() )
                        {
                            if(plg != finalGroup)
                                t_frontier.insert(plg);
                        }
                        finalGroup->add(pl, t_frontier, false );
                    }
                }
     
                return finalGroup;
            }
     
     
            TheoricPlinthGroup::~TheoricPlinthGroup(void)
            {
                m_list_th_plg.erase(this);
                for( TheoricPlinthGroup * th_plg : m_neigths )
                {
                    for( TheoricPlinth * th_pl : th_plg->m_frontiers[this] )
                    {
                        th_pl->eraseMe(this);
                    }
     
                    th_plg->m_neigths.erase(this);
                    th_plg->m_frontiers.erase(this);
                }
     
                for( auto * pl : m_pls)
                {
                    delete pl;
                }
     
            }
     
     
            // if there is more than 2 team, we eat group in randomly order so the result can be false.
            void TheoricPlinthGroup::eatADV(std::set<TheoricPlinthGroup *> & list_th_plg)
            {
                std::set<TheoricPlinthGroup *> groupToDestroy;
                std::set<TheoricPlinthGroup *> createdGroup;
     
                for( TheoricPlinthGroup * th_plg : list_th_plg )
                {
                    if( th_plg->m_team == ADV || th_plg->m_team == ADV_LIVING)
                    {
                        eat(th_plg);
                        if( th_plg->m_team != ADV)
                            groupToDestroy.insert(th_plg);
                    }
                }
     
                list_th_plg.insert(createdGroup.begin(), createdGroup.end());
     
                for( TheoricPlinthGroup * th_plg : groupToDestroy )
                {
                    delete th_plg;
                }
            }
     
            void TheoricPlinthGroup::eat(TheoricPlinthGroup * th_plg )
            {
                std::set<TheoricPlinthGroup *> neights = th_plg->m_neigths;
                std::cerr << "size neights " <<  neights.size();
                for( TheoricPlinthGroup * neight : neights)
                {
                    if(neight->m_team == EMPTY)
                    {
                        std::set<TheoricPlinth *> plinth_to_fill = neight->m_frontiers[th_plg];
                        neight->fill( plinth_to_fill);
                    }
                }
     
                th_plg->m_team = EMPTY;
            }
     
            void TheoricPlinthGroup::fill(std::set<TheoricPlinth *> & plinth_to_fill )
            {
                std::cerr << "plTo " << plinth_to_fill.size() << std::endl;
                for( TheoricPlinth * plinth : plinth_to_fill)
                {
                    plinth->fill();
                }
            }
     
     
            bool TheoricPlinthGroup::canLive(std::set<TheoricPlinthGroup *> & list_th_plg)
            {
                std::set<TheoricPlinth *> frontier;
                for( TheoricPlinthGroup * th_plg : list_th_plg )
                {
                    if( th_plg->team() == FRIEND)
                        continue;
                    for( auto pair : th_plg->m_frontiers )
                        frontier.insert(pair.second.begin(), pair.second.end());
                }
     
                std::cerr << "frontier size() :" <<frontier.size() << std::endl;
     
                std::set<TheoricPlinth *> eyes;
     
                while(frontier.size() + eyes.size() >= 2 &&
                      std::count_if(list_th_plg.begin(),
                                     list_th_plg.end(),
                                     [](TheoricPlinthGroup * th_plg)
                                            { return th_plg->team() == TheoricPlinthGroup::EMPTY; }
                                     )
                     )
                {
                    bool modification = false;
                    auto it = frontier.begin();
                    while(it != frontier.end() )
                    {
                        // search obvious eyes
                        if( (*it)->isEye() )
                        {
                            modification = true;
                            eyes.insert(*it);
     
                            if(eyes.size() >= 2)
                                return true;
                            // fill empty neightbourg
                            for( TheoricPlinthGroup * temp_th_plg : (*it)->frontier() )
                            {
                                if( temp_th_plg->team() == TheoricPlinthGroup::EMPTY)
                                {
                                    TheoricPlinth * adj_plinth = *(*it)->getFrontierWith(temp_th_plg)->begin();
                                    adj_plinth->fill();
                                    frontier.erase(adj_plinth);
                                }
                            }
                            it = frontier.erase(it);
                        }
                        else
                            ++it;
                    }
     
                    //TODO
                    // TODO
                    //TODO fill some empty cases
                    if( ! modification) // if we can't do anything else, they can live for this time.
                        return true;
                    std::cerr << "un tour un !" << std::endl;
                }
                return false;
            }
     
     
            std::map<Plinth *, TheoricPlinth *> TheoricPlinth::m_real_pls;
     
            TheoricPlinth::TheoricPlinth(Plinth * pl, TheoricPlinthGroup * gp)
                : m_pl(pl),
                  m_group(gp)
            {
                m_real_pls[pl] = this;
                for( Plinth * t_pl : pl->neigthbourg() )
                {
                    auto it = m_real_pls.find(t_pl);
                    if( it != m_real_pls.end() )
                    {
                        m_frontier.insert( std::pair<TheoricPlinthGroup *, std::set<TheoricPlinth *>
                                           >(it->second->m_group, std::set<TheoricPlinth *>() ) );
                        auto & set = m_frontier[it->second->m_group];
                        set.insert(it->second);
                        it->second->m_frontier[m_group].insert(this);
                    }
                }
            }
     
     
            TheoricPlinth::~TheoricPlinth(void)
            {
                m_real_pls.erase(m_pl);
            }
     
            void TheoricPlinth::eraseMe(TheoricPlinthGroup * th_plg)
            {
                m_frontier.erase(th_plg);
            }
     
     
            TheoricPlinth::Frontier * TheoricPlinth::getFrontierWith(TheoricPlinthGroup * gp)
            {
                auto it = m_frontier.find(gp);
                if( it == m_frontier.end() )
                    return nullptr;
                return &it->second;
            }
     
            void TheoricPlinth::fill(void)
            {
                if( m_group->team() != TheoricPlinthGroup::EMPTY)
                    return;
     
                std::set<TheoricPlinthGroup *> friend_neight;
                std::set<TheoricPlinthGroup *> frontier;
                for( auto it : m_frontier)
                {
                    frontier.insert(it.first);
                    if( it.first->team() == TheoricPlinthGroup::FRIEND )
                        friend_neight.insert(it.first);
                }
     
                if(friend_neight.size() == 0) //create.
                {
                    new TheoricPlinthGroup(this, frontier, m_group->list() );
                }
                else if( friend_neight.size() == 1) //add
                    (*(friend_neight.begin()))->add(this, frontier);
                else //fusion
                    TheoricPlinthGroup::fusion(this, frontier, friend_neight);
            }
     
            void TheoricPlinth::newGroupIs(TheoricPlinthGroup *gp)
            {
                for( auto pair : m_frontier)
                {
                    for(TheoricPlinth * adj : pair.second)
                    {
                        auto it = adj->m_frontier[m_group].find(this);
                        adj->m_frontier[m_group].erase(it);
                        adj->m_frontier[gp].insert(this);
                    }
                }
     
                m_group = gp;
            }
     
            std::set<TheoricPlinthGroup *> TheoricPlinth::frontier(void)
            {
                std::set<TheoricPlinthGroup *> front;
     
                for(auto pair : m_frontier)
                {
                    front.insert(pair.first);
                }
     
                return front;
            }
     
     
            bool TheoricPlinth::isEye(void)
            {
                if(m_frontier.size() == 1 && m_frontier.begin()->first->team() == TheoricPlinthGroup::FRIEND)
                    return true;
     
                TheoricPlinth * pl = nullptr;
                auto fr = frontier();
                auto it = fr.begin();
                auto end = fr.end();
                while( !pl && it != end)
                {
                    if( (*it)->team() == TheoricPlinthGroup::EMPTY)
                    {
                        Frontier * fr = getFrontierWith(*it);
                        if( fr->size() > 1)
                            return false;
                        pl = *fr->begin();
                    }
                    ++it;
                }
                if( !pl )
                    return false;
     
                auto frontier1 = frontier();
                auto frontier2 = pl->frontier() ;
                if( std::includes(frontier2.begin(), frontier2.end(),
                                  frontier1.begin(), frontier1.end()) )
                        return true;
     
                return false;
            }
    J'ai alors décidé de changer la représentation de ces donnée en ne créant qu'une instance de TheoricPlinthGroup qui stocke un vector de ThPlinth et ces ThPlinth contiennent l'identifiant du groupe auquels ils sont liés.
    Il y a déjà moins de duplication d'informations, il y a déjà beaucoup moins d'instance mais à première vue les informations sont "plus difficile d'accès".
    Mais à ma grande surprise, l'implémentation des fonctions a été beaucoup plus facile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    class PlinthGroup;
     
            class TheoricPlinthGroup
            {
            private :
                struct ThPlinth;
            public :
                //first bit is for frontier (1) or not(0) -only into ThPlinth-
                typedef uint16_t IdPlinth;
     
                // first bit is for empty (0) or plain (1) -only into ThPlinth-
                typedef uint16_t IdGp;
     
     
                TheoricPlinthGroup(const PlinthGroup & plinth, const std::set<PlinthGroup *> &living,
                                   unsigned int nbMaxPlinth);
                bool canLive(void);
     
                ThPlinth & getPlinth(IdPlinth id){ return m_plinths[id & MASK_ID]; }
                const ThPlinth & getPlinth(IdPlinth id) const { return m_plinths[id & MASK_ID]; }
     
                IdGp newIdGp(void){ return gpMax++; }
     
                void changeGpTo( IdGp old, IdGp current );
                bool isObviousEye(void);
                void setNewGroupTo(const std::set<IdPlinth> & plinths);
     
                bool groupHasOtherNeightbourg(IdGp gp, std::set<IdPlinth> & neightbourg );
            private:
                void createPlinths(const PlinthGroup & plinth, const std::set<PlinthGroup *> &living);
                void buildGroupAndNeightbourghood(void);
     
                IdGp gpMax = 0;
     
                enum{ MASK_ID = 0x7FFF, MASK_EMPTY = 0x8000, MASK_FRONTIER = 0x8000};
     
                struct ThPlinth
                {
                public :
                    class Iterator;
     
                    Iterator begin();
                    Iterator end();
     
                    IdPlinth id(void) const { return m_id & MASK_ID; }
                    bool empty(void) const { return ! (m_group & MASK_EMPTY); }
                    IdGp group(void) const { return m_group & MASK_ID; }
                    IdPlinth operator[](unsigned int i) const{ return m_neightbourg[i] & MASK_ID; }
                    unsigned int nbNeightbourg(void) const { return m_neightbourg.size(); }
                    void create(const std::set<IdPlinth> & neights, IdPlinth id,
                                bool empty, TheoricPlinthGroup * th_plg);
                    void setGroup(IdGp id){ m_group = (id & MASK_ID) | (m_group & MASK_EMPTY) ; }
                    void setFrontier(IdPlinth id);
                    void makeEye(void);
                    void fill(void);
                    bool isObviousEye(void) const;
                    std::set<IdPlinth> searchAllPlinthLinkTo(IdPlinth id,
                                                            std::set<IdPlinth> exceptions = std::set<IdPlinth>())
                                                            const;
                    bool cantBeEye(void);
                    static bool areNeightbourg(ThPlinth & a, ThPlinth & b);
     
                    static bool areNeightbourg(IdPlinth id_a, IdPlinth id_b,
                                               TheoricPlinthGroup &th_plg);
                    bool isFrontier(void){ return m_id & MASK_FRONTIER; }
                    bool isFrontierWith(unsigned int index){ return m_neightbourg[index] & MASK_FRONTIER; }
                private :
                    std::vector<IdPlinth> m_neightbourg;
                    IdGp m_group;
                    IdPlinth m_id;
                    TheoricPlinthGroup * m_th_plg;
     
                };
     
                std::vector< ThPlinth > m_plinths;
     
            };
     
            class TheoricPlinthGroup::ThPlinth::Iterator
            {
            public :
                TheoricPlinthGroup::IdPlinth operator*(void) const{ return (*m_ptr)[m_position]; }
                Iterator & operator++(void);
                Iterator & operator--(void);
                Iterator & operator-=(unsigned int i);
                Iterator & operator+=(unsigned int i);
                bool operator==(const Iterator & other) const { return m_ptr == other.m_ptr
                                                                       && m_position == other.m_position; }
                bool operator!=(const Iterator & other) const { return ! (*this == other); }
                uint8_t operator-(const Iterator & other) const{ return m_position - other.m_position; }
            private:
                ThPlinth * m_ptr;
                uint8_t m_position;
                Iterator(ThPlinth * ptr, int8_t position)
                    : m_ptr(ptr),
                      m_position(position)
                {}
                friend class ThPlinth;
            public :
                 bool isFrontierWith(void){ return m_ptr->isFrontierWith(m_position); }
            };
     
     
     
    TheoricPlinthGroup::TheoricPlinthGroup(const PlinthGroup & plg,
                                                   const std::set<PlinthGroup *> & living,
                                                   unsigned int nbMaxPlinth)
                : m_plinths(nbMaxPlinth)
            {
                createPlinths(plg, living);
     
                std::set<IdPlinth> id;
                int i = 0, j = 0;
                for( ThPlinth & th_pl : m_plinths )
                {
                    if( th_pl.empty() )
                    {
                        id.insert( th_pl.id() );
                        ++i;
                    }
                    ++j;
                }
     
                buildGroupAndNeightbourghood();
            }
     
            void TheoricPlinthGroup::createPlinths(const PlinthGroup & plg,
                                                   const std::set<PlinthGroup *> &living)
            {
                std::map<Plinth *, IdPlinth> getPlinth;
                std::stack<Plinth *> toHandle;
                const auto player = plg.player();
                Plinth * first = *plg.plinths().begin();
                IdPlinth id = 0;
     
                toHandle.push(first);
                getPlinth[first] = id++;
     
                while( ! toHandle.empty() )
                {
                    Plinth * handled = toHandle.top();
                    toHandle.pop();
     
                    bool nextAdv = false;
                    std::set<IdPlinth> neights;
     
                    for( Plinth * neight : handled->neigthbourg() )
                    {
                        if(neight->group()->player()
                                && neight->group()->player() != player)
                        {
                            nextAdv = true;
                            // we do not handle adv. living group.
                            if( living.find(neight->group()) != living.end() )
                                continue;
                        }
                        //add  to be handle
                        auto it = getPlinth.find(neight);
                        if( it == getPlinth.end() )
                        {
                            getPlinth[neight] = id;
                            neights.insert(id);
                            toHandle.push(neight);
                            ++id;
                        }
                        else
                            neights.insert(it->second);
                    }
                    IdPlinth myId = getPlinth[handled];
     
                    bool empty = (! nextAdv) && handled->group()->player() != player;
     
                    m_plinths[myId].create(neights, myId, empty, this);
                }
            }
     
     
            void TheoricPlinthGroup::buildGroupAndNeightbourghood(void)
            {
                std::set<IdPlinth> notHandled;
                for(IdPlinth id = 0; id != m_plinths.size() ; ++id)
                    notHandled.insert(id);
     
                while( ! notHandled.empty() )
                { // we create a new group
                    std::stack<IdPlinth> toHandle;
                    auto it = notHandled.begin();
     
                    toHandle.push( *it );
                    notHandled.erase(it);
                    while( ! toHandle.empty() )
                    {
                        IdPlinth handled = toHandle.top();
                        toHandle.pop();
                        ThPlinth & pl = m_plinths[handled];
     
                        for( IdPlinth neightbourg : pl)
                        {
                            if( m_plinths[neightbourg].empty() != pl.empty() )//frontier
                            {
                                pl.setFrontier(neightbourg);
                            }
                            else //same group
                            {
                                if( notHandled.find(neightbourg) != notHandled.end() )
                                {
                                    toHandle.push(neightbourg);
                                    notHandled.erase(neightbourg);
                                }
                            }
                        }
     
                        pl.setGroup(gpMax);
                    }
     
                    gpMax++; // we created a new group
                }
            }
     
            bool TheoricPlinthGroup::canLive(void)
            {
                unsigned int nbEye = 0;
                std::set<IdPlinth> emptyPlinth;
     
                for( ThPlinth & th_pl : m_plinths )
                    if( th_pl.empty() )
                        emptyPlinth.insert( th_pl.id() );
     
                bool modify = true;
     
                auto canLive = [&emptyPlinth, &nbEye, this]()
                {
                    int nbPossibleEye = emptyPlinth.size();
                    if(emptyPlinth.size() == 2)
                    {
                        if( ThPlinth::areNeightbourg( *(emptyPlinth.begin()), // first PlinthId
                                                      *(++emptyPlinth.begin()), // second PlinthId
                                                      *this) )
                            nbPossibleEye--;
                    }
                    return nbPossibleEye + nbEye >= 2;
                };
     
                while( canLive() && modify )
                {
                    modify = false;
                    auto it = emptyPlinth.begin();
                    while( it != emptyPlinth.end() )
                    {
                        ThPlinth & th_pl = m_plinths[*it];
                        if( th_pl.isObviousEye() )
                        {
                            modify = true;
                            th_pl.makeEye();
                            nbEye++;
                            for(IdPlinth neight : th_pl)
                                emptyPlinth.erase(neight);
                            if(nbEye >= 2)
                                return true;
                        }
                        else
                        {
                            bool test = th_pl.cantBeEye();
                            if( test )
                            {
                                th_pl.fill();
                                emptyPlinth.erase(th_pl.id());
                                modify = true;
                            }
                        }
                        ++it;
                    }
                }
     
                return ! modify; // modify = false <=> emptyPlinth.size() + nbEye < 2 <=> can't live
            }
     
            void TheoricPlinthGroup::changeGpTo( IdGp old, IdGp current )
            {
                for( ThPlinth & plinth : m_plinths )
                {
                    if( plinth.group() == old )
                        plinth.setGroup(current);
                }
            }
     
            void TheoricPlinthGroup::setNewGroupTo(const std::set<IdPlinth> & plinths)
            {
                IdGp newId = newIdGp();
                for( IdPlinth id : plinths )
                    m_plinths[id & MASK_ID].setGroup(newId);
            }
     
            bool TheoricPlinthGroup::groupHasOtherNeightbourg(IdGp gp, std::set<IdPlinth> & neightbourg )
            {
                for( ThPlinth & th_pl : m_plinths )
                {
                    if( th_pl.group() == (gp & MASK_ID) && th_pl.isFrontier() ) // we search the group's plinths
                    {
                        auto it = th_pl.begin();                auto end = th_pl.end();
                        auto it_set = neightbourg.begin();      auto it_end = neightbourg.end();
                        while( it != end )
                        {
                            if( it.isFrontierWith() )
                            {
                                while(it_set != it_end && *it > *it_set ) it_set++;//TODO
                                if( it_set == it_end || *it != *it_set)
                                    return true;// if the frontier isn't in neightbourg, return true
                            }
                            ++it;
                        }
                    }
                }
     
                return false;
            }
     
            void TheoricPlinthGroup::ThPlinth::setFrontier(TheoricPlinthGroup::IdPlinth id)
            {
                m_id |= TheoricPlinthGroup::MASK_FRONTIER;
                int i = 0;
                while( (m_neightbourg[i] & TheoricPlinthGroup::MASK_ID) != id ) ++i;
                m_neightbourg[i] | TheoricPlinthGroup::MASK_FRONTIER;
            }
     
     
            bool TheoricPlinthGroup::ThPlinth::isObviousEye(void) const
            {
                std::set<TheoricPlinthGroup::IdPlinth> gp_adj;
                bool haveOneFriend = false;
                TheoricPlinthGroup::IdPlinth theFriend = 0;
     
                for( TheoricPlinthGroup::IdPlinth id : m_neightbourg )
                {
                    if( ! id & TheoricPlinthGroup::MASK_FRONTIER ) // a friend
                    {
                        if( haveOneFriend )
                            // a return into a for isn't "good" but I'm too lazy to make a while loop.
                            return false;
                        else
                        {
                            haveOneFriend = true;
                            theFriend = id;
                        }
                    }
                    else
                    {
                        gp_adj.insert(id);
                    }
     
                }
     
                if( gp_adj.size() <= 1 )
                    return true;
                if( haveOneFriend )
                {
                    auto & first = m_th_plg->getPlinth(theFriend).m_neightbourg;
                    return std::includes( first.begin(), first.end(), gp_adj.begin(), gp_adj.end(),
                                          [](const TheoricPlinthGroup::IdPlinth & a,
                                             const TheoricPlinthGroup::IdPlinth & b)
                                        { return (a & TheoricPlinthGroup::MASK_ID)
                                               < (b & TheoricPlinthGroup::MASK_ID); } );
                }
     
                return false;
            }
     
            void TheoricPlinthGroup::ThPlinth::makeEye(void)
            {
                for( TheoricPlinthGroup::IdPlinth id : *this )
                {
                    m_th_plg->getPlinth(id).fill();
                }
            }
     
            void TheoricPlinthGroup::ThPlinth::fill(void)
            {
                if( m_group & TheoricPlinthGroup::MASK_EMPTY ) // if already plain
                    return;
     
                bool frontier = false;
                int i = 0;
                TheoricPlinthGroup::IdPlinth oldGroup = m_group;
     
                std::set<TheoricPlinthGroup::IdPlinth> plinthInTheFirstEmptyGroup;
     
                for( IdPlinth & id : m_neightbourg )
                {
                    ThPlinth & th_pl = m_th_plg->getPlinth(id);
     
                    if( id & TheoricPlinthGroup::MASK_FRONTIER ) // plain neightbourg
                    {
                        if( oldGroup == m_group ) // add a plinth to a group
                        {
                            m_group = th_pl.m_group;
                        }
                        else
                            m_th_plg->changeGpTo(th_pl.m_group, m_group);// "fusion"
                    }
                    else
                    {
                        frontier = true;
     
                        // we don't care about that but if I decide to use it instead of PlinthGroup, I will need
                        // it.
                        if( (oldGroup & TheoricPlinthGroup::MASK_ID) == m_th_plg->getPlinth(id).group() )
                        {
                            if( plinthInTheFirstEmptyGroup.empty() )
                            {
                                plinthInTheFirstEmptyGroup = \
                                        searchAllPlinthLinkTo(id, {m_id} );
                            }
                            else if( plinthInTheFirstEmptyGroup.find(id) == plinthInTheFirstEmptyGroup.end() )
                            { // create a new group, this plinth isn't link to the old group.
                                m_th_plg->setNewGroupTo( searchAllPlinthLinkTo(id, {m_id}) );
                            }
                        } // else the group has already handled.
                    }
                    // a frontier become an unfrontier and an unfrontier becaume a frontier.
                    id = ( id & TheoricPlinthGroup::MASK_ID ) | ( ~id & TheoricPlinthGroup::MASK_FRONTIER );
     
                    bool adj_frontier = false;
                    for( IdPlinth & id_pl : th_pl.m_neightbourg )
                    {
                        // for update frontier flag
                        if( ( id_pl & TheoricPlinthGroup::MASK_ID ) == ( m_id & TheoricPlinthGroup::MASK_ID ) )
                            id_pl = ( id_pl & TheoricPlinthGroup::MASK_ID )
                                    | ( ~id_pl & TheoricPlinthGroup::MASK_FRONTIER );
     
                        // for update frontier flag
                        if( id_pl & TheoricPlinthGroup::MASK_FRONTIER )
                            adj_frontier = true;
                    }
                    //update frontier flag
                    th_pl.m_id = ( th_pl.m_id & TheoricPlinthGroup::MASK_ID )
                            | (adj_frontier ? TheoricPlinthGroup::MASK_FRONTIER : 0);
                    i++;
                }
     
                // create a new group
                if( m_group == oldGroup )
                    m_group = m_th_plg->newIdGp() | TheoricPlinthGroup::MASK_EMPTY;
     
                // update frontier flag
                m_id = ( m_id & TheoricPlinthGroup::MASK_ID )
                        | (frontier ? TheoricPlinthGroup::MASK_FRONTIER : 0);
            }
     
            void TheoricPlinthGroup::ThPlinth::create(const std::set<TheoricPlinthGroup::IdPlinth> & neights,
                                                      TheoricPlinthGroup::IdPlinth id,
                                                      bool empty, TheoricPlinthGroup *th_plg)
            {
                m_id = id;
                m_neightbourg.insert(m_neightbourg.begin(), neights.begin(), neights.end() );
                m_group = empty ? 0 : TheoricPlinthGroup::MASK_EMPTY;
                m_th_plg = th_plg;
            }
     
            std::set<TheoricPlinthGroup::IdPlinth> \
                TheoricPlinthGroup::ThPlinth::searchAllPlinthLinkTo(TheoricPlinthGroup::IdPlinth id,
                                                                std::set<TheoricPlinthGroup::IdPlinth> exceptions)
                                                                    const
            {
                std::set<TheoricPlinthGroup::IdPlinth> found;
                found.insert(id & TheoricPlinthGroup::MASK_ID);
                std::stack<TheoricPlinthGroup::IdPlinth> toHandle;
                toHandle.push(id & TheoricPlinthGroup::MASK_ID);
     
                while( ! toHandle.empty() )
                {
                    TheoricPlinthGroup::IdPlinth handled = toHandle.top();
                    toHandle.pop();
                    TheoricPlinthGroup::ThPlinth & plinth = m_th_plg->getPlinth(handled);
                    for( TheoricPlinthGroup::IdPlinth neight : plinth.m_neightbourg )
                    {
                        TheoricPlinthGroup::IdPlinth neight_id = neight & TheoricPlinthGroup::MASK_ID;
                        if( ! neight & TheoricPlinthGroup::MASK_FRONTIER //if friend
                          && found.find(neight_id) == found.end()
                          && exceptions.find(neight_id) == exceptions.end() )
                        {
                            found.insert(neight_id);
                            toHandle.push(neight_id);
                        }
                    }
                }
     
                return found;
            }
     
            bool TheoricPlinthGroup::ThPlinth::areNeightbourg(ThPlinth & a, ThPlinth & b)
            {
                for( IdPlinth id : a)
                    if(id == b.id() )
                        return true; // not good to do
                return false;
            }
     
            bool TheoricPlinthGroup::ThPlinth::areNeightbourg(IdPlinth id_a, IdPlinth id_b,
                                                              TheoricPlinthGroup & th_plg)
            {
                return areNeightbourg(th_plg.getPlinth(id_a), th_plg.getPlinth(id_b));
            }
     
     
            bool TheoricPlinthGroup::ThPlinth::cantBeEye(void) // bug
            {
                std::set<TheoricPlinthGroup::IdPlinth> empty;
                std::list<std::set<TheoricPlinthGroup::IdGp> > plain;
                plain.push_back(std::set<TheoricPlinthGroup::IdGp>());
     
                for( TheoricPlinthGroup::IdPlinth id : m_neightbourg )
                    if( ! (id & TheoricPlinthGroup::MASK_FRONTIER) ) // if same group
                        empty.insert(id & TheoricPlinthGroup::MASK_ID);
                    else
                        plain.front().insert(id & TheoricPlinthGroup::MASK_ID);
     
                bool oneIsPlain = false;
     
                for( TheoricPlinthGroup::IdPlinth id : empty)
                {
                    plain.push_back( std::set<TheoricPlinthGroup::IdGp>() );
                    TheoricPlinthGroup::ThPlinth & th_pl = m_th_plg->getPlinth(id);
                    for( TheoricPlinthGroup::IdPlinth id_pl : th_pl.m_neightbourg )
                    {
     
                        if( id_pl & TheoricPlinthGroup::MASK_FRONTIER ) // if plain
                        {
                            plain.back().insert(id_pl & TheoricPlinthGroup::MASK_ID);
                            oneIsPlain = true;
                        }
                    }
                }
     
                if( ! oneIsPlain )
                    return false;
     
                // fusion the plain set which are one same plain group
                auto it = plain.begin();
                while( it != plain.end() )
                {
                    auto it2 = it;
                    while( ++it2 != plain.end() )
                    {
                        auto it_a = it->begin();   auto end_a = it->end();
                        auto it_b = it2->begin();  auto end_b = it2->end();
                        while( it_a != end_a )
                        {
                            while( it_b != end_b && *it_b < *it_a) ++it_b;
                            if( *it_a == *it_b)
                                break;
                            it_a++;
                        }
     
                        if( it_a != end_a )
                        {
                            for( TheoricPlinthGroup::IdGp id_gp : *it )
                                it2->insert(id_gp);
                            it = plain.erase(it);
                            break;
                        }
                    }
                    ++it;
                }
     
                empty.insert(m_id & TheoricPlinthGroup::MASK_ID);
     
                for( std::set<TheoricPlinthGroup::IdGp> & listGroup : plain )
                {
                    bool hasOtherFreedom = false;
     
                    for( TheoricPlinthGroup::IdGp group : listGroup )
                    {
                        // search frontier
                        if( m_th_plg->groupHasOtherNeightbourg(group, empty) )
                            hasOtherFreedom = true;
                    }
     
                    if( ! hasOtherFreedom )
                        return true;
                }
                // 1 - L2 = trouver voisins "vides"
                // 2 - (L1) = liste des voisins "plein" et des voisins "pleins" des voisins "vides"
                // -- plusieurs listes selon les fusions
                // 3 - L3 = Chercher la liste des voisins vides de L1.
                // Si L3 = L2 : remplir
                return false;
            }
     
     
     
            TheoricPlinthGroup::ThPlinth::Iterator TheoricPlinthGroup::ThPlinth::begin()
            { return Iterator(this, 0); }
     
            TheoricPlinthGroup::ThPlinth::Iterator TheoricPlinthGroup::ThPlinth::end()
            { return Iterator(this, m_neightbourg.size() ); }
     
            TheoricPlinthGroup::ThPlinth::Iterator & TheoricPlinthGroup::ThPlinth::Iterator::operator++(void)
            {
                if( m_position == m_ptr->nbNeightbourg() )
                    return *this;
                m_position++;
                return *this;
            }
     
            TheoricPlinthGroup::ThPlinth::Iterator & TheoricPlinthGroup::ThPlinth::Iterator::operator--(void)
            {
                if( m_position == m_ptr->nbNeightbourg() )
                    return *this;
                if( m_position)
                    m_position--;
                else
                    m_position = m_ptr->nbNeightbourg();
                return *this;
            }
     
            TheoricPlinthGroup::ThPlinth::Iterator & \
                            TheoricPlinthGroup::ThPlinth::Iterator::operator-=(unsigned int i)
            {
                if( m_position == m_ptr->nbNeightbourg() )
                    return *this;
                if( m_position >= i)
                    m_position-= i;
                else
                    m_position = m_ptr->nbNeightbourg();
                return *this;
            }
     
            TheoricPlinthGroup::ThPlinth::Iterator & \
                            TheoricPlinthGroup::ThPlinth::Iterator::operator+=(unsigned int i)
            {
                if( m_position + i >= m_ptr->nbNeightbourg() )
                    return *this;
                m_position++;
                return *this;
            }

    Mais question serait alors la suivante :
    Comment choisir efficacement la représentation de ses données, l'architecture du "modèle" ?

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    La duplication des données est, rarement, la bonne solution car elle pose énormément de problèmes, ne serait-ce qu'au niveau de la mise à jour des données dupliquées.

    Je crois personnellement que la solution la plus simple est toujours la moins compliquée... heu, pardon : la meilleure.

    Le gros problème est que, bien souvent, la première solution à laquelle on pense est rarement la plus simple

    Cela implique donc qu'il faille, régulièrement, garder l'esprit ouvert à "une autre possibilité à trouver" pour déterminer avec le plus de certitude possible de quelle manière les données seront effectivement représentées

    C'est, d'ailleurs, peut être un des problèmes récurrents de l'approche OO en général (bien que l'on puisse y être confronté dans tous les paradigme), dans le sens où l'on essaye de privilégier l'encapsulation et donc la manière dont les données sont utilisées, bien plus que la manière dont elles sont représentées
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Neckara Voir le message
    TheoricPlinthGroup qui représente un groupe de socle et TheoricPlinth qui représente un socle.
    J'ai essayé de faire en sorte d'accéder le plus facilement aux données en les "dupliquant", en effet, un TheoricPlinth possède la liste de ses TheoricPlinth voisins et TheoricPlinthGroup possède la liste de ses TheoricPlinthGroup voisins ainsi que la liste des TheoricPlinth qui constituent ses frontières avec un autre groupe.
    Ce n'est pas clair. En tout cas moi je ne comprend pas. Je ne sais plus quel forumeur avisé a dans sa signature la phrase suivante (mais je crois qu'il n'est pas loin ):
    "Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément."

    Tu devrais commencer par éclaircir le problème et l'énoncer clairement. Ton problème semble être trop complexe pour être expliqué en 3 phrases.
    Une fois cet exercice brillamment achevé, une solution devrait commencer à émerger d'elle-même.

    Peut-être une piste: généralement, c'est une mauvaise idée que la classe qui stocke les données soit la même qui les manipule. En ça les conteneurs de la STL sont un mauvais exemple, et la présence de la lib <algorithm> est une tentative de correction (A. Alexandrescu, Modern c++ Design, p. 4).
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par r0d Voir le message
    Ce n'est pas clair. En tout cas moi je ne comprend pas. Je ne sais plus quel forumeur avisé a dans sa signature la phrase suivante (mais je crois qu'il n'est pas loin ):
    "Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément."

    Tu devrais commencer par éclaircir le problème et l'énoncer clairement. Ton problème semble être trop complexe pour être expliqué en 3 phrases.
    Une fois cet exercice brillamment achevé, une solution devrait commencer à émerger d'elle-même.
    Je voulais juste donner un exemple sans trop rentrer dans les détails, si je devais vous expliquer l'algorithme ça deviendrait très long
    (L'algorithme ne peut pas être directement codé, il faut passer par des équivalents etc...).

    Là j'ai trouvé une solution et pour le moment elle marche, mais question portait surtout sur le "cas général" au cas où je me retrouve dans une situation similaire (ou plutôt éviter de se reretrouver dans une telle situation).
    Mon code était surtout là pour servir d'exemple.

  5. #5
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Je voulais juste donner un exemple sans trop rentrer dans les détails, si je devais vous expliquer l'algorithme ça deviendrait très long
    (L'algorithme ne peut pas être directement codé, il faut passer par des équivalents etc...).

    Là j'ai trouvé une solution et pour le moment elle marche, mais question portait surtout sur le "cas général" au cas où je me retrouve dans une situation similaire (ou plutôt éviter de se reretrouver dans une telle situation).
    Mon code était surtout là pour servir d'exemple.
    De manière générale, la « simplicité » s’obtient au moyen de fonctions dont la sémantique est claire et pertinente. La représentation des données n’a pas grand chose à voir là-dedans (puisque, dans un monde idéal, l’interface est indépendante de la représentation sous-jacente des données).

    Donc du coup, envisager de dupliquer des données, avec tous les problèmes que ça pose, pour simplifier, c’est faire totalement fausse route de mon point de vue. La question à se poser, c’est « que va m’apporter cette nouvelle représentation que ne me permettait pas la précédente, quitte à ce que je rajoute des fonctions » ? Et dans cette optique, la seule chose qui va t’amener à t’éloigner de la représentation la plus simple, ce sont les performances (certains choix de représentation vont se révéler dramatique de ce point de vue).

  6. #6
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    A ce que j'ai compris, je pencherais pour mettre en priorité l'optimisation ( dans le sens la clarté ) de tes informations en priorité, ensuite l'accès à ces informations est une autre histoire car elle peut dépendre d'une lib externe, d'un post traitement etc... Il vaut mieux souffrir d'une indirection supplémentaire mais être efficace dans le traitement de ses données car elle sont simples à comprendre.
    Donc je dirais oui pour ta deuxième solution, un id pour un groupe, tu peux facilement changer de groupe sans toucher à la représentation du groupe. ( Quand tu tri les déchets tu ne modifies pas la poubelle jaune et la bleu ou verte )

    EDIT: Je le vois au boulot, une architecture de jeu orienté composant est plus lente/lourde pour la machine, mais beaucoup plus facile à traité/modifié/supprimé pour le programmeur car c'est orienté DATA. Un gros travaille est a réalisé sur les algorithmes et le lien entre tout ses objets et composant mais les datas sont simples et modifiable par un non programmeur facilement
    Homer J. Simpson


  7. #7
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par Astraya Voir le message
    EDIT: Je le vois au boulot, une architecture de jeu orienté composant est plus lente/lourde pour la machine, mais beaucoup plus facile à traité/modifié/supprimé pour le programmeur car c'est orienté DATA.
    C'est quand même bizarre cette remarque. J'avais cru comprendre que les archis orienté composant avait justement était crée pour être optimisé sur les machines modernes, car elle se concentre justement sur les données et leur layout en mémoire, pour tirer parti au mieux des caches et des accès mémoires.

  8. #8
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    C'est quand même bizarre cette remarque. J'avais cru comprendre que les archis orienté composant avait justement était crée pour être optimisé sur les machines modernes, car elle se concentre justement sur les données et leur layout en mémoire, pour tirer parti au mieux des caches et des accès mémoires.
    Aussi, bien que il faut faire attention au cache friendly ça peut vite partir en cou... . De plus, un moteur OO est plus lourd qu'un moteur disons "autre" (Comparaison ici (PDF)). Mais sinon c'est principalement dans le but de rendre la vie plus facile pour les autres corps de métier et également la maintenance coté programmeur!
    Une bonne slides qui parle de ça ci tu veux lire un peu ^^
    http://fr.slideshare.net/KostasAnagn...me-development

    Après j'ai une vision qui vient de notre façon de travailler qui n'est pas forcement adapté dans d'autre projet de développement.
    Homer J. Simpson


  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Au fait, vous auriez des sources (sites, bouquins...) concernant ces optimisations liés au cache ?

  10. #10
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    Celui la est assez sympa je trouve, ce sont des optims facilement réalisable:
    http://www.drdobbs.com/parallel/cach...s-ne/240012736
    Homer J. Simpson


  11. #11
    Membre expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Points : 3 892
    Points
    3 892
    Par défaut
    Pour l'optimisation de cache, je vous recommande Andrei Alexandrei qui en est spécialiste, sa dernière intervention toute fraiche : http://www.developpez.net/forums/d13...t/#post7477583

    Une architecture orienté data le sera nécessairement au détriment des performances. En effet, si vous prenez un diagramme merise/uml, que vous éclatez tout au maximum, vous serez sûr d'occuper le moins de place possible avec les données. En revanche, cela a un coût, et le coût ce sont les indirections qui vont plomber vos performances.

Discussions similaires

  1. Réponses: 5
    Dernier message: 13/12/2006, 16h08
  2. Réponses: 11
    Dernier message: 08/12/2006, 21h39
  3. Réponses: 2
    Dernier message: 26/07/2006, 12h46
  4. Choisir une bonne carte mère
    Par Lorponos dans le forum Composants
    Réponses: 27
    Dernier message: 05/05/2006, 16h49
  5. [MySQL] Vider une table puis insérer des données
    Par moonia dans le forum PHP & Base de données
    Réponses: 28
    Dernier message: 29/04/2006, 00h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo