package scrabble import ( "testing" "github.com/iliadenisov/alphabet" dawg "github.com/iliadenisov/dafsa" "gitea.iliadenisov.ru/developer/scrabble-solver/dictdawg" "gitea.iliadenisov.ru/developer/scrabble-solver/wordlist" ) func bruteCrossSet(words [][]byte, above, below []byte, size int) letterSet { set := make(map[string]bool, len(words)) for _, w := range words { set[string(w)] = true } var out letterSet for x := range size { w := make([]byte, 0, len(above)+1+len(below)) w = append(w, above...) w = append(w, byte(x)) w = append(w, below...) if set[string(w)] { out |= letterSet(1) << uint(x) } } return out } func TestDAWGCrossSetMatchesBruteForce(t *testing.T) { const size = 26 words := wordlist.Encode( []string{"cat", "cot", "cut", "cap", "cab", "at", "it"}, alphabet.Latin(), 2, 15) finder, err := dictdawg.Build(alphabet.Latin(), words) if err != nil { t.Fatal(err) } cur, err := dawg.NewCursor(finder) if err != nil { t.Fatal(err) } cases := []struct { name string above, below []byte }{ {"c_t", []byte{2}, []byte{19}}, // expect {a,o,u} {"_t", nil, []byte{19}}, // expect {a,i} {"c_", []byte{2}, nil}, // expect {} (no two-letter c-words) {"a_t", []byte{0}, []byte{19}}, // expect {} } for _, tc := range cases { want := bruteCrossSet(words, tc.above, tc.below, size) if got := dawgCrossSet(cur, tc.above, tc.below, size); got != want { t.Errorf("%s: dawgCrossSet = %026b, want %026b", tc.name, got, want) } } // c_t must be exactly {a(0), o(14), u(20)}. want := letterSet(0) for _, x := range []byte{0, 14, 20} { want |= letterSet(1) << x } if got := dawgCrossSet(cur, []byte{2}, []byte{19}, size); got != want { t.Errorf("c_t cross-set = %026b, want {a,o,u} = %026b", got, want) } // No perpendicular neighbours: every letter is allowed. if got := dawgCrossSet(cur, nil, nil, size); got != fullSet(size) { t.Errorf("empty context = %026b, want full", got) } }