42
\$\begingroup\$

In Wordle, you try to guess a secret word, and some letters in your guess are highlighted to give you hints.

If you guess a letter which matches the letter in the same position in the secret word, the letter will be highlighted green. For example, if the secret word is LEMON and you guess BEACH, then the E will be highlighted green.

If you guess a letter which is present in the secret word, but not in the correct corresponding position, it will be highlighted yellow.

If a letter appears more times in the guess than it does in the secret word, only upto as many occur in the secret may be highlighted. If any of the occurrences are in the same place, they should be preferentially highlighted green, leaving earlier letters unhighlighted if necessary.

For example, with the secret LEMON and the guess SCOOP, the second O will be green, because it is in the right place, but the first O will be unhighlighted, because there is only one O in the secret, and one O has already been highlighted.

Any of the remaining letters in the secret may be highlighted yellow if they match, as long as the right number are highlighted in total. For example, with the secret LEMON and the guess GOOSE, only one of the Os should be highlighted; it does not matter which.

Task

Given two five-letter strings, a secret and a guess, highlight the letters in the guess according to the rules above.

You can "highlight" the letters using any reasonable output format. For example:

  • a length-5 list of highlight values
  • a list of 5 pairs of (letter, highlight value)
  • a mapping from indices 0-4 or 1-5 to the highlight at that position

You can choose any three distinct values to represent unhighlighted, yellow, and green. (For example, 0/1/-1, or ""/"Y"/"G"...)

If in doubt about the "reasonable"ness of your output format, please ask. It must be unambiguous about the ordering of highlighting in case of double letters.

Rules

  • You may assume the inputs are both of length 5 and contain only ASCII letters
  • You may choose whether to accept input in uppercase or lowercase
  • You may take input as a string, a list of character codes, or a list of alphabet indices (in \$ [0, 25] \$ or \$ [1, 26] \$)
  • You may use any standard I/O method
  • Standard loopholes are forbidden
  • This is , so the shortest code in bytes wins

Test cases

