summaryrefslogblamecommitdiffstats
path: root/šola/p1/wordle/Tekm_12345678.java
blob: 71d736025b113a051f322fd9361dd4c55bf45f6b (plain) (tree)












































































































































                                                                                              

import java.util.*;

//
// Primer stroja za igro Wordle. Stroj vzdržuje množico slovarskih besed, ki
// so združljive z vsemi dosedanjimi omejitvami, in vsakokrat izbere ``prvo''
// besedo iz množice (tj. tisto, ki jo vrne iterator ob prvem klicu metode
// next).
//

public class Tekm_12345678 implements Stroj {

    // izhodiščna množica besed
    // (nastavi se ob inicializaciji, potem pa se ne spreminja)
    private Set<String> izhodiscneBesede;

    // množica besed, ki še ustreza omejitvam
    private Set<String> besede;

    // nazadnje izbrana beseda
    private String zadnjaIzbira;

    //
    // Nastavi izhodiščno množico besed.
    //
    @Override
    public void inicializiraj(Set<String> besede) {
        this.izhodiscneBesede = new TreeSet<>(besede);
    }

    //
    // Na podlagi podanega odziva na prejšnjo izbiro vrne naslednjo izbiro.
    //
    // odziv[i]: odziv ('+', 'o' ali '-') na i-to črko prejšnje izbire;
    //           null, ko ogrodje zahteva prvo izbiro.
    //
    @Override
    public String poteza(List<Character> odziv) {

        if (odziv == null) {
            // Prva ``poteza'': ponastavi množico besed.
            this.besede = new TreeSet<>(this.izhodiscneBesede);

        } else {
            if (vseEnako(odziv, '+')) {
                // Konec, naša zadnja izbira je bila pravilna!
                return null;
            }

            if (this.besede.isEmpty()) {
                // Množica besed je prazna, kljub temu da besede še nismo
                // uganili.
                throw new RuntimeException("Nekaj močno smrdi!");
            }

            // Iz množice odstranimo vse besede, ki niso združljive z odzivom
            // na zadnjo izbiro.
            Set<String> odstrani = new TreeSet<>();
            for (String beseda: this.besede) {
                if (!jeZdruzljiva(beseda, this.zadnjaIzbira, odziv)) {
                    odstrani.add(beseda);
                }
            }
            this.besede.removeAll(odstrani);
        }

        // Vrnemo ``prvo'' besedo iz množice (tj. prvo, ki jo vrne iterator).
        return this.zadnjaIzbira = this.besede.iterator().next();
    }

    //
    // Vrne true natanko v primeru, če so vsi elementi podanega seznama enaki
    // podanemu elementu.
    //
    private static <T> boolean vseEnako(List<T> seznam, T element) {
        return seznam.stream().allMatch(e -> e.equals(element));
    }

    //
    // Vrne true natanko v primeru, če je beseda <beseda> združljiva s
    // podanim odzivom na podano izbiro.
    //
    private static boolean jeZdruzljiva(String beseda, String izbira, List<Character> odziv) {
        int n = odziv.size();

        // Izdelamo seznam znakov besed <beseda> in <izbira>
        // (nizi so nespremenljivi, seznami pa niso).
        // (npr. "znanka" -> ['z', 'n', 'a', 'n', 'k', 'a'].
        List<Character> crkeBesede = new ArrayList<>();
        List<Character> crkeIzbire = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            crkeBesede.add(beseda.charAt(i));
            crkeIzbire.add(izbira.charAt(i));
        }

        // Preverimo, ali za vse i-je, pri katerih je odziv[i] == '+',
        // velja beseda[i] == izbira[i].
        for (int i = 0; i < n; i++) {
            if (odziv.get(i) == '+') {
                if (crkeBesede.get(i) != crkeIzbire.get(i)) {
                    return false;
                }

                // Označimo, da smo ta položaj že pregledali
                // (to je pomembno za pravilno obravnavo odzivov 'o').
                crkeBesede.set(i, '#');
                crkeIzbire.set(i, '_');
            }
        }

        // Preverimo, ali za vse i-je, pri katerih je odziv[i] == 'o',
        // velja, da <beseda> vsebuje črko izbira[i], a ne na indeksu <i>.
        // Vsako tako črko beseda <izbira> je treba povezati z eno samo črko
        // besede <beseda>.

        for (int ixIzbira = 0; ixIzbira < n; ixIzbira++) {

            if (odziv.get(ixIzbira) == 'o') {
                char crka = crkeIzbire.get(ixIzbira);
                int ixBeseda = crkeBesede.indexOf(crka);
                if (ixBeseda < 0 || crkeBesede.get(ixIzbira) == crka) {
                    return false;
                }

                // Označimo, da smo pripadajoča položaja že pregledali.
                crkeBesede.set(ixBeseda, '#');
                crkeIzbire.set(ixIzbira, '_');
            }
        }

        // Preverimo, ali za vse i-je, pri katerih je odziv[i] == '-',
        // velja, da <beseda> ne vsebuje črke izbira[i].
        for (int i = 0; i < n; i++) {
            if (odziv.get(i) == '-' && crkeBesede.indexOf(crkeIzbire.get(i)) >= 0) {
                return false;
            }
        }

        return true;
    }
}