| Bytes | Lang | Time | Link |
|---|---|---|---|
| 093 | R | 240613T190159Z | pajonk |
| 125 | R | 240613T075103Z | int 21h |
| 120 | AWK | 231116T084836Z | Marius_C |
| 064 | AWK | 231226T094016Z | Bubbler |
| 187 | Swift | 231223T153052Z | Annett S |
| 065 | Gema | 231221T223315Z | manatwor |
| 142 | TypeScript's Type System | 231107T130816Z | noodle p |
| 014 | 05AB1E | 231115T095426Z | Kevin Cr |
| 118 | Java JDK | 231110T135034Z | Fhuvi |
| 057 | APL+WIN | 231107T183445Z | Graham |
| 164 | Java SE | 231108T164344Z | Tobias G |
| 055 | Python | 231107T235050Z | Albert.L |
| 083 | Python | 231107T140246Z | mousetai |
| 029 | Perl 5 p | 231108T140610Z | Nahuel F |
| 241 | C# without Implicit global usings | 231109T085125Z | gobes |
| 3862 | Uiua | 231108T225831Z | regr4444 |
| 012 | Nekomata | 231108T035415Z | alephalp |
| 093 | C# | 231108T161409Z | Acer |
| 023 | Retina 0.8.2 | 231107T123410Z | Neil |
| 011 | Stax | 231108T032631Z | jimmy230 |
| 014 | Jelly | 231107T193719Z | Nick Ken |
| 041 | Ruby | 231108T124351Z | G B |
| 059 | JavaScript ES6 | 231107T133402Z | Arnauld |
| 027 | Uiua | 231108T103136Z | Matthew |
| 051 | Python | 231107T174554Z | Phan Trọ |
| 025 | J 9.4 | 231108T004802Z | Bubbler |
| 086 | Python | 231108T021038Z | ShadowRa |
| 014 | Vyxal ≤ v2.21.12 | 231108T003811Z | emanresu |
| 029 | Uiua | 231107T193802Z | Pseudo N |
| 1325 | Vyxal | 231107T121059Z | lyxal |
| nan | J | 231107T221117Z | Jonah |
| 080 | Google Sheets | 231107T191614Z | doubleun |
| 015 | Charcoal | 231107T124756Z | Neil |
| 017 | Jelly | 231107T173032Z | Jonathan |
| 073 | Python 3 | 231107T191814Z | xnor |
| 082 | Python 3.8 | 231107T184049Z | Jonathan |
| 064 | Ruby | 231107T155937Z | Kirill L |
| 209 | Go | 231107T151054Z | bigyihsu |
R, 113 98 93 bytes
Edit: -15 and -5 bytes thanks to Dominic van Essen.
`?`=\(S,a=c("aa","ab","ba","bb","c"))`if`(length(a)>1,sub(a[!i],"",S)?a[i<-!pmatch(a,S,0)],a)
Less sophisticated (straightforward) approach than @int 21h -- Glory to Ukraine --'s, but shorter. And using pmatch function that I learnt thanks to them!
R, 134 131 128 125 bytes
- -3 bytes thanks to pajonk
\(S,s=sub("c","",S),v=strtoi(s,16),u=c(170,171,186,187))`if`(S>s,{for(j in 1:3){u=u[u!=v%%256];v=v%/%256};as.hexmode(u)},"c")
A semi-arithmetic approach: remove "c" (if any) read the rest as a hexadecimal value, get the remainder from division by 0x100, divide by 0x100, 3 times and output the missing number as a hexadecimal.
Missing "c" is treated separately.
AWK, 123 120 bytes
a["aa"];a["ab"];a["ba"];a["bb"];{if(!sub(/c/,z))$0="c";else{for(i=1;i<6;i+=2)delete a[substr($0,i,2)];for(k in a)$0=k}}1
- -3 bytes, thanks to manatwork
Ungolfed :
a["aa"];a["ab"];a["ba"];a["bb"]
{
if($0!~/c/)$0="c"
else{
sub(/c/,"",$0)
for(i=1;i<6;i+=2) delete a[substr($0,i,2)]
for(k in a)$0=k
}
}
1
AWK, 67 64 bytes
patsplit($0,l,/c|[ab]./){$0="aaabbbbac";for(k in l)sub(l[k],a)}1
Removed a semicolon by moving patsplit out to the pattern part (-1), and golfed the regex a bit (-2).
previous answer, 67 bytes:
{patsplit($0,l,/c|[ab]{2}/);$0="aaabbbbac";for(k in l)sub(l[k],a)}1
patsplit($0,l,/c|[ab]{2}/): Split$0(the input string) into valid chunks and store as a list inl./c|../doesn't work because regex matching is done in favor of longer length across all alternatives.$0="aaabbbbac": Replace$0with this fixed string.for(k in l)sub(l[k],a): For each chunk inl, find and remove once from$0. An uninitialized variableais used in place of an empty string.1: An all-match pattern. This causes$0to be printed as a default action.
Replacing without splitting "aaabbbbac" into chunks first works because
- there is only one place to be replaced for
abandba, and - for
aaandbb, it doesn't matter which part of the runs is removed.
Swift, 187 bytes
Short version:
func m(_ s: String)->String{var t:Set=["aa","ab","ba","bb","c"];let s=s.map({String($0)});var i=0;while i<s.count{var x=s[i];if x != "c"{i+=1;x+=s[i];};t.remove(x);i+=1};return t.first!}
Verbose version:
func m2(_ s: String) -> String {
var t:Set = ["aa","ab","ba","bb","c"]
let s = s.map({String($0)})
var i = 0
while i < s.count {
var x = s[i]
if x != "c" {
i += 1
x += s[i]
}
t.remove(x)
i += 1
}
return t.first!
}
Gema, 96 65 characters
c=@set{c;}
??=@set{??;}
\Z=${aa;aa}${ab;ab}${ba;ba}${bb;bb}${c;c}
Sample run:
bash-5.2$ echo -n 'aaabbac' | gema 'c=@set{c;};??=@set{??;};\Z=${aa;aa}${ab;ab}${ba;ba}${bb;bb}${c;c}'
bb
TypeScript's Type System, 144 142 bytes
type F<S,X=0>=S extends`c${infer R}`?F<R,X|"c">:S extends`${infer A}${infer B}${infer R}`?F<R,X|`${A}${B}`>:Exclude<"aa"|"ab"|"ba"|"bb"|"c",X>
Try it at the TypeScript playground.
This is only so long because it has to check for "c" separately because TypeScript annoyingly doesn't let you infer part of a string that is a union of strings of variable length. I also have a different idea that might be shorter, but it's not at all obvious how to accomplish it in TS types so it might take me a while to figure out.
05AB1E, 14 bytes
'cK2ôH.«^12Mhl
Port of @Bubbler's J & Vyxal answer, so make sure to upvote that answer as well!
Try it online or verify all possible I/O test cases.
Explanation:
'cK '# Remove a potential "c" from the (implicit) input-string
2ô # Split it into pairs
H # Convert each string-pair from hexadecimal to a base-10 integer
.« # Reduce this list by:
^ # Bitwise-XORing
12 # Push 12
M # Push the largest value on the stack
h # Convert it from a base-10 integer to (uppercase) hexadecimal
l # Convert it to lowercase
# (after which the result is output implicitly)
Java (JDK), 118 bytes
Adaptation of Arnauld's first JS answer
(this could probably be outgolfed with the new base-16 trick)
s->{var r="";for(var e:("aaabbabbc"+s).split("(?<=\\G..|c)"))r=r.contains(e)?r.replace(e,""):r+e+" ";return r.trim();}
We concatenate the string of all possible values with the string parameter, so that the whole resulting string contains every value twice, except for the "missing" value which will only appear once.
Then we use a regex to split the whole string into either pairs of characters, or the character "c" alone.
We parse the resulting array, and in a string accumulator we add any unseen value (with a space separator) and remove every value already seen. At the end, the accumulator contains only the missing value, and lots of spaces that we trim.
APL+WIN, 69, 63, 57 bytes.
A bit more golfing saves another 6 bytes.
Prompts for string:
((8=⍴i)/'c'),(~s∊⊂[2]((⍴v),2)⍴v←(i←⎕)~'c')/s←,'ab'∘.,'ab'
Java (SE), 164 bytes
b->{if(b.contains("c"))l:for(var c:"aa ab ba bb".split(" ")){for(int i=0;i<6;i+=2)if(c.contains(b.replace("c","").substring(i,i+2)))continue l;return c;}return"c";}
Formatted:
static Function<String, String> f1 = b -> {
if (b.contains("c"))
l:for (var c : "aa ab ba bb".split(" ")) {
for (int i = 0; i < 6; i += 2)
if (c.contains(b.replace("c", "").substring(i, i + 2)))
continue l;
return c;
}
return "c";
};
Logs:
- Golfing tips for I/O defaults respected (lambda function
b) Thanks @corvus_192 ! Stringreplaced withvarat one place (-3 bytes)System.out.printlns replaced withreturns (-31 bytes) Thanks @ceilingcat !return "c";replaced withreturn"c";(-1 byte)
Python, 55 bytes
lambda a:f'{int("cc"+(30*a).strip("ab"),16)%255%192:x}'
This produces 15 (= base - 1) on frame and (if c is present) 15 off frame copies of the input. The sum will therefore be 0 modulo 0x11 x 0x0f. .strip("ab") removes one set of on frame copies of all but c. Adding 0xcc which is the sum of the four possible non c terms mod 0xff yields the missing item unless it is c which is dealt with separately.
Python, 57 bytes
lambda s:" aabbcbaba"[int(s.replace("c",""),14)%195%8::5]
How?
First get rid of the evil frame-shifting "c". Afterwards read as base 14 and add all pairs by reducing modulo 195. Further reduce and produce the answer by indexing into a magic string.
Python, 83 bytes
lambda a:min({'aa','ab','bb','ba','c'}-{a.replace('c','')[i:i+2]for i in[0,2,4,6]})
- -17 bytes thanks to Neil
Perl 5 (-p), 32, 29 bytes
$_=s/c//?eval s/..\K\B/^/gr:c
If c can't be removed returns c otherwise bitwise xor 2 char strings.
-3 bytes thanks to Kjetil S, changing (?!$) (negative lookahead end anchor) with \B (non-word-boundary)
C# (without Implicit global usings), 241 bytes
var v=new System.Collections.Generic.List<string>();int i=0;while(v.Count<4){if(args[0][i]=='c')v.Add("c");else{v.Add(args[0].Substring(i,2));i++;}i++;}foreach(var k in"aa|ab|ba|bb|c".Split('|'))if(!v.Contains(k))System.Console.WriteLine(k);
This is my first golf, and the language isn't very golfable... be indulgent :-)
I didn't find a online compiler which handle input arguments correctly ; so to test this, paste it in a Visual Studio .cs file.
Uiua, 38 characters (62 bytes)
("c";|⊢▽¬∊,⊃(↯¯1_2▽∊,)(/⊂⊞⊂.)"ab")∊@c.
("c";|⊢▽¬∊,⊃(↯¯1_2▽∊,)(/⊂⊞⊂.)"ab")∊@c.
( | )∊@c. # Is 'c' a member of the string?
"c"; # If not, just return 'c'
⊃ (/⊂⊞⊂.)"ab" # Else, generate the list L = ["aa" "ab" "ba" "bb"]
⊃(↯¯1_2▽∊,) # And filter out any the c's from the string (by keeping only members of "ab") and reshape it into a n×2 matrix
⊢▽¬∊, # Return the element of L which does not appear in this matrix.
Nekomata, 12 bytes
ĕ<ĭÐŤʳXH"c"I
The xor trick is borrowed from this answer by Bubbler.
ĕ<ĭÐŤʳXH"c"I
ĕ Pick one char out from the input string
< Check that all remaining chars are less than the picked char
If this does not fail, which means the input contains 'c':
ĭÐ Uninterleave the remaining chars into a pair of strings
Ť Transpose
ʳX Reduce by xor (chars are converted to code points implicitly)
H Convert from code points
I Otherwise:
"c" Return "c"
C#, 93 bytes
x=>"aa ab ba bb c".Split().Except(x.Replace("c","").Chunk(2).Select(z=>""+z[0]+z[1])).First()
Explanation
x => // input string
"aa ab ba bb c".Split() // construct array with the four pairs + c
.Except( // remove from it...
x.Replace("c","") // remove c from input
.Chunk(2) // split into chunks of size 2 (each chunk is a char[])
.Select( // transform each item
z=>""+z[0]+z[1] // convert char[] to string
)
).First(); // first item remaining. this is c if all pairs were removed
Uses .Chunk which isn't supported on tio.run.
Retina 0.8.2, 29 23 bytes
$
¶aaabbbbac
D`c|..
1A`
Try it online! Link includes test cases. Explanation:
$
¶aaabbbbac
Append another copy of the whole list on a separate line.
D`c|..
Remove duplicate elements from the copy.
1A`
Remove the original input.
Stax, 11 bytes
ù¢╓┘0ï<ΣEZ1
Unpacked (13 bytes):
'c|^2/M{{SkmT
Explanations:
'c|^ Set xor with "c" without deduplication or changing of order.
2/ Split into 2 character chunks.
M Transpose (aka zip).
{{Skm Map by reduce by xor of the character codes.
The two lines work like reducing by vectorized xor.
T Trim on the right. For some reasons null bytes are also
printed as spaces and are also removed.
The difficult part is to find the right language that had all the required features. Many languages have them but they may not be the default behavior of the most obvious operator, so I thought they don't. The most important one is set xor (set symmetric difference) without deduplication. Others are splitting to equally sized chunks, and doing mathematics on character values. But Stax doesn't have map and reduce operators with block starters omitted for a single character operation.
Vyxal, 87 bitsv2, 11 10.875 bytes
\cÞ⊍C2ẇƒ꘍C∑Ǎ
Bitstring:
011010100001110110101010000101011001101011111101101001000110111010111001101110101010000
Explanations:
\cÞ⊍ Set xor with "c" without deduplication or changing of order.
C Convert characters to numbers.
2ẇ Split into 2 character chunks.
ƒ꘍ Reduce by automatically vectorized xor.
C Convert back to characters.
∑ Concatenate.
Ǎ Remove non-letters, i.e. the null byte if the answer is "c".
Jelly, 15 14 bytes
ḟ”cQp`ḟs2$Ʋȯ”c
Thanks to @JonathanAllan for saving a byte!
A full program taking a string as its argument and printing the missing piece. (It can also be used as a monadic link, but will return a Jelly string if the result is one of the ab permutations and a single character for c.)
Explanation
ḟ”cQp`ḟs2$Ʋȯ”c
ḟ”c | Filter out "c"
Ʋ | Following as a monad:
Q | - Uniquify
p` | - Cartesian product with itself
ḟ | - Filter out
s2$ | - The c-less input split into twos
ȯ”c | Or "c"
Alternative approach: Jelly, 10 bytes
œ^”cs2œ^"/
This is a translation of @jimmy23013’s clever Stax answer; I’ve not replaced my main one since I wanted to preserve my different approach, but this is clearly shorter!
œ^”cŒœœ^/€ would also work for ten.
JavaScript (ES6), 59 bytes
s=>(s+"aaabbabbc").replace(q=/c|../g,s=>(q[s]^=1)?o=s:0)&&o
Commented
s => // s = input string
(s + "aaabbabbc") // append all the patterns to s
.replace( // replace:
q = // we use q as an object to keep track of
// encountered patterns
/c|../g, // a pattern is either 'c' or 2 characters
s => // for each matched pattern s:
(q[s] ^= 1) ? // if this is the first time we see it:
o = s // save it into o
: // else:
0 // do nothing
) && o // end of replace(); return o (i.e. the last
// pattern seen for the first time)
JavaScript (ES6), 52 bytes
Porting Phan Trọng Nhân's excellent answer is definitely shorter.
s=>(216-`0x${s}`.replace('c','0c')%255).toString(16)
JavaScript (ES6), 64 bytes
My original answer.
s=>"b__c__aab"[q=s.replace(/c|../g,s=>'0x'+s|0)%9]+["ab"[q%7%5]]
How?
Identifying the missing pattern
We look for the relevant patterns in the input string with /c|../g and replace each of them with its decimal value when parsed as hexadecimal.
This gives:
| original pattern | replaced with |
|---|---|
| aa | 170 |
| ab | 171 |
| ba | 186 |
| bb | 187 |
| c | 12 |
For instance, "abbabbc" is turned into "17118618712".
It is a well known fact that \$n \bmod 9\$ is the sum of the decimal digits of \$n\$ modulo \$9\$. (Obviously, the order of the digits doesn't matter.)
Because each decimal pattern described above has a different remainder modulo \$9\$, we can identify the missing one by just reducing the entire transformed string modulo \$9\$:
| \$q=n \bmod 9\$ | missing pattern |
|---|---|
| 0 | ba |
| 3 | c |
| 6 | ab |
| 7 | aa |
| 8 | bb |
Output
We use a 9-character lookup string for the first character:
"b__c__aab"[q=...]
We could also use the following trick, which is unfortunately just as long:
"bac"[7/(q=...)|0]
And we use a shorter lookup string with a modulo chain for the 2nd character, wrapped into brackets so that undefined is turned into an empty string for \$q=3\$:
["ab"[q%7%5]]
Uiua, 27 bytes
?"c"⍜(-@a)(◿2/+↯~2▽<2.)=8⧻.
Explanation:
For the cases where 'c' is in the string, this uses a little trick by converting 'a' to 0 and 'b' to 1, then the XOR of the three pairs results in the missing pair.
?"c" =8⧻. # If the string length is 8, return "c"
⍜(-@a)( ) # Subtract char 'a' from the string to get an
# array where a=0, b=1, c=2. Then perform the
# following and add char 'a' back at the end:
▽<2. # Remove any 2s (char 'c')
↯~2 # Reshape to pairs
◿2/+ # XOR by adding the pairs and taking modulo 2
Example:
Input: "cbbbaab"
| Operation | Stack (top on left): |
|---|---|
| "cbbbaab" | |
⧻. |
7 "cbbbaab" |
=8 |
0 "cbbbaab" |
?"c" |
"cbbbaab" |
⍜(-@a)( |
[2 1 1 1 0 0 1] |
▽<2. |
[1 1 1 0 0 1] |
↯~2 |
[[1 1] [1 0] [0 1]] |
/+ |
[2 2] |
◿2 |
[0 0] |
) |
"aa" |
Python, 55 51 bytes
lambda a:'%x'%(-int(a.replace('c','0c'),16)%255-39)
Explain:
- Observe that 'a', 'b', 'c' are base 16 digits.
- I learnt from Albert.Lang's solution that we can use int(a.replace('c',''),x)%(x*x-1) to extract sum of character at odd and even position.
- Replace 'c' with '0c' allow us to subtract by 39 to get 'c' without affecting other output cases (Original idea is to replace 'c' with '33', by xnor).
- Finally, '%x'% is used to convert int back to base 16.
Logs:
- Saved 4 bytes thank to xnor's suggests.
Python, 94 92 bytes
lambda a:('c'in a)*''.join(chr(390-sum(map(ord,a.replace('c','')[i::2])))for i in(0,1))or'c'
Logs:
- Saved 2 bytes thank to Jonathan Allan's tip.
J 9.4, 25 bytes
(]>.&XOR&.dfh _2]\-.)&'c'
dfh and hfd were recently modified to have each other as inverses. ATO doesn't have the change yet.
J, 26 bytes
12(hfd@>.XOR)_2 dfh\-.&'c'
The XOR of three of aa, ab, ba, bb interpreted as hexadecimal (or any base that is a greater power of 2) is the missing one, and the XOR of all four is zero. When all four are present, the XOR value is replaced with 12 before converting back to hexadecimal.
12(hfd@>.XOR)_2 dfh\-.&'c' input: a string
-.&'c' remove 'c'
_2 dfh\ convert each chunk of 2 with "hex->int"
( XOR) reduce by bitwise XOR
12 >. max with 12; if the result is 0, use 12 instead
hfd@ convert with "int->hex"
Vyxal, 99 bitsv2, 12.375 bytes
\co2ẇHƒ꘍12∴k6τ
Bitstring:
011010100001111110010011010110100010110000110101011111111011101001101110100010100100100101011011010
Literal translation of the J solution above.
\co2ẇHƒ꘍12∴k6τ
\co remove 'c'
2ẇ chunks of 2
H convert each with "hex->int"
ƒ꘍ reduce by bitwise XOR
12∴ max with 12
k6τ into base "lower hex digits"; convert with "int->hex"
Python, 86 bytes
lambda s:[*{'aa','ab','ba','bb'}-{*map(str.__add__,*[filter('c'.__ne__,s)]*2)},'c'][0]
No magic numbers here, just another approach to solving in Python, this one a straightforward-ish golfing of removing each of the pairs in the string (with 'c' removed) from the initial set, and if none are left, defaulting to 'c'.
Vyxal ≤ v2.21.12, 14 bytes
\cẆǒf«H₴Ǐ3F«ǒ⊍
Try it Online! (code modified to work on current version)
I'm using an older version of Vyxal because for some reason ǒ was modified in a recent version. Also, yes there's another Vyxal answer, but this one's shorter in regular SBCS bytes.
Ẇ # Split (keeping delimiter) on
\c # "c"
ǒf # Cut each into chunks of length 2
«H₴Ǐ3F« # Compressed string "abaabbbac"
ǒ # Cut into chunks of length 2
⊍ # Take the set difference
Uiua, 31 29 bytes
Two bytes saved by replacing "ab" with ⊝.
⊔⊡⊗0⊐⊃∊'⊂⊙"c"∩(↯~2)⊞⊟.⊝.▽≠@c.
Interestingly, since Uiua has an autoformatter that runs during execution, afterwards it is 30 bytes. (Specifically, '⊂⊙"c" is turned into (⊂⊙"c"))
Explanation
▽≠@c. # Remove all c from the string
⊞⊟.⊝. # construct "ab" and generate all pairs of its elements
∩(↯~2) # Simultaneously:
# flatten the table into an array of 2-char strings
# chunk the input (sans c) into 2-char strings
⊐⊃∊ # Both find which of aa,ab,ba,bb are in chunked input...
'⊂⊙"c" # ...and add c to the array of aa,ab,ba,bb
⊗0 # Index of pair that was not found (4 if all were found)
⊔⊡ # Select from aa,ab,ba,bb,c
Vyxal, 106 bitsv2, 13.25 bytes
‛ab2↔\cpṖ'ḣ∑?=;hh
Bitstring:
1010100100110111101010010101000011000010000011011100110001101010100111101011100111001010011100110100101110
Explained
«F^ǒ⇩v«2ẇṖ'ḣ∑?=;hh
Ṗ # Permutations of
«F^ǒ⇩v« # The string "aaabbabbc"
2ẇ # split into chunks of size 2
' ; # Filtered by:
ḣ # the permutation with the head removed
∑ # joined into a single string
?= # equals the input.
hh # Get the first item of the first item in that list.
💎
Created with the help of Luminespire.
J, 31 30 29 bytes
(e.~{];,@{@;~@-.-._2<\-.)&'c'
-1 thanks to ovs
,@{@;~@-.All valid 2 char pairs, constructed by the crossing the input with itself after removing 'c'. This will contain dups but is guaranteed to have all the valid pairs.-.Minus_2<\-.All 2 char input pairs, formed after removing 'c'- At this point we will either have our answer or the empty list (in the case that 'c' itself is missing)
];Prepend 'c'- Now we will have an answer that looks like
c;ab(in the case we're missing a 2 char sequence) or simplyc(in the case we're missing 'c')
- Now we will have an answer that looks like
e.~{If 'c' is an element of the input, take the 2nd element. Otherwise take the first (ie, return 'c' itself).
J, 30 bytes
(-.~,&;(,{;~'ab')-._2<\-.)&'c'
A similar alternate solution that has unboxed output and no conditional logic. Feels slightly cleaner to me despite being 1 byte longer.
Google Sheets, 80 bytes
=substitute(regexreplace("aa|ab|ba|bb|c",regexreplace(A1,"(c|..)","$1|"),),"|",)
Put the input in cell A1 and the formula in B1.
Nothing clever here, just two replaces, plus removal of hardcoded separators.
Translation to JavaScript (90 bytes, non-competing):
s=>(r=(x,y,z)=>x.replace(RegExp(y,'g'),z||''))(r('aa#ab#ba#bb#c',r(s,'(c|..)','$1|')),'#')
Charcoal, 19 15 bytes
⌊⁻⪪”&∨O⊕”²⪪⁻Sc²
Try it online! Link is to verbose version of code. Explanation:
”...” Compressed string `aaabbbbac`
⪪ ² Split into pairs of characters
⁻ Remove elements from
S Input string
⁻ c Remove the `c`
⪪ ² Split into pairs of characters
⌊ Take the minimum
Implicitly print
If all of the a/b pairs were successfully removed then the only remaining element is the trailing c otherwise the minimum element is the missing a/b pair.
Jelly, 20 18 17 bytes
-3 thanks to Nick Kennedy reminding me to golf the magic table.
⁾abp`”cṭŒ!F=¥Þ⁸ṪṪ
A full program that accepts the flattened, redacted permutation and prints the missing item.
Try it online! Or see all twenty four of each of the five choices here.
How?
Brute force...
⁾abp`”cṭŒ!F=¥Þ⁸ṪṪ - Link: list of characters, X
⁾ab - "ab"
p` - Cartesian product with itself -> ["aa","ab","ba","bb"]
”cṭ - tack 'c' character -> ["ab","ba","bb","aa",'c']
Œ! - all permutations
Þ - sort by:
¥ ⁸ - last two links as a dyad - f(Permutation, X):
F - flatten the Permutation
= - equals X (vectorised)
Ṫ - tail -> permutation with matching prefix
Ṫ - tail -> the missing pair
- implicit print
Non-brute-force 21 bytes
I quite like this non-brute force method at 21 bytes though (maybe it can be improved upon?)...
ḟ”cOḤÐoS;Ḥ$%5Qị“bbaac
A full program that accepts the flattened, redacted permutation and prints the missing item.
Try it online! Or see all twenty four of each of the five choices here.
How?
ḟ”cOḤÐoS;Ḥ$%5Qị“bbaac - Main Link: list of characters
ḟ”c - remove any 'c' character
O - cast to ordinal values ('a' -> 97, 'b' -> 98)
Ðo - apply to odd indices (first, third, ...):
Ḥ - double
S - sum
;Ḥ$ - concatenate double this value -> [sum, 2×sum]
%5 - modulo five -> [sum%5, (2×sum)%5]
Q - deduplicate
ị“bbaac - index into "bbaac"
Examples:
1. missing "c" "aaabbbba"
-> "aaabbbba" (removed 'c'; no change)
-> [97,97,97,98,98,98,98,97] (cast to ordinals)
-> [194,97,194,98,196,98,194,97] (double values at odd indices)
-> 1170 (sum those)
-> [1170, 2340] (concatenate double itself)
-> [0, 0] (modulo five)
-> [0] (deduplicate)
-> "c" (index into "bbaac" - Note that indexing is one-based and modular)
2. missing "bb" "aaacbba"
-> "aaabba" (removed 'c')
-> [97,97,97,98,98,97] (cast to ordinals)
-> [194,97,194,98,196,97] (double values at odd indices)
-> 876 (sum those - i.e. \$1170 - (2 \times 98) - 98 = 876\$)
-> [876, 1752] (concatenate double itself)
-> [1, 2] (modulo five)
-> [1, 2] (deduplicate; no change)
-> "bb" (index into "bbaac")
Python 3, 73 bytes
b,*l=0,{'c'},{0}
for c in input():l[b]^={c};b^=c<'c'
print(str(l)[3::10])
71 bytes
b=k=62
for c in input():k^=ord(c)*b;b^=c<'c'
print("babbaac"[k%7:][:2])
Python 3.8, 82 bytes
lambda a:("cbbaa"*469)[(k:=sum(map(ord,(r:=a.replace('c',''))+r[::2])))::k][r==a:]
An unnamed function that accepts the flattened, redacted permutation and returns the missing item.
A port of my non-brute-force Jelly solution.
Ruby, 64 bytes
->s{a=%w[aa ab ba bb c];a.find{[*(a-[_1]).permutation].join[s]}}
Go, 209 bytes
import."strings"
func f(s string)string{r,S:=ReplaceAll(s,"c",""),map[string]int{"aa":0,"ab":0,"ba":0,"bb":0}
for i:=0;i<len(r);i+=2{k:=r[i:i+2]
if S[k]<1{S[k]++}}
for k,v:=range S{if v<1{return k}}
return"c"}
Explanation
import."strings"
func f(s string)string{
// remove "c" from the input. guaranteed to be even length
r:=ReplaceAll(s,"c","")
// map to keep track of seen pairs
S:=map[string]int{"aa":0,"ab":0,"ba":0,"bb":0}
// for each pair of chars...
for i:=0;i<len(r);i+=2{
// get the pair
k:=r[i:i+2]
// if pair is not seen yet, increment the counter
if S[k]<1{S[k]++}}
// for each pair...
for k,v:=range S{
// if not seen, return that pair
if v<1{return k}}
// otherwise return "c"
return"c"}