| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | 241125T183455Z | Arnauld | |
| 003 | Python | 241125T222134Z | Jonathan |
N=4
Regex
/^[ct][ao][np][es]$/
Words
cane, cans, cape, caps,
cone, cons, cope, cops,
tane, tans, tape, taps,
tone, tons, tope, tops
Search code (Node.js)
This is the one and only solution found by this code.
const fs = require("fs");
const data = fs.readFileSync("words.txt").toString().split("\n");
const SHOW_ALL = false;
function search(N) {
const re = RegExp(`^[a-z]{${N}}$`),
dict = [ ...new Set(data.filter(w => re.test(w))) ];
let best = SHOW_ALL ? 1 : 2 ** N;
recursiveSearch(dict);
function recursiveSearch(list, pos = 0, path = "") {
if(pos == N) {
if(list.length >= best) {
best = list.length;
console.log(best);
console.log(`/^${path}$/`);
console.log(list.sort().join(", ") + "\n");
}
return;
}
let chars = [ ...new Set(list.map(w => w[pos])) ];
chars.forEach(x => {
chars.forEach(y => {
if(y > x) {
let newList = list.filter(w => w[pos] == x || w[pos] == y);
if(newList.length >= best) {
recursiveSearch(newList, pos + 1, path + `[${x + y}]`);
}
}
});
});
}
}
search(4);
Try it online! (dictionary limited to 4-character words for TIO)
N=5 (no solution)
Out of curiosity, I've tried to search \$N=5\$ (and beyond).
The best score is 19 words, which is -- unsurprisingly -- pretty far from 32.
/^[ch][ao][lr][dt][es]$/
cards, carte, carts, colde, colds, colts, corde, cords, corte, halte, halts, harde, harte, harts, holde, holds, holte, horde, horte
/^[cp][ao][rs][et][es]$/
cares, carte, carts, cases, caste, casts, cores, corte, costs, parte, parts, paste, pores, porte, ports, posee, poses, poste, posts
/^[cp][ao][rs][st][ae]$/
carta, carte, casse, caste, corse, corta, corte, costa, parse, parte, passa, passe, paste, porta, porte, possa, posse, posta, poste
Python 3
A full program that accepts an integer and a file path (without a path uses stdin, only implemented for the TIO suite really) and prints sets of words that equal or beat the maximal cardinality found so far.
The find function could be passed a floor of 2 ** word_length to not search for smaller than full sets (or could do that by default), this is just so we can see the best when no sets are "full" ones.
Here are the record breakers it finds for \$N \in [4,10]\$ (there are \$7965\$ length eight sets for \$N=3\$):
| N | Length | Word Set |
|---|---|---|
| 4 | 16 | cane cans cape caps cone cons cope cops tane tans tape taps tone tons tope tops |
| 5 | 19 | cards carte carts colde colds colts corde cords corte halte halts harde harte harts holde holds holte horde horte |
| 5 | 19 | cares carte carts cases caste casts cores corte costs parte parts paste pores porte ports posee poses poste posts |
| 5 | 19 | carta carte casse caste corse corta corte costa parse parte passa passe paste porta porte possa posse posta poste |
| 6 | 17 | cantar canter cartas carter cartes contar conter contes corner cornes cortes manner mannes monter montes mortar mortes |
| 6 | 17 | cantar canter cartas carter cartes conies contar conter contes cortes manier marier monies monter montes mortar mortes |
| 7 | 16 | changed changer chanted chanter chatted chatter clanged clangor clatter clotted planted planter platter plonger plotted plotter |
| 7 | 16 | partait partant parting parvint portait portant pouting pouvait pouvant sautait sautant sortait sortant sorting soutint souvint |
| 7 | 16 | pendait pendant pendent perdait perdant perdent portait portant portent sentais sentait sentant sentent sortait sortant sortent |
| 7 | 16 | pendait pendant pendent perdait perdant perdent portait portant portend portent sentait sentant sentent sortait sortant sortent |
| 7 | 16 | pendait pendant pendent perdait perdant perdent pertain portait portant portent sentait sentant sentent sortait sortant sortent |
| 8 | 14 | clacking clanging clanking clicking clinging clinking crackers cracking cringing flanking flickers flicking flinging fringing |
| 8 | 14 | clacking clanging clanking clicking clinging clinking cracking crackled cringing crinkled flanking flicking flinging fringing |
| 8 | 14 | blacking blankets blinking brackets bringing clacking clanging clanking clicking clinging clinking cracking crickets cringing |
| 8 | 14 | deserved deserves devolved devolves diversas diverses reserved reserves resolved resolves reversed reverses revolved revolves |
| 8 | 14 | deserved deserves devolved devolves diverses diversos reserved reserves resolved resolves reversed reverses revolved revolves |
| 9 | 12 | contorted contenter consentir presenter consorted preserver consented contented conserver conserved presented preserved |
| 10 | 11 | consenting consistait consisting contentait contenting contesting continuait continuant continuing protestant protesting |
| 10 | 11 | consenting consistait consisting contentait contenting contesting continuait continuant continuing presentait presenting |
...if repeats were allowed there is a \$17\$ for \$N=7\$ ([cb][lr][au][is][hs][ee][ds]: clashes classed cruised crushes blushed bruises cruises brushed brasses crushed blushes clashed bruised classes crashed brushes crashes)
import sys
LETTERS = 'abcdefghijklmnopqrstuvwxyz'
def find(word_length, words, floor=1, i=0):
if i >= word_length:
if all(len(set(column)) == 2 for column in zip(*tuple(words))):
yield words
else:
allowed_letters = tuple(set(w[i] for w in words))
for n, left in enumerate(allowed_letters, 1):
for right in allowed_letters[n:]:
filtered_words = {w for w in words if w[i] == left or w[i] == right}
if len(filtered_words) < floor:
continue
for result in find(word_length, filtered_words, floor, i + 1):
floor = len(result)
yield result
def main():
word_length = int(sys.argv[1])
if sys.argv[2:]:
words_filepath = sys.argv[2]
word_file = open(words_filepath, mode='r', encoding="utf8")
else:
word_file = sys.stdin
words = set()
for line in word_file.readlines():
if line.startswith("#"):
continue
word = line.strip('\n')
if len(word) == word_length and all(c in LETTERS for c in word):
words.add(word)
for found in find(word_length, words):
print(len(found), found)
print("Done.")
if __name__ == "__main__":
main()
Try it online! - you may want to collapse the "Input" section. This is for \$N=3\$ as TIO is too slow to do much more.