summaryrefslogtreecommitdiffstats
path: root/šola/p1/wordle/Tekm_12345678.java
blob: 71d736025b113a051f322fd9361dd4c55bf45f6b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

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;
    }
}