Word ladder: Difference between revisions

Content deleted Content added
Rdm (talk | contribs)
J
Not a robot (talk | contribs)
Add APL
 
(6 intermediate revisions by 4 users not shown)
Line 23:
{{trans|Nim}}
 
<langsyntaxhighlight lang="11l">F isOneAway(word1, word2)
V result = 0B
L(i) 0 .< word1.len
Line 74:
print(‘No path from "’start‘" to "’target‘".’)
E
print(path.join(‘ -> ’))</langsyntaxhighlight>
 
{{out}}
Line 86:
white -> whine -> chine -> chink -> clink -> blink -> blank -> black
bubble -> babble -> gabble -> garble -> gargle -> gaggle -> giggle -> jiggle -> jingle -> tingle -> tinkle -> tickle
</pre>
 
=={{header|Ada}}==
Changed my solution to use Multiway_Trees.
<syntaxhighlight lang="ada">
pragma Ada_2022;
with Ada.Containers.Multiway_Trees;
with Ada.Containers.Vectors;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO; use Ada.Text_IO.Unbounded_IO;
procedure Word_Ladder is
 
DICT_FILENAME : constant String := "unixdict.txt";
MAX_DEPTH : constant Positive := 50;
 
subtype LC_Chars is Character range 'a' .. 'z';
 
type Word_Node_T is record
Level : Positive;
Word : Unbounded_String;
end record;
 
package Word_Vectors is new Ada.Containers.Vectors (Positive, Unbounded_String);
package Dict_Vectors is new Ada.Containers.Vectors (Positive, Unbounded_String);
 
package Word_Trees is new Ada.Containers.Multiway_Trees (Word_Node_T);
use Word_Trees;
Word_Tree : Tree;
Solved : Boolean;
Solution : Cursor;
 
function Load_Candidate_Words (Dict_Filename : String; Word_Len : Positive)
return Dict_Vectors.Vector is
Dict_File : File_Type;
Read_Word : Unbounded_String;
Cands : Dict_Vectors.Vector;
Valid : Boolean;
C : Character;
begin
Open (File => Dict_File, Mode => In_File, Name => Dict_Filename);
while not End_Of_File (Dict_File) loop
Read_Word := Get_Line (Dict_File);
if Length (Read_Word) = Word_Len then
Valid := True;
for Ix in 1 .. Word_Len loop
C := Element (Read_Word, Ix);
Valid := C in LC_Chars;
exit when not Valid;
end loop;
if Valid then Cands.Append (Read_Word); end if;
end if;
end loop;
Close (Dict_File);
return Cands;
end Load_Candidate_Words;
 
function Mutate (Word : Unbounded_String; Dict : in out Dict_Vectors.Vector)
return Word_Vectors.Vector is
Mutations : Word_Vectors.Vector;
Poss_Word : Unbounded_String;
begin
for Ix in 1 .. Length (Word) loop
for Letter in LC_Chars loop
if Letter /= Element (Word, Ix) then
Poss_Word := Word;
Replace_Element (Poss_Word, Ix, Letter);
if Dict.Contains (Poss_Word) then
Mutations.Append (Poss_Word);
Dict.Delete (Dict.Find_Index (Poss_Word));
end if;
end if;
end loop;
end loop;
return Mutations;
end Mutate;
 
procedure Recurse_Tree (Start_Pos : Cursor;
Level : Positive;
Target : Unbounded_String;
Dict : in out Dict_Vectors.Vector) is
Pos : Cursor := Start_Pos;
Mutations : Word_Vectors.Vector;
New_Node : Word_Node_T;
begin
while not Solved and then Pos /= No_Element loop
if Element (Pos).Level = Level then
Mutations := Mutate (Element (Pos).Word, Dict);
if not Word_Vectors.Is_Empty (Mutations) then
for Word of Mutations loop
New_Node.Level := Level + 1;
New_Node.Word := Word;
Append_Child (Word_Tree, Pos, New_Node);
if Word = Target then
Solved := True;
Solution := Pos;
end if;
end loop;
end if;
end if;
if not Solved then
Recurse_Tree (First_Child (Pos), Level, Target, Dict);
end if;
Pos := Next_Sibling (Pos);
end loop;
end Recurse_Tree;
 
