// Produce all valid "left" indices for a particular search query. // What determines whether an index is valid is whether it can form the start // of a complete word. This basically means "any cell with nothing on the // left". // // A cell that has *something* on the left of it cannot form the beginning of a // word because it must have a prefix (the stuff on the left) to be a word. // // Given a query like ..AD.., this will produce the indices 0, 1, 2, 5 // (because indices 3 and 4 are 'D' and the '.' after it, which can't be the // beginning of a word, but index 2 can, since a word can start with 'AD' in // this scenario). func GetSubSuffixes(info index.AllowedInfo) <-chan int { out := make(chan int) emit := func(left int) { if info.AnchoredSubSequence(left, len(info.Draws)) { out <- left } } go func() { defer close(out) for left := 0; left < len(info.Constraints); left++ { emit(left) for left < len(info.Constraints) && !info.Draws[left] { left++ } } }() return out }
// Get all allowed subconstraints from an initial constraint. // // This constitutes peeling off from the left and right whatever can be peeled // off to form a new sub constraint. func GetSubConstraints(info index.AllowedInfo) <-chan Endpoints { out := make(chan Endpoints) emit := func(left, right int) { if info.AnchoredSubSequence(left, right) { out <- Endpoints{left, right} } } go func() { defer close(out) for left := range GetSubSuffixes(info) { emit(left, len(info.Constraints)) for right := left + 1; right < len(info.Constraints); right++ { // We can't peel off a fixed tile - it must form part of the // word. if !info.Draws[right] { continue } emit(left, right) } } }() return out }