Gena Playing Hanoi

Sort by

recency

|

36 Discussions

|

  • + 1 comment

    C++ (more at https://github.com/IhorVodko/Hackerrank_solutions , feel free to give a star:) )
    Build bfs tree where each node is a game state.

    static const size_t rodsCount = 4;
    static const size_t statesMaxCount = static_cast<size_t>(std::pow(4, 10)); 
    
    size_t hanoi(
        std::vector<size_t> const & positions
    ){
        using namespace std;
        using state_t = vector<size_t>;
        using mask_t = vector<bool>;
        auto const & disksCount{positions.size()};
        // last element of a vector tracks how many moves done to achive its state
        auto stateAtTreeRoot(state_t(disksCount + 1, 0));
        transform(cbegin(positions), cend(positions), begin(stateAtTreeRoot),
            [&](const auto & disk){
                return disk - 1;
            });
        auto bfsQ{queue<state_t>{}};
        bfsQ.push(stateAtTreeRoot);
        auto statesAtTreeVisited{mask_t(::statesMaxCount, false)};
        auto hash = [&](auto const & value){
            size_t hashValue{0};
            for_each(cbegin(value), cend(value) - 1, [&](auto const & num){
                hashValue = hashValue * ::rodsCount + num;
            });
            return hashValue;
        };
        statesAtTreeVisited.at(hash(stateAtTreeRoot)) = true;
        auto rodsVisitedToMoveFrom{mask_t(::rodsCount, false)};
        auto rodsVisitedToMoveTo{mask_t(::rodsCount, false)};
        size_t hashValue{0};
        auto stateAtSubTreeRoot{state_t(disksCount + 1, 0)};
        auto stateAtNextNode{state_t(disksCount + 1, 0)};
        while(!bfsQ.empty()){
            copy(cbegin(bfsQ.front()), cend(bfsQ.front()),
                begin(stateAtSubTreeRoot));
            bfsQ.pop();
            for(size_t disk{0}; disk < disksCount; ++disk){
                if(rodsVisitedToMoveFrom.at(stateAtSubTreeRoot.at(disk))){
                   continue; 
                }
                rodsVisitedToMoveFrom.at(stateAtSubTreeRoot.at(disk)) = true;
                copy(cbegin(rodsVisitedToMoveFrom), cend(rodsVisitedToMoveFrom),
                    begin(rodsVisitedToMoveTo));
                for(size_t newRod{0}; newRod < ::rodsCount; ++newRod){
                    if(rodsVisitedToMoveTo.at(newRod)){
                        continue;
                    }
                    rodsVisitedToMoveTo.at(newRod) = true;
                    copy(cbegin(stateAtSubTreeRoot), cend(stateAtSubTreeRoot),
                        begin(stateAtNextNode));
                    ++stateAtNextNode.back();
                    stateAtNextNode.at(disk) = newRod;
                    hashValue = hash(stateAtNextNode);
                    if(hashValue == 0){
                        return stateAtNextNode.back();
                    }
                    if(statesAtTreeVisited.at(hashValue)){
                        continue;
                    }
                    statesAtTreeVisited.at(hashValue) = true;
                    bfsQ.push(stateAtNextNode);
                }
                fill(begin(rodsVisitedToMoveTo), end(rodsVisitedToMoveTo),
                    false);
            }
            fill(begin(rodsVisitedToMoveFrom), end(rodsVisitedToMoveFrom),
                false);
        }
        return numeric_limits<size_t>::max();
    }
    
  • + 0 comments

    Most straightforward solution, in my opinion:

    from sys import stdin
    from functools import reduce
    from queue import deque
    
    
    def get_states(state: int, n: int):
        """returns a list of states that can be achieved from the given state"""
        top_disks = []
        positions = set()
        for size in range(n):
            pos = (state >> 2 * size) & 3
            if pos not in positions:
                top_disks.append((size, pos))
                positions.add(pos)
        top_disks.sort()
        allowed_positions = set(range(4))
        states = []
        for size, pos in top_disks:
            allowed_positions.discard(pos)
            for pos_ in allowed_positions:
                new_state = (pos_ << 2 * size) | (state ^ (pos << 2 * size))
                states.append(new_state)
        return states
    
    
    def hanoi(init_state: int, n: int):
        """
        represent each possible arrangement as a binary number
        of length 2 * n, where n is the number of disks. the rightmost 2 digits
        represent the position of disk 1, the next two digits represent the
        position of disk 2, etc., then do a bfs of the graph starting at init_state...   
        """
        queue = deque([(init_state, 0)])
        visited = {init_state}
        while queue:
            state, num_moves = queue.popleft()
            if state == 0:
                return num_moves
            else:
                states = get_states(state, n)
                for state in states:
                    if not state in visited:
                        queue.append((state, num_moves + 1)) 
                        visited.add(state)   
    
    
    def main():
        n = int(stdin.readline().strip())
        disks = map(int, stdin.readline().strip().split())
        state = reduce(
            lambda x, y: x | y, 
            ((pos - 1) << 2 * size for size, pos in enumerate(disks)))
        print(hanoi(state, n))
    
    
    if __name__ == "__main__":
        main()
    
  • + 0 comments

    Cached optimized brute force passes all tests.

    int maxdepth = 50;
    int tw[4][10];
    int twsize[4];
    size_t dsknum;
    int dsk;
    int cache[1048576];
    
    int hanoi2()
    {
        static int depth = 0;
        if (dsk == 0) return 0;
        if (depth >= maxdepth) return 255;    
        int moves_n_depth = cache[dsk];
        if (moves_n_depth && depth+1 >= (moves_n_depth & 255)) 
            return moves_n_depth >> 8;
        ++depth;
        cache[dsk] = (255 << 8) | depth;
        int moves = 255;        
        for (int ti1 = 0; ti1 < 3; ti1++) {
            for (int ti2 = ti1 + 1; ti2 < 4; ti2++) {
                int di1 = twsize[ti1] ? tw[ti1][twsize[ti1]-1] : 255;
                int di2 = twsize[ti2] ? tw[ti2][twsize[ti2]-1] : 255;
                bool rev = (di1 > di2);
                if (rev) swap(ti1, ti2);
                auto& t1 = tw[ti1];
                auto& t2 = tw[ti2];
                if (!twsize[ti1]) continue;
                int db = (rev ? di2 : di1) << 1;
                dsk &= ~(3 << db);
                dsk |= (ti2 << db);
                t2[twsize[ti2]++] = t1[--twsize[ti1]];
                moves = min(moves, hanoi2() + 1);
                t1[twsize[ti1]++] = t2[--twsize[ti2]];
                dsk &= ~(3 << db);
                dsk |= (ti1 << db);
                if (rev) swap(ti1, ti2);
            }
        }
        cache[dsk] = (moves << 8) | depth;
        --depth;
        return moves;
    }
    
    int hanoi(vector<int> posts)
    {
        for (maxdepth = 10; maxdepth <= 50; maxdepth += 20) {
            cout << "maxdepth=" << maxdepth << "\n";
            dsknum = posts.size();
            fill(&tw[0][0], &tw[0][0]+sizeof(tw)/sizeof(tw[0][0]), 0);
            fill(twsize, twsize +sizeof(twsize)/sizeof(twsize[0]), 0);
            fill(cache, cache + sizeof(cache)/sizeof(cache[0]), 0);
            dsk = 0;
            for (auto di = 0; di < dsknum; di++) {
                int ti = posts[di] - 1;
                dsk |= (ti << (di << 1));
                tw[ti][twsize[ti]] = di;
                twsize[ti]++;
            }
            for (int ti = 0; ti < 4; ti++)
                sort(tw[ti], tw[ti] + twsize[ti], greater<int>());
    
            int result = hanoi2();
            if (result < 255)
                return result;
        }
        return 255;
    }
    
  • + 0 comments

    Here is my solution in java, javascript, python, C, C++, Csharp HackerRank Gena Playing Hanoi Problem Solution

  • + 0 comments

    Here is the solution of Gena Playing Hanoi Click Here