procedure Ladder (Start_S, Target_S : String) is
Dictionary : Dict_Vectors.Vector;
Level : Positive := 1;
Word_Node : Word_Node_T;
Start, Target : Unbounded_String;
Start_Pos : Cursor;
Output : Unbounded_String;
begin
if Start_S'Length /= Target_S'Length then
Put_Line ("ERROR: Start and Target words must be same length.");
return;
end if;
Dictionary := Load_Candidate_Words (DICT_FILENAME, Start_S'Length);
Start := To_Unbounded_String (Start_S);
Target := To_Unbounded_String (Target_S);
Solved := False;
Word_Node.Level := 1;
Word_Node.Word := Start;
Word_Tree := Empty_Tree;
Word_Tree.Insert_Child (Word_Tree.Root, No_Element, Word_Node);
Start_Pos := Find (Word_Tree, Word_Node);
while Level <= MAX_DEPTH and then not Solved loop
Recurse_Tree (Start_Pos, Level, Target, Dictionary);
Level := @ + 1;
end loop;
if not Solved then
Put_Line (Start & " -> " & Target & " - No solution found at depth" & MAX_DEPTH'Image);
else
while not Is_Root (Solution) loop
Word_Node := Element (Solution);
Output := Word_Node.Word & " -> " & Output;
Solution := Parent (Solution);
end loop;
Put_Line (Output & Target);
end if;
end Ladder;
begin
Ladder ("boy", "man");
Ladder ("girl", "lady");
Ladder ("jane", "john");
Ladder ("child", "adult");
Ladder ("ada", "god");
Ladder ("rust", "hell");
end Word_Ladder;
</syntaxhighlight>
 
{{out}}
As expected "ada" can become a "god", and "rust" can go to "hell" :-)
<pre>
boy -> bay -> may -> man
girl -> gill -> gall -> gale -> gaze -> laze -> lazy -> lady
jane -> cane -> cone -> conn -> cohn -> john
child -> adult - No solution found at depth 50
ada -> fda -> faa -> fad -> gad -> god
rust -> bust -> best -> belt -> bell -> hell
</pre>
 
=={{header|ALGOL 68}}==
With ''a68g'' use option <code>--storage 2</code>, otherwise it runs out of memory.
<langsyntaxhighlight lang="algol68"># quick implementation of a stack of INT.
real program starts after it.
#
Line 268 ⟶ 430:
print(newline)
FI
OD</langsyntaxhighlight>
{{out}}
<pre>boy->bay->ban->man
Line 290 ⟶ 452:
bubble->babble->gabble->garble->gargle->gaggle->giggle->jiggle->jingle->tingle->tinkle->tickle</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL}}
<syntaxhighlight lang="apl">wordladder←{
from to←⍵
dict←((≢¨⍺)=≢to)/⍺
 
dict{
match←(⊂to)≡¨⊃∘⌽¨⍵
∨/match:⊃match/⍵
0∊≢¨⍺⍵:⍬
word←⊃⌽ladder←⊃⍵
next←(1=⍺+.≠¨⊂word)/⍺
(⍺~next)∇(1↓⍵),(⊂ladder),¨⊂¨next
}⊂⊂from
}
task←{
dict←(~dict∊⎕TC)⊆dict←⊃⎕NGET'unixdict.txt'
pairs←('boy' 'man')('girl' 'lady')('john' 'jane')('child' 'adult')
⎕←↑↑{
hdr←⍺,' → ',⍵,': '
ladder←dict wordladder ⍺ ⍵
0=≢ladder:hdr,'impossible'
hdr,1↓∊'→',¨ladder
}/¨pairs
}</syntaxhighlight>
{{out}}
<pre>boy → man: boy→bay→ban→man
girl → lady: girl→gill→gall→gale→gaze→laze→lazy→lady
john → jane: john→cohn→conn→cone→cane→jane
child → adult: impossible </pre>
=={{header|C++}}==
This borrows heavily from [[#Wren|Wren]] and a bit from [[#Raku|Raku]].
<langsyntaxhighlight lang="cpp">#include <algorithm>
#include <fstream>
#include <iostream>
Line 383 ⟶ 575:
word_ladder(words, "bubble", "tickle");
return EXIT_SUCCESS;
}</langsyntaxhighlight>
 
{{out}}
Line 398 ⟶ 590:
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">
// Word ladder: Nigel Galloway. June 5th., 2021
let fG n g=n|>List.partition(fun n->2>Seq.fold2(fun z n g->z+if n=g then 0 else 1) 0 n g)
Line 407 ⟶ 599:
let i,e=fG dict n in match i with Done i->Some([n;g]) |_->wL(i|>List.map(fun g->[g;n])) [] e
[("boy","man");("girl","lady");("john","jane");("child","adult")]|>List.iter(fun(n,g)->printfn "%s" (match wL n g with Some n->n|>String.concat " -> " |_->n+" into "+g+" can't be done"))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 418 ⟶ 610:
The bad news is evil can not be turned into good, but the good news is god can become man.
 
<langsyntaxhighlight lang="fsharp">
[("evil","good");("god","man")]|>List.iter(fun(n,g)->printfn "%s" (match wL n g with Some n->n|>String.concat " -> " |_->n+" into "+g+" can't be done"))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 429 ⟶ 621:
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 517 ⟶ 709:
wordLadder(words, pair[0], pair[1])
}
}</langsyntaxhighlight>
 
