0

I'm implementing Minesweeper AI add_knowledge funcion which I expanded with add_sentence function for recursion in inference. I've written tests to test my add_knowledge function and it seems to be working for me, yet CS50 checker claims that my function cannot infer safe cells when given new information. Here is the code snippet:

def add_sentence(self, cells, count):
    # Create new sentence based on the nearby cells and known mines and safe cells.
    newSentence = Sentence(cells, count)
    self.knowledge.append(newSentence)

    # Check new sentence for discoveries.
    for cell in copy.deepcopy(newSentence.known_safes()):
        if cell not in self.safes:
            self.mark_safe(cell)
    for cell in copy.deepcopy(newSentence.known_mines()):
        if cell not in self.mines:
            self.mark_mine(cell)

    # Remove empty sentences:
    for sentence in self.knowledge:
        if len(sentence.cells) == 0:
            self.knowledge.remove(sentence)

    # Add mines and safes from inferred sentences:
    for sentence in self.knowledge:
        if len(sentence.cells) == sentence.count:
            for cell in copy.deepcopy(sentence.cells):
                self.mark_mine(cell)
            self.knowledge.remove(sentence)
            continue
        if sentence.count == 0:
            for cell in copy.deepcopy(sentence.cells):
                self.mark_safe(cell)
            self.knowledge.remove(sentence)
            continue

    # Remove same sentences
    updatedKnowledge = []
    for sentence in self.knowledge:
        if sentence not in updatedKnowledge:
            updatedKnowledge.append(sentence)
    self.knowledge = updatedKnowledge

    # Infer knowledge based on new sentence
    if len(self.knowledge) > 1:
        for sentence in self.knowledge:
            if sentence != newSentence:
                if sentence.cells.issubset(newSentence.cells):
                    inferredSet = Sentence(
                        newSentence.cells - sentence.cells,
                        newSentence.count - sentence.count,
                    )
                    if inferredSet not in self.knowledge:
                        self.add_sentence(
                            newSentence.cells - sentence.cells,
                            newSentence.count - sentence.count,
                        )
                if newSentence.cells.issubset(sentence.cells):
                    inferredSet2 = Sentence(
                        sentence.cells - newSentence.cells,
                        sentence.count - newSentence.count,
                    )
                    if inferredSet2 not in self.knowledge:
                        self.add_sentence(
                            sentence.cells - newSentence.cells,
                            sentence.count - newSentence.count,
                        )

def add_knowledge(self, cell, count):
    """
    Called when the Minesweeper board tells us, for a given
    safe cell, how many neighboring cells have mines in them.

    This function should:
        1) mark the cell as a move that has been made
        2) mark the cell as safe
        3) add a new sentence to the AI's knowledge base
           based on the value of `cell` and `count`
        4) mark any additional cells as safe or as mines
           if it can be concluded based on the AI's knowledge base
        5) add any new sentences to the AI's knowledge base
           if they can be inferred from existing knowledge
    """
    # Mark cell as the move made
    self.moves_made.add(cell)

    # Mark cell as safe
    self.mark_safe(cell)

    # Get nearby cells and substract known mines and safe cells
    NearbyCells = self.nearby_cells(cell)
    validNearbyCells = copy.deepcopy(NearbyCells)
    for cell in NearbyCells:
        if cell in self.safes:
            validNearbyCells.discard(cell)
        if cell in self.mines:
            validNearbyCells.discard(cell)
            count -= 1

    # Add new sentence and infer knowledge based on added sentence
    self.add_sentence(validNearbyCells, count)

    # Add mines and safes from inferred sentences:
    for sentence in self.knowledge:
        if len(sentence.cells) == sentence.count:
            for cell in copy.deepcopy(sentence.cells):
                self.mark_mine(cell)
            self.knowledge.remove(sentence)
            continue
        if sentence.count == 0:
            for cell in copy.deepcopy(sentence.cells):
                self.mark_safe(cell)
            self.knowledge.remove(sentence)
            continue

Now, do you have any ideas where did I go wrong?

2

1 Answer 1

1

Thanks to @kcw78 I managed to come up with a solution. I've redesigned the code completely. I made sure that every time the knowledge is updated it goes through the same process of marking mines and safes and inference recursively. This is now how my add_knowledge(cell, count) function looks like:

def add_knowledge(self, cell, count):
    """
    Called when the Minesweeper board tells us, for a given
    safe cell, how many neighboring cells have mines in them.

    This function should:
        1) mark the cell as a move that has been made
        2) mark the cell as safe
        3) add a new sentence to the AI's knowledge base
           based on the value of `cell` and `count`
        4) mark any additional cells as safe or as mines
           if it can be concluded based on the AI's knowledge base
        5) add any new sentences to the AI's knowledge base
           if they can be inferred from existing knowledge
    """
    # Mark cell as the move made
    self.moves_made.add(cell)

    # Mark cell as safe
    self.mark_safe(cell)

    # Get nearby cells and substract known mines and safe cells
    NearbyCells = self.nearby_cells(cell)
    validNearbyCells = copy.deepcopy(NearbyCells)
    for cell in NearbyCells:
        if cell in self.safes:
            validNearbyCells.discard(cell)
        elif cell in self.mines:
            validNearbyCells.discard(cell)
            count -= 1

    # Add new sentence
    self.add_sentence(validNearbyCells, count)

    # Mark cells and infer knowledge every time knowledge is changed
    knowledgeChanged = True

    while knowledgeChanged:
        knowledgeChanged = False
        # Mark safe cells and mines
        if self.mark_cells():
            knowledgeChanged = True
        # Infer new knowledge
        if self.infer_knowledge():
            knowledgeChanged = True

Functions mark_cells() and infer_knowledge() return True if they change the KB and make the while loop go around again.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .