CSES - Koodin selvitys

Avainkoodissa on neljä numeroa väliltä 191 \dots 9. Koodissa ei esiinny kahta kertaa samaa numeroa.

Sinulle on annettu olio ("oraakkeli"), jonka sisällä on salainen avainkoodi. Tehtäväsi on selvittää koodi tekemällä kyselyitä oraakkelille. Jokainen kysely on avainkoodi ja oraakkeli kertoo, moniko numero on oikealla paikalla koodissa ja moniko numero kuuluu koodiin mutta on väärällä paikalla.

Esimerkiksi jos oikea koodi on 4217 ja teet kyselyn 1234, oraakkeli antaa vastauksena luvut 11 ja 22. Tämä tarkoittaa, että yksi numero (2) on oikealla paikalla koodissa ja lisäksi kaksi numeroa (1 ja 4) kuuluvat koodiin mutta niiden paikat ovat väärät.

Tehtävän haasteena on, että saat tehdä enintään 1616 kyselyä oraakkelille. Tämän jälkeen sinun täytyy pystyä ilmoittamaan salainen koodi.

Jokaisessa kyselyssä oraakkelille tulee olla kelvollinen avainkoodi. Huomaa erityisesti, että koodissa ei saa olla kahta samaa numeroa eli esimerkiksi koodi 1212 ei kelpaa.

Toteuta tiedostoon findcode.py funktio find_code, jolle annetaan parametrina oraakkeli. Funktion tulee kutsua oraakkelin metodia check_code, joka palauttaa vastauksen kahden kokonaisluvun parina.

Funktio ei saa yrittää selvittää vastausta oraakkelilta muulla tavalla kuin kutsumalla metodia check_code. Palvelimella oleva oraakkeli saattaa erota tehtäväpohjan toteutuksesta.

import re

class Oracle:
    def __init__(self, code):
        self.code = code
        self.counter = 0

    def check_code(self, code):
        self.counter += 1
        if self.counter > 16:
            raise RuntimeError("too many check_code calls")

        if type(code) != str or not re.match("^[1-9]{4}$", code) or len(code) != len(set(code)):
            raise RuntimeError("invalid code for check_code")

        in_place = in_code = 0
        for pos in range(4):
            if code[pos] in self.code:
                if code[pos] == self.code[pos]:
                    in_place += 1
                else:
                    in_code += 1

        return in_place, in_code

def find_code(oracle):
    # TODO

if __name__ == "__main__":
    # esimerkki oraakkelin toiminnasta
    oracle = Oracle("4217")
    print(oracle.check_code("1234")) # (1, 2)
    print(oracle.check_code("3965")) # (0, 0)
    print(oracle.check_code("4271")) # (2, 2)
    print(oracle.check_code("4217")) # (4, 0)

    # esimerkki funktion find_code toiminnasta
    oracle = Oracle("4217")
    code = find_code(oracle)
    print(code) # 4217