{{out}}
Line 531 ⟶ 723:
The function first expands a ball around the starting word in the space of possible words, until the ball surface touches the goal (if ever). After that it performs depth-first path-finding from the goal back to the center.
 
<langsyntaxhighlight lang="haskell">import System.IO (readFile)
import Control.Monad (foldM)
import Data.List (intercalate)
Line 577 ⟶ 769:
showChain $ wordLadder dict "john" "jane"
showChain $ wordLadder dict "alien" "drool"
showChain $ wordLadder dict "child" "adult"</langsyntaxhighlight>
 
<pre>λ> lines <$> readFile "unixdict.txt" >>= print . wordLadders "boy" "man"
Line 598 ⟶ 790:
Performs searching from both ends. This solution is much faster for cases with no chains, and for for short chains. In case of long chains looses its' efficiency.
 
<langsyntaxhighlight lang="haskell">wordLadders2 :: String -> String -> [String] -> [[String]]
wordLadders2 start end dict
| length start /= length end = []
Line 629 ⟶ 821:
where g (b, r) a = (\x -> (x, x:r)) <$> f b a
 
findM p = msum . map (\x -> if p x then pure x else mzero)</langsyntaxhighlight>
 
===Using A*-search===
See [[A*_search_algorithm#Haskell]]
 
<langsyntaxhighlight lang="haskell">import AStar (findPath, Graph(..))
import qualified Data.Map as M
 
Line 646 ⟶ 838:
g = Graph $ \w -> M.fromList [ (x, 1)
| x <- short_dict
, distance w x == 1 ]</langsyntaxhighlight>
 
<pre>λ> main
Line 660 ⟶ 852:
Here we use a double ended breadth first search (starting from each end). This tends to give us several options where they meet in the middle, so we pick a shortest example from those.
 
<langsyntaxhighlight Jlang="j">extend=: {{
j=. {:y
l=. <:{:$m
Line 689 ⟶ 881:
end.
}.,' ',.r{words
}}</langsyntaxhighlight>
 
Task examples:<langsyntaxhighlight Jlang="j"> 'boy' wlad 'man'
boy bay ban man
'girl' wlad 'lady'
Line 705 ⟶ 897:
white whine chine chink clink blink blank black
'bubble' wlad 'tickle'
bubble babble gabble garble gargle gaggle giggle jiggle jingle tingle tinkle tickle</langsyntaxhighlight>
 
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
Line 802 ⟶ 994:
wordLadder(words, "bubble", "tickle", 12);
}
}</langsyntaxhighlight>
{{out}}
<pre>boy -> bay -> may -> man
Line 815 ⟶ 1,007:
===Faster alternative===
{{trans|C++}}
<langsyntaxhighlight lang="java">import java.io.*;
import java.util.*;
 
Line 886 ⟶ 1,078:
System.out.printf("%s into %s cannot be done.\n", from, to);
}
}</langsyntaxhighlight>
 
{{out}}
Line 904 ⟶ 1,096:
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<langsyntaxhighlight lang="jq">def count(stream): reduce stream as $i (0; .+1);
 