All using the secret word HELLO: \$ \require{color} \newcommand{\qG}[1]{\colorbox{##0f0}{$ \mathtt #1 $}} \newcommand{\qY}[1]{\colorbox{##ff0}{$ \mathtt #1 $}} \newcommand{\qW}[1]{\colorbox{ ##eee}{$ \mathtt #1 $}} \$

  • SCRAP -> \$ \qW S \qW C \qW R \qW A \qW P \$
  • HELLO -> \$ \qG H \qG E \qG L \qG L \qG O \$
  • EPOCH -> \$ \qY E \qW P \qY O \qW C \qY H \$
  • CIVIL -> \$ \qW C \qW I \qW V \qW I \qY L \$
  • BELCH -> \$ \qW B \qG E \qG L \qW C \qY H \$
  • ZOOMS -> \$ \qW Z \qY O \qW O \qW M \qW S \$ or \$ \qW Z \qW O \qY O \qW M \qW S \$
  • LLAMA -> \$ \qY L \qY L \qW A \qW M \qW A \$
  • EERIE -> \$ \qW E \qG E \qW R \qW I \qW E \$
  • HALAL -> \$ \qG H \qW A \qG L \qW A \qY L \$
  • LLLXX -> \$ \qY L \qW L \qG L \qW X \qW X \$ or \$ \qW L \qY L \qG L \qW X \qW X \$
  • LLLLL -> \$ \qW L \qW L \qG L \qG L \qW L \$

Copy and paste friendly format

\$\endgroup\$
8
  • \$\begingroup\$ Sandbox \$\endgroup\$
    – pxeger
    Jan 25 at 7:42
  • \$\begingroup\$ I assume we're allowed to replace the green/yellow values with a distinct value, and keeping the grey values unchanged (which the Retina answer already does for example)? It isn't specifically mentioned, hence the question. \$\endgroup\$ Jan 25 at 9:23
  • \$\begingroup\$ @KevinCruijssen Actually that was probably me not reading the challenge well enough. I'll update my answer. \$\endgroup\$
    – Neil
    Jan 25 at 9:48
  • 1
    \$\begingroup\$ @KevinCruijssen Yes, it's fine; I class it as "any reasonable format". \$\endgroup\$
    – pxeger
    Jan 25 at 10:04
  • 1
    \$\begingroup\$ @TobySpeight Yes, it is pretty much the same rules as Mastermind (apart from the restriction that it must be a valid English word, but that doesn't matter for this challenge). We have had some Mastermind-related challenges in the past which may interest you: codegolf.stackexchange.com/search?q=mastermind+is:q \$\endgroup\$
    – pxeger
    Jan 29 at 17:49

17 Answers 17

12
\$\begingroup\$

BQN, 27 24 bytesSBCS

Returns 0 for white, 1 for yellow and 2 for green.

+`⊸×∘≠⊏2∾(≠/⊣)(⊒<≠∘⊣)≠/⊢

Run online!

This is a golfed version of my Judge function from the Wordle solver challenge, with an improvement suggested by Marshall.
There might another approach more suitable for .

This is a tacit function taking the guess on the right and the secret on the left.
≠/⊢ / ≠/⊣ Remove fully correct letters from the guess / secret.
Progressive indices of the shortened guess inside the shortened secret. Progressive means that no index is output twice and if a value is not available, the length of the vector is returned.
<≠∘⊣ For each index, is this less than the length of the shortened secret?
2∾ Prepend a 2 to this boolean vector.
+`⊸×∘≠ 0s at the green positions, positive integers in increasing order at the other positions.
Index with that into the vector.

The part +`⊸×∘≠⊏2∾ is mostly there to invert the ≠/, it would be nice if ≠/⁼ would work instead.

"HELLO" (≠/⊢) "LLLXX"
# "LLXX"
"HELLO" (≠/⊣) "LLLXX"
# "HELO"
"HELO" (⊒) "LLXX"
# ⟨ 2 4 4 4 ⟩
"HELO" (⊒<≠∘⊣) "LLXX"
# ⟨ 1 0 0 0 ⟩
"HELLO" (+`⊸×∘≠) "LLLXX"
# ⟨ 1 2 0 3 4 ⟩
1‿2‿0‿3‿4⊏2∾1‿0‿0‿0
# ⟨ 1 0 2 0 0 ⟩
\$\endgroup\$
10
\$\begingroup\$

Perl 5 + -pF, 57 bytes

Returns 2 for green, 1 for yellow and leaves others as they were.

This example pretty prints using ANSI escape codes!

$_=<>;s/./$F[pos]=~s!$&!#!?2:$&/ge;eval's/$F[$-++]/1/;'x5

Try it online!

Explanation

Initial (implicit via -p) input (the target word) is stored in $_ and split into @F and the guess is then stored in $_ instead. s///ubstitute each letter with: if s///ubstituting $& (the current match) with # is successful, 2, otherwise itself. Then s///ubstitute each index of @F left in $_ (s/// works on $_ by default) with 1.

\$\endgroup\$
2
  • \$\begingroup\$ Wow, that sandbox is cool! \$\endgroup\$
    – pxeger
    Jan 25 at 12:47
  • \$\begingroup\$ Heh, thanks! It's no ATO but, as time allows, I'm hoping to add in more WASM wrappers for other langs. Ruby and Python already exist and should be easy enough to use. I've wanted to have a proper shareable terminal without using asciinema for a while so figured I should just do it! :) \$\endgroup\$ Jan 25 at 12:51
9
\$\begingroup\$

05AB1E, 14 bytes

øDÆĀ*ø`0Kvy®.;

Input as a list of 1-based alphabet indices; modifies the list to change green to 0 and yellow to -1 (grey values remain the same).

Try it online or verify all test cases.

Explanation:

ø              # Zip the two (implicit) input-lists together, creating pairs
 D             # Duplicate this list of pairs
  Æ            # Reduce each inner pair by subtracting
   Ā           # Check for each that it's NOT 0 (0 if 0; 1 otherwise)
    *          # Multiply that to the pairs
     ø         # Zip/transpose; swapping rows/columns
      `        # Pop and push both lists separated to the stack
       0K      # Remove all 0s from the top list
         v     # Foreach `y` over the remaining values:
          y®.; #  Replace the first `y` with -1 in the other list
               # (after which the result is output implicitly)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ @Shaggy "You may take input as a string, a list of character codes, or a list of alphabet indices (in \$[0, 25]\$ or \$[1, 26]\$)." \$\endgroup\$
    – Makonede
    Jan 26 at 4:09
  • \$\begingroup\$ @Shaggy As mentioned by Makonede above, the third rule states this is an allowed input format. And the output format I'm using is allowed in the comments under the challenge. \$\endgroup\$ Jan 26 at 7:31
7
\$\begingroup\$

R, 84 80 bytes

function(s,g){e=s!=g;for(i in 1:5)s[x]=g[i]=1+is.na(x<-which(s*e==g[i])[1]);g*e}

Try it online!

My golfing skills are quite rusty after a long break, but here it goes anyway.

Takes input as a vector of codepoints, outputs 0 for exact match, 1 for inexact match, 2 - for miss (the reverse of what is given in test cases).

\$\endgroup\$
1
  • \$\begingroup\$ R4.1 now supports short-hand notation for functions, i.e. function(s,g) is equivalent to \(s,g). \$\endgroup\$
    – Bob Jansen
    Jan 27 at 15:22
6
\$\begingroup\$

Retina 0.8.2, 45 bytes

+`(\w)(.{5})\1
+$2+
+`(\w)(.*,.*)\1
-$2-
,.*

Try it online! Link includes test cases. Takes input as two comma-separated words. Matching letters are changed to + and near-misses are changed to -. Explanation:

+`(\w)(.{5})\1
+$2+

Change all matching letters to +s (in the secret word too, so that it doesn't match later.)

+`(\w)(.*,.*)\1
-$2-

Change all near misses to -s.

,.*

Delete the secret word.

\$\endgroup\$
0
6
\$\begingroup\$

Haskell, 112 bytes

import Data.List
f(x:y,z)=[0^x|elem x z]:f(y,delete x z)
f _=[]
x?z|x==z=(0,0)|1>0=(x,z)
((f.unzip).).zipWith(?)

Try it online!

Takes input as a list of integers on the range \$[1,26]\$. Outputs a list of [] for no match [1] for perfect match and [0] for imperfect match.

This feels like it could be shorter. Having to import delete is costly.

\$\endgroup\$
4
\$\begingroup\$

Python 3, 113 bytes

lambda g,w:[g[i]-w[i]and~((g[:i]+[a-b or b for a,b in zip(w,g)][i:]).count(g[i])<w.count(g[i]))for i in range(5)]

Try it online!

Uses -1 for gray, -2 for yellow and 0 for green. A further 3 bytes can be saved if -1 is replaced by False and -2 by True, but I dislike this output format, since False==0.

Input is a list of charcodes

\$\endgroup\$
4
\$\begingroup\$

JavaScript, 76b   72b   69b

Solution found by @subzey and me while golfing the MiniWordle project.

Thanks to @emanresu for the further improvements

// a is the correct word (array of letters)
// b is the guessed word (array of letters)

a=>b=>b.map((s,i)=>s==a[i]?a[i]=0:s).map(s=>s?a[x=a.indexOf(s)]=~x:1)

Returns an array of 5 digits. 0 = black, 1 = green, anything else = yellow

For example: f([..."TEETH"])([..."EERIE"]) == [-3, 1, 0, 0, 0]

\$\endgroup\$
2
  • 3
    \$\begingroup\$ The parentheses around a[x=a.indexOf(s)]=~x are unnecessary. Also, if you take input uppercase, you can replace s<"~" with s<{} for -1, and you can take input curried (a=>b=>...) for another -1. \$\endgroup\$
    – emanresu A
    Feb 11 at 6:09
  • \$\begingroup\$ thanks @emanresu! I'm gonna update my answer :) \$\endgroup\$
    – xem
    Feb 11 at 15:45
3
\$\begingroup\$

Charcoal, 33 bytes

⭆θ⎇⁼ι§ηκ+§.-‹№E…θκ⁻λ§ημι№Eη⁻λ§θμι

Try it online! Link is to verbose version of code. Outputs + for exact match, - for near miss and . for mismatch. Explanation:

 θ                                  Guessed word
⭆                                   Map over letters
    ι                               Current letter
   ⁼                                Equal to
      η                             Secret word
     §                              Indexed by
       κ                            Current index
  ⎇                                 If true then
        +                           Literal string `+` else
          .-                        Literal string `.-`
         §                          Indexed by
             №                      Count of
                       ι            Current letter in
                θ                   Guessed word
               …                    Truncated to length
                 κ                  Current index
              E                     Map over letters
                   λ                Inner letter
                  ⁻                 Remove match of
                     η              Secret word
                    §               Indexed by
                      μ             Inner index
            ‹                       Is less than
                        №           Count of
                                ι   Current letter in
                          η         Secret word
                         E          Map over letters
                            λ       Inner letter
                           ⁻        Remove match of
                              θ     Guessed word
                             §      Indexed by
                               μ    Inner index
                                    Implicitly print
\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 63 bytes

s=>g=>g.map((u,i)=>s[i]-u&&s.some((v,j)=>g[j]==v|u-v?0:s[j]=1))

Try it online!

Input array of code points, Output array of 0 = Green, true = Yellow, false = Unhighlighted.

\$\endgroup\$
0
3
\$\begingroup\$

C (gcc), 125 122 117 bytes

#define F for(i=5;i--;)g[i]
i;f(s,g,p)char*s,*g,*p;{F==s[i]?s[i]=1,g[i]=2:0;F,(p=index(g,s[i]))?*p=3:0;F>3?g[i]=4:0;}

Try it online!

Saved 5 bytes thanks to tsh!!!

Inputs a secret and a guess as two strings.
Returns the "highlights" as a list of \$2\$s, \$3\$s, and \$4\$s in the second input string.
With \$2\$ for green, \$3\$ for yellow, and \$4\$ for unhighlighted.

\$\endgroup\$
2
  • \$\begingroup\$ A quick and dirty hack: #define F for(i=5;i--;)g[i], i;f(s,g,p)char*s,*g,*p;{F==s[i]?s[i]=1,g[i]=2:0;F,(p=index(g,s[i]))?*p=3:0;F>3?g[i]=4:0;} \$\endgroup\$
    – tsh
    Jan 26 at 1:38
  • \$\begingroup\$ @tsh Quick and dirty does it nicely - thanks! :D \$\endgroup\$
    – Noodle9
    Jan 26 at 8:13
2
\$\begingroup\$

JavaScript (Node.js), 78 bytes

a=>b=>b.map(y=(x,i)=>x-(c=a[i])&&(y[c]=-~y[c]*2,x)).map((x,i)=>x&&!(y[x]>>=1))

Try it online!

Input charcode/[1,26], output true(no), 0(green), false(yellow)

JavaScript (Node.js), 82 bytes

a=>b=>b.map(y=(x,i)=>x!=(c=a[i])&&(y[c]=-~y[c],x)).map((x,i)=>x&&~~y[x]&&!!y[x]--)

Try it online!

0(no match), false(green), true(yellow)

\$\endgroup\$
2
  • 2
    \$\begingroup\$ @Shaggy You may take input as a string, a list of character codes, or a list of alphabet indices (in [0,25] or [1,26]) \$\endgroup\$
    – l4m2
    Jan 26 at 4:43
  • \$\begingroup\$ Hi @l4m2, congrats for your 82b answer, I realized it was better than the one I had implemented in my MiniWordle clone, so I used yours and put your name in the project's credits: xem.github.io/MiniWordle Cheers! \$\endgroup\$
    – xem
    Feb 10 at 7:55
2
\$\begingroup\$

Python 3.8 (pre-release), 92 bytes

Returns a list of -1 for Green, False for Yellow and True for not highlighted.

lambda*r,c='':[-(a==b)or(c:=c+b).count(b)>sum(y!=x==b for x,y in zip(*r))for a,b in zip(*r)]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Jelly, 18 17 bytes

o@=
çW;œ-\⁻Ɲʋç@+=

Try it online!

-1 because there was a completely extraneous ɗ

Target on left, guess on right; 0 for gray, 1 for yellow, 2 for green.

Absolutely dreadful... There ought to be some sort of -based solution, but I've had no luck yet.

o@=    Dyadic helper link: mask out exact matches
  =    For each pair of corresponding elements, are they equal?
o@     Replace 0s with elements from the left argument, leaving 1s unchanged.

çW;œ-\⁻Ɲʋç@+=    Main link
ç                Mask matches out of the target,
         ç@      mask matches out of the guess,
        ʋ        and with those on the left and right:
 W;  \           Scan across the guess, starting with the masked target, by
   œ-            multiset difference;
       Ɲ         for each pair of adjacent scan results,
      ⁻          are they not equal?
           +=    Add that to the mask of exact matches.
\$\endgroup\$
2
\$\begingroup\$

Julia 1.6, 72 bytes

a\b=(* =.==;c=a*b;b[c]=a[c].=0;c-[sum(b[i]b[1:i])>sum(b[i]a) for i=1:5])

Attempt This Online!

Fixed and improved version of mbeltagy's answer

Needs version 1.6+ for (*) = (.==). 73 bytes in Julia 1.0
Inputs are vectors of characters, and the output is a vector with 1 for green, 0 for yellow, and -1 for uncolored

\$\endgroup\$
2
\$\begingroup\$

Vyxal t, 24 23 21 bytes

Z⁰¹-ḃ*∩÷$£0o(¥nuøḞ£)¥

Try it Online!

or Run all the test cases (it took me way longer to write the code to run the test cases than the program itself lol)

Port of 05AB1E answer. Can probably be golfed down a ton.

-1 byte thanks to Aaroneous Miller

\$\endgroup\$
1
1
\$\begingroup\$

Python 2, 95 bytes

lambda g,t:[not a or a in t and t.remove(a)for a in[a[a==b:]or t.remove(a)for a,b in zip(g,t)]]

Try it online!

Loops over the guess twice, while removing characters from the target. Direct matches are removed in the first loop, indirect matches in the second. Requires two lists as input. Outputs a list containing 5 elements: True for direct match, None for indirect match and False for no match.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.