12 dominating knights puzzle (backtracking)

前端 未结 5 1975
感动是毒
感动是毒 2021-02-07 05:47

I\'ve been searching for hours and haven\'t found a fully working solution for this kind of puzzle yet. So I followed similar problem with bishops.

What I need to do is

5条回答
  •  囚心锁ツ
    2021-02-07 06:35

    First I define my basic concept attack-ability. Attack-ability is how many knights can attack given cell.

    Ex: Corner cells can be attacked by only two knights so attack-ability is two. Attack-ability of middle cell is 8.

    Attack-ability of cells

    | 2 | 3 | 4 | 4 | 4 | 4 | 3 | 2 |

    | 3 | 4 | 6 | 6 | 6 | 6 | 4 | 3 |

    | 4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |

    | 4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |

    | 4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |

    | 4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |

    | 3 | 4 | 6 | 6 | 6 | 6 | 4 | 3 |

    | 2 | 3 | 4 | 4 | 4 | 4 | 3 | 2 |

    Calculating attackability

    AttackingNodes::AttackingNodes(int x, int y)
    {
        target = new Element(x, y);
        CreateAtackList();
    }
    
    void AttackingNodes::CreateAtackList()
    {
        for(int diffx = -2; diffx <=2; ++diffx)
        {
    
            for(int diffy = -2; diffy <=2; ++diffy)
            {
                if((diffx*diffx + diffy* diffy) == 5)
                {
                    AddAttack(target->_X + diffx, target->_Y + diffy);
                }
            }
        }
    }
    
    void AttackingNodes::AddAttack( int x, int y )
    {
        if(x >= 0 && y >= 0 && x < BOARD_SIZE && y < BOARD_SIZE)
        {
            Element* element = new Element(x, y);
            attackers.push_back(element);
        }
    }
    

    size of the attackers in attacking nodes is equal to attackability.

    Then multimap is created attackability against attackingNodes

    for(int x = 0; x < BOARD_SIZE; ++x)
    {
        for(int y = 0; y < BOARD_SIZE; ++y)
        {
            AttackingNodes* nodes = new AttackingNodes(x, y);
            attackNodes[x][y] = nodes;
            mapAttackPriority.insert(std::make_pair(nodes->attackers.size(), nodes));
        }
    }
    

    If attackability is low then there is lesser options for attacking given cell.

    So first node from multimap is chosen which has lesser attacking options.

    First cell will be 0, 0. There is two options to attack 0, 0

    1, 2 or 2, 1
    

    Lets choose 1, 2 and attack cells if they are empty. It can attack 6 cells.

    attack(..) is placing knight in given cell. Atackers and targets are same way related. So data generated while calculating attack-ability is used here.

    bool Solution::attack( Element* nodes )
    {
        ++knightCount;
        AttackingNodes* attackList = PriorityTargets::inst->attackNodes[nodes->_X][nodes->_Y];
        std::list::iterator itr;
    
        board[nodes->_X][nodes->_Y] = CC_KNIGHT;
    
        for(itr = attackList->attackers.begin(); itr != attackList->attackers.end(); ++itr)
        {
            Element* attackNode = *itr;
    
            if(board[attackNode->_X][attackNode->_Y] == CC_EMPTY)
            {
                board[attackNode->_X][attackNode->_Y] = CC_ATTACKED;
            }
        }
    
        return false;
    }
    

    | A | 0 | A | 0 | 0 | 0 | 0 | 0 |

    | 0 | 0 | 0 | A | 0 | 0 | 0 | 0 |

    | 0 | K | 0 | 0 | 0 | 0 | 0 | 0 |

    | 0 | 0 | 0 | A | 0 | 0 | 0 | 0 |

    | A | 0 | A | 0 | 0 | 0 | 0 | 0 |

    | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

    | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

    | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

    Then algorithm search for next empty cell (no Knight, no Attacked) with lowest attackability attack it with available options.

    AttackingNodes* PriorityTargets::GetNextNode( Solution* solution )
    {
    
        std::multimap::iterator priorityItr;
        for(priorityItr  = mapAttackPriority.begin(); priorityItr != mapAttackPriority.end(); ++priorityItr)
        {
            AttackingNodes* attackNodes = priorityItr->second;
            if(solution->board[attackNodes->target->_X][attackNodes->target->_Y] == CC_EMPTY)
            {
                return attackNodes;
            }
        }
    
        return NULL;
    }
    

    It will be an another corner node for second options and it will go on until knight count is larger than 12 or no empty cells.

    knight count is larger than 12 it is a fail attempt and backed tracked. If there is no empty cell then it is a solution.

    Solution::Solution()
    {
        Clear();
    }
    
    void Solution::Print()
    {
    
        std::cout << std::endl ;
        for(int x = 0; x < BOARD_SIZE; ++x)
        {
            for(int y = 0; y < BOARD_SIZE; ++y)
            {
                std::cout << (int)board[x][y] << " ";
            }
            std::cout << std::endl ;
        }
    
    
        std::cout << std::endl ;
    
    }
    
    bool Solution::Solve( Solution* solution )
    {
        AttackingNodes* nextAttackingNode = PriorityTargets::inst->GetNextNode(solution);
    
        if(nextAttackingNode != NULL)
        {
            Solution* newSolutioon = new Solution();
            std::list::iterator itr;
            for(itr = nextAttackingNode->attackers.begin(); itr != nextAttackingNode->attackers.end(); ++itr)
            {
                Element* attack = *itr;
    
    
                    *newSolutioon = *solution;
                    newSolutioon->attack(attack);
                    if(newSolutioon->knightCount < 13)
                    {
                        Solve(newSolutioon);
                    }
                    else
                    {
                        //Fail
                        newSolutioon->Clear();
                    }
            }
    
            delete newSolutioon;
        }
        else
        {
            std::cout << "Solved" << std::endl;
            solution->Print();
        }
    
        return false;
    }
    
    
    void Solution::Clear()
    {
        memset(board, 0, BOARD_SIZE*BOARD_SIZE);
        knightCount = 0;
    }
    

    And I got the answer in lesser than 500 ms in visual studio 2008 release mode. I have used 2 for Knight and 1 for attacked.

提交回复
热议问题