def words: [inputs]; # one way to read the word list
Line 946 ⟶ 1,138:
words
| pairs as $p
| wordLadder($p[0]; $p[1])</langsyntaxhighlight>
 
{{out}}
Line 959 ⟶ 1,151:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">const dict = Set(split(read("unixdict.txt", String), r"\s+"))
 
function targeted_mutations(str::AbstractString, target::AbstractString)
Line 985 ⟶ 1,177:
println("john to jane: ", targeted_mutations("john", "jane"))
println("child to adult: ", targeted_mutations("child", "adult"))
</langsyntaxhighlight>{{out}}
<pre>
boy to man: [["boy", "bay", "may", "man"], ["boy", "bay", "ban", "man"], ["boy", "bon", "ban", "man"]]
Line 995 ⟶ 1,187:
=={{header|Mathematica}} / {{header|Wolfram Language}}==
{{incorrect|Mathmatica|The requirement is to find the shortest path other examples do John to Jane with 4 intermediate words. Also an impossible example is required: child to adult.}}
<langsyntaxhighlight Mathematicalang="mathematica">db=DeleteDuplicates[RemoveDiacritics[ToLowerCase[Select[DictionaryLookup[],StringLength/*EqualTo[3]]]]];
sel=Select[Subsets[db,{2}],HammingDistance[#[[1]],#[[2]]]==1&];
g=Graph[db,UndirectedEdge@@@sel];
Line 1,009 ⟶ 1,201:
sel=Select[Subsets[db,{2}],HammingDistance[#[[1]],#[[2]]]==1&];
g=Graph[db,UndirectedEdge@@@sel];
FindShortestPath[g,"child","adult"]</langsyntaxhighlight>
{{out}}
<pre>{"boy", "bay", "ban", "man"}
Line 1,017 ⟶ 1,209:
 
=={{header|Nim}}==
<langsyntaxhighlight Nimlang="nim">import sets, strformat, strutils
 
 
Line 1,072 ⟶ 1,264:
echo &"No path from “{start}” to “{target}”."
else:
echo path.join(" → ")</langsyntaxhighlight>
 
{{out}}
Line 1,087 ⟶ 1,279:
===Direct translation===
{{trans|C++}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
 
Line 1,185 ⟶ 1,377:
word_ladder('lead', 'gold');
word_ladder('white', 'black');
word_ladder('bubble', 'tickle');</langsyntaxhighlight>
{{out}}
<pre>boy -> bay -> ban -> man
Line 1,198 ⟶ 1,390:
===Idiomatic version===
<b>Exactly</b> the same algorithm, written in a more Perl-ish style. Is this better, or worse? Maybe both. Interestingly, runs 1/3-rd faster.
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 1,248 ⟶ 1,440:
}
 
word_ladder(split) for 'boy man', 'girl lady', 'john jane', 'child adult';</langsyntaxhighlight>
Same style output.
 
=={{header|Phix}}==
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">words</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">unix_dict</span><span style="color: #0000FF;">()</span>
Line 1,282 ⟶ 1,474:
<span style="color: #000000;">word_ladder</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"john"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"jane"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">word_ladder</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"child"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"adult"</span><span style="color: #0000FF;">)</span>
<!--</langsyntaxhighlight>-->
<small>Aside: an initial poss = filter(poss,"out",{a}) might be prudent, but would only prevent a single next:={} step, at about the same cost as the initial filter anyway.</small>
{{out}}
Line 1,294 ⟶ 1,486:
=={{header|Python}}==
The function ''cache'' is not part of the algorithm but avoid re-download and map re-computing at each re-run.
<langsyntaxhighlight lang="python">import os,sys,zlib,urllib.request
 
def h ( str,x=9 ):
Line 1,341 ⟶ 1,533:
 
for w in ('boy man','girl lady','john jane','alien drool','child adult'):
print( find_path( cache( build_map,load_dico( dico_url )),*w.split()))</langsyntaxhighlight>
 
{{out}}
Line 1,354 ⟶ 1,546:
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
 
(define *unixdict* (delay (with-input-from-file "../../data/unixdict.txt"
Line 1,394 ⟶ 1,586:
(Word-ladder "john" "jane")
(Word-ladder "alien" "drool")
(Word-ladder "child" "adult"))</langsyntaxhighlight>
 
{{out}}
Line 1,445 ⟶ 1,637:
 
=={{header|Raku}}==
<syntaxhighlight lang="raku" perl6line>constant %dict = 'unixdict.txt'.IO.lines
.classify(*.chars)
.map({ .key => .value.Set });
Line 1,481 ⟶ 1,673:
say word_ladder($from, $to)
// "$from into $to cannot be done";
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,488 ⟶ 1,680:
(john cohn conn cone cane jane)
child into adult cannot be done</pre>
 
=={{header|Refal}}==
This program needs to be run with <tt>refal -l48</tt> to allocate enough memory for it to run.
<syntaxhighlight lang="refal">$ENTRY Go {
, <ReadFile 1 'unixdict.txt'>: e.Dict
= <DisplayLadder (e.Dict) ('boy') ('man')>
<DisplayLadder (e.Dict) ('girl') ('lady')>
<DisplayLadder (e.Dict) ('john') ('jane')>
<DisplayLadder (e.Dict) ('child') ('adult')>;
};
 
DisplayLadder {
(e.Dict) (e.From) (e.To),
e.From ' -> ' e.To ': ': e.Header,
<Ladder (e.Dict) (e.From) (e.To)>: {
Impossible = <Prout e.Header 'impossible'>;
Result e.Words = <Prout e.Header <Join ('->') e.Words>>;
};
};
 
Join {
(e.Join) = ;
(e.Join) (e.Word) = e.Word;
(e.Join) (e.Word) e.Words = e.Word e.Join <Join (e.Join) e.Words>;
};
 
ReadFile {
s.Chan e.File =
<Open 'r' s.Chan e.File>
<ReadFile (s.Chan)>;
(s.Chan), <Get s.Chan>: {
0 = ;
e.Line = (e.Line) <ReadFile (s.Chan)>;
};
};
 
Filter {
(e.Fn) = ;
(e.Fn) t.Item e.Items, <Mu e.Fn t.Item>: {
True = t.Item <Filter (e.Fn) e.Items>;
False = <Filter (e.Fn) e.Items>;
};
};
 
SameLen {
(e.Word1) (e.Word2),
<Lenw e.Word1>: s.Len e.Word1,
<Lenw e.Word2>: s.Len e.Word2 = True;
(e.Word1) (e.Word2) = False;
};
 
Diffs {
() () = 0;
(s.X e.Word1) (s.X e.Word2) = <Diffs (e.Word1) (e.Word2)>;
(s.X e.Word1) (s.Y e.Word2) = <+ 1 <Diffs (e.Word1) (e.Word2)>>;
};
 
OneDiff {
t.Word1 t.Word2, <Diffs t.Word1 t.Word2>: {
1 = True;
s.Diffs = False;
};
};
 
Ladder {
(e.Dict) t.From t.To,
<Filter (SameLen t.From) e.Dict>: e.Dict2 =
<Ladder2 ((t.From)) (e.Dict2) t.To>;
};
 
Ladder2 {
(e.Ladders) (e.Dict) t.To,
e.Ladders: e.X (e.Words t.To) e.Y = Result e.Words t.To;
 
(e.Ladders) () t.To = Impossible;
() (e.Dict) t.To = Impossible;
 
((e.Ladder) e.Ladders) (e.Dict) t.To,
e.Ladder: e.1 t.Last,
<Filter (OneDiff t.Last) e.Dict>: e.NextWords,
<RemoveAll (e.NextWords) e.Dict>: e.NextDict,
<AddAll (e.Ladder) e.NextWords>: e.NextLadders
= <Ladder2 (e.Ladders e.NextLadders) (e.NextDict) t.To>;
};
 
RemoveAll {
(e.Remove) = ;
(e.Remove) t.Word e.Words, e.Remove: {
e.X t.Word e.Y = <RemoveAll (e.Remove) e.Words>;
e.Remove = t.Word <RemoveAll (e.Remove) e.Words>;
};
};
 
AddAll {
(e.Ladder) = ;
(e.Ladder) t.Word e.Words =
(e.Ladder t.Word) <AddAll (e.Ladder) e.Words>;
};</syntaxhighlight>
{{out}}
<pre>boy -> man: boy->bay->ban->man
girl -> lady: girl->gill->gall->gale->gaze->laze->lazy->lady
john -> jane: john->cohn->conn->cone->cane->jane
child -> adult: impossible</pre>
 
=={{header|REXX}}==
Line 1,498 ⟶ 1,793:
Programming note: &nbsp; &nbsp; this REXX program uses the &nbsp; '''lower''' &nbsp; BIF &nbsp; which Regina has).
<br>If your REXX doesn't support that BIF, &nbsp; here is an equivalent function:
<langsyntaxhighlight lang="rexx">lower: procedure; parse arg a; @= 'abcdefghijklmnopqrstuvwxyz'; @u= @; upper @u
return translate(a, @, @u)</langsyntaxhighlight>
<langsyntaxhighlight lang="rexx">/*REXX program finds words (within an identified dict.) to solve a word ladder puzzle.*/
parse arg base targ iFID . /*obtain optional arguments from the CL*/
if base=='' | base=="," then base= 'boy' /*Not specified? Then use the default.*/
Line 1,557 ⟶ 1,852:
end /*k*/
end /*i*/
$= $$; return ''</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 1,612 ⟶ 1,907:
=={{header|Ruby}}==
{{trans|Raku}}
<langsyntaxhighlight lang="ruby">require "set"
 
Words = File.open("unixdict.txt").read.split("\n").
Line 1,654 ⟶ 1,949:
puts "#{from} into #{to} cannot be done"
end
end</langsyntaxhighlight>
 
{{Out}}
Line 1,661 ⟶ 1,956:
john → cohn → conn → cone → cane → jane
child into adult cannot be done</pre>
 
=={{header|SETL}}==
<syntaxhighlight lang="setl">program word_ladder;
dict := read_dictionary("unixdict.txt");
testpairs := [['boy', 'man'], ['girl', 'lady'], ['john', 'jane'], ['child', 'adult']];
 
loop for [fromWord, toWord] in testpairs do
l := ladder(dict, fromWord, toWord);
if l = om then
print(fromWord, '->', toWord, 'impossible');
else
print(fromWord, '->', toWord, l);
end if;
end loop;
 
proc ladder(dict, fromWord, toWord);
dict := {word : word in dict | #word = #fromWord};
ladders := [[fromWord]];
dict less:= fromWord;
loop while ladders /= [] do
l fromb ladders;
next := {word : word in onediff(dict, l(#l))};
dict -:= next;
nextls := [l + [word] : word in next];
if exists l in nextls | l(#l) = toWord then
return l;
end if;
ladders +:= nextls;
end loop;
return om;
end proc;
 
proc onediff(rw dict, word);
return {other : other in dict | #other = #word and diffs(word, other) = 1};
end proc;
 
proc diffs(word1, word2);
return +/[if word1(i) = word2(i) then 0 else 1 end : i in [1..#word1]];
end proc;
 
proc read_dictionary(file);
dictfile := open(file, 'r');
dict := {getline(dictfile) : until eof(dictfile)};
close(dictfile);
return dict;
end proc;
end program;</syntaxhighlight>
{{out}}
<pre>boy -> man [boy bay ban man]
girl -> lady [girl gill gall gale gaze laze lazy lady]
john -> jane [john cohn conn cone cane jane]
child -> adult impossible</pre>
 
=={{header|Swift}}==
{{trans|Wren}}
<langsyntaxhighlight lang="swift">import Foundation
 
func oneAway(string1: [Character], string2: [Character]) -> Bool {
Line 1,724 ⟶ 2,071:
} catch {
print(error.localizedDescription)
}</langsyntaxhighlight>
 
{{out}}
Line 1,741 ⟶ 2,088:
{{trans|Phix}}
{{libheader|Wren-sort}}
<langsyntaxhighlight ecmascriptlang="wren">import "io" for File
import "./sort" for Find
 
var words = File.read("unixdict.txt").trim().split("\n")
Line 1,781 ⟶ 2,128:
["child", "adult"]
]
for (pair in pairs) wordLadder.call(pair[0], pair[1])</langsyntaxhighlight>
 
{{out}}