# Which ghosts are missing?

In this challenge, given a list of ghosts from Pac-Man, you must output which ghosts are missing. You must do it in as few bytes as you can

## Input

Input will consist of a string or list, which will include a number ghosts, which could include;

• Inky
• Pinky
• Clyde

However, input may also include Pac-Man (with that punctuation). So, the maximum amount of items in a list will be five, in any order. It can be assumed that no invalid items will be in the list

## Output

Output will consist of a string, or list. This will include of all the ghosts that are not in the input, in any order. However, if Pac-Man is in the input, all ghosts will be considered missing (because he eats them).

## Test cases

input: Clyde
output: Blinky, Inky, Pinky
alternate output: Inky, Pinky, Blinky
or one of the other 4 permutations

input: Clyde, Blinky # or however you delimit it
output: Inky, Pinky
alt: Pinky, Inky

input: Pac-Man, Clyde
Output: Blinky, Inky, Pinky, Clyde
or you could output one of the other 23 permutations

input:[null]
Output: Blinky, Inky, Pinky, Clyde
or you could output one of the other 23 permutations


This is codegolf, so the lower the bytecount, the better.

• If there aren't any ghosts, is the input an empty string, or [null]? – Zizouz212 Jul 19 '16 at 1:35
• it is an empty string. – Destructible Lemon Jul 19 '16 at 1:36
• Are the input and output formats strictly string types, or can we use a list? The specs say they're strings, but then they're referred to as lists. – atlasologist Jul 19 '16 at 1:57
• The general consensus is that cumbersome/strict input and output formats should be avoided. Splitting and joining words just makes the code longer and it doesn't really add anything to the core challenge. – Dennis Jul 19 '16 at 5:55
• Is not wrong the output with Pac-Man? can you clarify? Thanks – Hastur Jul 19 '16 at 12:58

# Jelly, 25 22 bytes

Ff”-ȯ⁸“JLKqḤṢ&F⁻ı»ṣ⁶¤ḟ


This is a monadic function. I/O is in form of lists. Try it online!

### How it works

Ff”-ȯ⁸“JLKqḤṢ&F⁻ı»ṣ⁶¤ḟ  Monadic link. Argument: A (list of strings)

F                       Flatten A.
f”-                    Filter it with the string "-" to detect "Pac-Man".
ȯ⁸                  Flat logical OR with A. This yields A if there is no '-'
in the input, the string "-" otherwise.
¤   Combine the three links to the left into a niladic chain.
“JLKqḤṢ&F⁻ı»        Yield "Blinky Inky Pinky Clyde", using Jelly's built-in
English dictionary.
ṣ⁶      Split at spaces to yield
["Blinky", "Inky", "Pinky", "Clyde"].
ḟ  Filter-false; removing all elements from that list that
appear in A or "-". This is a noop if A contains "Pac-Man".

• Which dictionary did you use that has "Pinky" etc. in it? XD – Conor O'Brien Jul 19 '16 at 19:40
• The default one that came with my OS. Pinky means little finger iirc, so it should be present in most dictionaries. I had to construct Blinky as B + linky though. Not sure what a linky is... – Dennis Jul 19 '16 at 19:43

## Retina, 45 bytes

A-
$,;BliNClyde,INPiN N nky, D\w+, .*;|,$



The trailing linefeed is significant. Input and output are comma separated.

Try it online! (The first line enables a linefeed-separated test suite.)

### Explanation

I did not expect to be able to show off Retina's latest addition (deduplication stages) so soon, but it's really helpful for this challenge. :)

Stage 1: Anti-Grep

A-


Anti-grep stages discard all lines that match the given regex. The regex is just - and the input is always a single line, so this discards all ghosts if the input contains Pac-Man.

Stage 2: Substitution

$,;BliNClyde,INPiN  This simply appends the fixed string ,;BliNClyde,INPiN. This will be the list of ghosts in the output after some clean-up. Stage 3: Substitution N nky,  Note that we've written the three *nky ghosts with an N in the previous stage (and omitted the comma after them), and we now expand this shorthand, which saves a couple of bytes. There is now a comma after every single ghost, and we've got the input ghosts and list of all ghosts separated by a semicolon. Stage 3: Deduplication D\w+,  This is the new part. Deduplication stages find all instances of the given regex and discard all matched substrings which are equal to an earlier matched substring. The regex simply matches all the ghosts, both in the input and in the list of potential outputs. If the input contains a ghost, then the same ghost will be matched again in the second list and is discarded. Otherwise, the ghost is matched for the first time in the second list and kept. So after this, the list after the semicolon is our desired output. All that's left is a bit of clean-up: Stage 5: Substitution .*;|,$



We simply match everything up to the semicolon as well as the comma at the end of the string and remove them.

• What about the Pac-Man case? – Value Ink Jul 19 '16 at 8:39
• @KevinLau-notKenny See the explanation of the first stage. – Martin Ender Jul 19 '16 at 8:40

## Python 3, 75 bytes

lambda s:[x for x in['Blinky','Inky','Pinky','Clyde']if(x in s)<1or'-'in s]


Input is a comma-separated string, and the output will be a list.

• The if(x in s)<1 part is clever! +1 – Daniel Jul 19 '16 at 17:14

# JavaScript ES6, 85 78 bytes

As an anonymous function

a=>["Blinky","Inky","Pinky","Clyde"].filter(c=>!a.includes(c)|a.some(v=>v[6]))


Today I learned about this filter function. Fun!

15 bytes saved thanks to Neil.

Usage:

(a=>["Blinky","Inky","Pinky","Clyde"].filter(c=>!a.includes(c)||a.includes("Pac-Man")))(["Pac-Man"])

• Rather than special-casing Pac-Man outside the filter, I think you can add it as a.includes("Pac-Main")||!a.includes(c) in the filter, at which point you only have one use of g and can therefore inline it and turn your block into an expression thus avoiding the return statement. – Neil Jul 19 '16 at 9:24
• @Neil Great idea. I was able to cut out the return and the {} and saved a ton of bytes, thanks! – charredgrass Jul 19 '16 at 9:34
• You can also save one byte by replacing your calls to a.includes with a[z="includes"] (first) and a[z] (second). Also, I think you can save another byte by using bitwise OR (|) on your boolean results instead of logical OR (||). – apsillers Jul 19 '16 at 16:53
• Actually, since Pac-Man is the longest possible input (and invalid inputs are impossible), we can test for the existence of a seventh character to test for Pac-Man: c=>!a.includes(c)||a.some(v=>v[6]). Using that with the bitwise OR brings the score down to 78. – apsillers Jul 20 '16 at 17:06
• @apsillers Ooh, that's a great, never would have thought to check length. I changed to the bitwise or and added that, thanks! – charredgrass Jul 21 '16 at 3:22

# Ruby, 55 49 bytes

Try it online!

-6 bytes from @MartinEnder

->a{%w"Blinky Inky Pinky Clyde"-(a*''=~/-/?[]:a)}


Ruby arrays can undergo set subtraction, making it very easy to remove the appropriate ghosts.

• How does this deal with Pac-Man? – Neil Jul 19 '16 at 9:25
• @Neil it joins the array together using a*'' and regex-compares it to the - present in the name Pac-Man. If it's present, it subtracts nothing from the list of ghosts, and if it isn't, it subtracts the input list (so each element in the input list is removed from the list of ghosts) – Value Ink Jul 19 '16 at 9:39

## Perl, 51 bytes

50 bytes code + 1 for -n

for$@(Blinky,Inky,Pinky,Clyde){print$@if/-/|!/$@/}g}  ### Usage perl -ne 'for$@(Blinky,Inky,Pinky,Clyde){print$@if/-/|!/$@/}' <<< 'Pac-Man, Clyde'


I can amend the output if necessary, adding a space after each ghost, for + 3 bytes replacing print$@ with print"$@ ".

-6 bytes thanks to @MartinEnder!

## Perl, 53 bytes

51 bytes code + 2 for -na

An alternative solution, using the smartmatch operator:

perl -nae 'print grep/-/~~@F|!($_~~@F),Blinky,Inky,Pinky,Clyde' <<< 'Clyde Pinky Inky Pac-Man' BlinkyInkyPinkyClyde'  # Pyth - 45 38 35 Bytes =GwI!:G"a")j-["inky""pinky""blinky""clyde")cG  I!:=Gw"a")j-c:" p bl clyde"d"inky "dcG  j-c:" p bl clyde"d"inky "d?:z\aZYcz  -1 more byte thanks to Leaky Nun! Input must be space delimited, all lowercase; outputs missing ghosts on separate lines unless pac-man is in the input. • You forgot "Pac-Man" – Jacques Marais Jul 19 '16 at 14:57 • @JacquesMarais No, it works. The :z\a detects if there's an "a" in the input, and there will be an "a" in the input iff pac-man is in the input – KoreanwGlasses Jul 19 '16 at 15:44 • I clicked the Pyth link and it didn't work when I entered "Pac-Man". When "Pac-Man" is entered, it should show all names, not none of them. – Jacques Marais Jul 19 '16 at 15:45 • @JacquesMarais My mistake. Fixed. – KoreanwGlasses Jul 19 '16 at 15:51 • }\az also tests if z contains the letter a. 1 byte shorter. – Jakube Jul 26 '16 at 12:29 # C, 171 bytes Pass a NULL-terminated array of strings to f(), and it will print out the missing names. *a[]={"Blinky","Inky","Pinky","Clyde",0},**s,**r,n;f(int**p){for(r=p;*p;)r=strcmp(*p++,"Pac-Man")?r:a+4;for(s=a;*s;++s){for(p=r,n=1;n&&*p;)n=strcmp(*s,*p++);n&&puts(*s);}}  Try it on ideone. ## PowerShell v4+, 107 bytes param($n)((($n+($x='Pinky','Inky','Blinky','Clyde')|group|?{$_.count-eq1}).Name),$x)['-'-in[char[]]-join$n]  A little clunky compared to others, as PowerShell lacks a ternary operator or any sort of map-style operator. As a result, we build our own. Takes input $n as an explicit array of strings (e.g., .\which-ghosts-are-missing.ps1 @('Clyde','Blinky'). The rest of the program is one pseudo-ternary that's composed of an array that we index into via some logic [...]. The logic is simply whether the - character is anywhere in the input array -joined together into a single string and then re-cast as a char array, in order to use the -in operator. Thus, if Pac-Man is in the input array, this will be $TRUE and the second element of the pseudo-ternary array will be chosen, else the first will be chosen. If it's the case that Pac-Man is not in the array, the first portion of the pseudo-ternary array is output. That is a combination of the input array $n concatenated with an array of all the ghosts (saved into $x). We pipe that new array into Group-Object which will group like items together, then select using Where-Object (aliased via |?{...} only the items where their .count is -equal to 1. That's all encapsulated in a parens, and we select the .Name property. This is where the v4 requirement comes in, as under v4 you can reference a hashtable label like this rather than using something like |Select Name, which saves several bytes. Otherwise, since Pac-Man is in the input array, we need to output all the ghosts. Thankfully we already saved those into $x, so that's the choice in this case. Either way, the pipeline now contains a string array of ghosts, and output is implicit.

### Examples

PS C:\Tools\Scripts\golfing> .\which-ghosts-are-missing.ps1 @('Clyde')
Pinky
Inky

PS C:\Tools\Scripts\golfing> .\which-ghosts-are-missing.ps1 @('Pac-Man','Clyde')
Pinky
Inky
Clyde

PS C:\Tools\Scripts\golfing> .\which-ghosts-are-missing.ps1 @()
Pinky
Inky
Clyde

PS C:\Tools\Scripts\golfing> .\which-ghosts-are-missing.ps1 @('Clyde','Blinky')
Pinky
Inky


# Python 2, 6661 96 bytes

g={"Blinky","Inky","Pinky","Clyde"};i=set(input());print",".join(g-i if not"Pac-Man"in i else g)


Input must be a list, output will be a string of names separated by a ,.

61 bytes version that doesn't handle Pac-Man:

print",".join({"Blinky","Inky","Pinky","Clyde"}-set(input()))

• Pac-Man is not handled in this entry. – Destructible Lemon Jul 19 '16 at 3:21
• You don't need set[...]. Just use a {...} set literal. – Dennis Jul 19 '16 at 8:23
• I really didn't notice the Pac-Man thing even after reading the challenge 3 times... I'll fix my code. – acrolith Jul 19 '16 at 14:59

# Haskell, 91 bytes

import Data.List
p l=(if elem"Pac-Man"l then id else(\\l))["Blinky","Inky","Pinky","Clyde"]


Input is a list of strings. It decides whether to use the list as-is or do a list-difference based on the presence of "Pac-Man".

For extra fun, here is no Pac-Man:

import Data.List


Will be improving this answer soon, did it super late at night.

## Python 3, 77 bytes

lambda i:[g for g in"Blinky Inky Pinky Clyde".split()if g not in i or"-"in i]


Here is another answer at 89 bytes that I was playing with but didn't work out :(

lambda i:[g for g in[s+"nky"for s in"Bli I Pi".split()]+["Clyde"]if g not in i or"-"in i]


And here's the original at 85 bytes:

lambda i,n="Blinky Inky Pinky Clyde":([g for g in n.split()if g not in i],n)["-"in i]


These all take a single string of the names separated by spaces/commas.

## 05AB1E, 47 44 bytes

•1g!Z~÷kÅ]°%Ï0›K/•35B0¡™svy'-åi,q}}v¹ykÌiy)˜


Explaination

•1g!Z~÷kÅ]°%Ï0›K/•35B0¡™                      # push list of the 4 ghosts
svy'-åi,q}}           # if Pac-Man is in input, quit and output list of all 4 ghosts
v¹ykÌiy)˜   # otherwise, generate the list of ghosts missing from input


Try it online

# Python 2, 151 bytes

As there are already Python answers using sets and strings I decided to restrict myself to work with lists, which turned out to be pretty long and uncompetitive. However, as the approach taken is different as the common one used, here it is:

o=['Blinky','Clyde','Inky','Pinky']
p=lambda x:[l for l in reduce(lambda z,x:z+[y+[x]for y in z],o,[[]])if sorted(l+x)==o][0]if'Pac-Man'not in x else o


where the expected input is a list of strings.

The approach is to bruteforce all possible combinations (without taking order into account) of 0,1,2,3 and 4 elements. This is done by

reduce(lambda z,x:z+[y+[x]for y in z],o,[[]])


which returns

[[], ['Clyde'], ['Pinky'], ['Clyde', 'Pinky'], ['Inky'], ['Clyde', 'Inky'],
['Pinky', 'Inky'], ['Clyde', 'Pinky', 'Inky'], ['Blinky'], ['Clyde', 'Blinky'],
['Clyde', 'Pinky', 'Inky', 'Blinky']]


and find the one which, in addition to the input list results in the complete list of ghosts.

Then it is checked if the string 'Pac-Man' is part of the input and, in case it is, the whole list of ghosts is returned. If not, only the ones which are not part of the input are returned.

Notice that the list containing all ghost names (o) is sorted alphabetically and the same goes for the list built as (sorted(l+x)). This is due to the fact that in Python, ['a','b']==['b','a'] is evaluated as False whereas ['a','b']==['a','b'] is evaluated as True.

3 bytes can be saved if it is permitted to return the answer as a list of lists ( by removing the [0] at the end of the first list comprehension). But as I'm not sure it is a valid output I am counting them.

# Object Pascal, 204 200 bytes

Two loops, using a binary to find which ghosts+pacman are present. Takes the arguments from the commandline. Thanks to @manatwork for saving some more bytes!

var a:array[1..4]of string=('Blinky','Inky','Pinky','Clyde');i,s:Byte;begin for i:=1to ParamCount do s:=1<<Pos(ParamStr(i)[4],'nykd-')or s;for i:=1to 4do if(1<<i and s=0)or(s>31)then WriteLn(a[i])end.


Ungolfed:

var
a: array[1..4] of string = ('Blinky', 'Inky', 'Pinky', 'Clyde');
i, s: byte;
begin
for i:=1 to ParamCount do
s := 1 << pos(ParamStr(i)[4], 'nykd-') or s; // fill bits by shifting, check for unique 4th char of names, '-' in 'pac-man', could also use the 3rd char
for i:=1 to 4 do
if (1 << i and s=0) or (s>31) then    // check if bits are on
writeln(a[i]);
end.


# Old version using a set, 227 209 bytes

Two loops, using a set to find which ghosts+pacman are present. Takes the arguments from the commandline.

var a:array[1..4]of string=('Blinky','Inky','Pinky','Clyde');i:byte;s:set of 1..5;begin for i:=1to ParamCount do s:=s+[pos(ParamStr(i)[4],'nykd-')];for i:=1to 4do if not(i in s)or(5in s)then writeln(a[i]);end.


Ungolfed:

var
a: array[1..4] of string = ('Blinky', 'Inky', 'Pinky', 'Clyde');
i: byte;
s: set of 1..5;
begin
for i:=1 to ParamCount do
s := s + [pos(ParamStr(i)[4], 'nykd-')]; // fill set with indxs
for i:=1 to 4 do
if not(i in s) or (5 in s) then    // check indx not in set or pac-man is
writeln(a[i]);
end.

• Nice. Some ways to shortening it: integerbyte; remove declaration of g and use its value directly, ParamCount5 (as I understand the task, there will be no duplicated or invalid input items anyway). At least in FreePascal numeric literals may touch keywords, like i:=1to 5do or 5in s. See whether your supports it too. – manatwork Jul 20 '16 at 13:45
• I think using bits instead of set would be beneficial: pastebin.com/r2nB5wY3 – manatwork Jul 20 '16 at 14:16
• @manatwork Wow, everytime I learn something new.. I am using your suggestions except for ParamCount, because the behavior is undefined for numbers bigger then actual input params (at least there is nothing about it in the docs), even though it works. – hdrz Jul 20 '16 at 15:40

# PHP program, 84 bytes

<?print_r(array_diff([Blinky,Inky,Pinky,Clyde],in_array('Pac-Man',$argv)?[]:$argv));

• takes arguments from command line, prints result as an array.
• filename must not be any of the ghosts or 'Pac-Man'!
• short breakdown: remove (if 'Pac-Man' is in arguments: nothing, else all arguments) from all ghosts; print result recursively

examples:

>php -d error_reporting=0 ghosts.php Clyde
Array
(
[1] => Inky
[2] => Pinky
)
>php -d error_reporting=0 ghosts.php Clyde Blinky
Array
(
[0] => Inky
[1] => Pinky
)
>php -d error_reporting=0 ghosts.php Pac-Man Clyde
Array
(
[1] => Inky
[2] => Pinky
[3] => Clyde
)


PHP function, 90 bytes

function p($a){return array_diff([Blinky,Inky,Pinky,Clyde],in_array('Pac-Man',$a)?[]:$a);}  takes and returns an array, use empty array for empty input, no other falsy value! further thoughts • replace in_array(...) with strstr(join($argv),'-') to detect - instead of Pac-Man (-2)
• use ereg('-',join($argv)) instead (another -2) • program could lose another 6 bytes in PHP<5.4 with register_globals on • to make the program print a comma-separated list: replace <?print_r( with <?=join(',', (+2). You may want to add ;echo"" to the call for a line break # jq, 69 characters ("Blinky Inky Pinky Clyde"/" ")as$a|if inside($a)then$a-. else$a end  Input is JSON, output is JSON, conditional syntax is pain. Sample run: bash-4.3$ jq '("Blinky Inky Pinky Clyde"/" ")as $a|if inside($a)then$a-. else$a end' <<< '["Clyde"]'
[
"Inky",
"Pinky"
]

bash-4.3$jq '("Blinky Inky Pinky Clyde"/" ")as$a|if inside($a)then$a-. else\$a end' <<< '["Pac-Man","Clyde"]'
[
"Inky",
"Pinky",
"Clyde"
]


On-line test:

# TSQL(sqlserver 2016), 114 bytes

Golfed:

DECLARE @ VARCHAR(99) = 'Blinky,Inky,Pinky,Clyde'

SELECT*FROM STRING_SPLIT('Blinky,Inky,Pinky,Clyde',',')EXCEPT SELECT*FROM STRING_SPLIT(@,','WHERE @ NOT LIKE'%-%'


Ungolfed:

DECLARE @ VARCHAR(99) = 'Blinky,Inky,Pinky,Clyde'

SELECT * FROM STRING_SPLIT('Blinky,Inky,Pinky,Clyde',',')
EXCEPT
SELECT * FROM STRING_SPLIT(@,',')
WHERE @ NOT LIKE'%-%'


Fiddle

## Lotus Notes @Formula language, 858475 74 characters

-1 character by reversing the @If assignment

-9 Changed @Contains(i;"-") to @Like(i;"%-%") and removed @Trim (not needed if displayed using space as seperator)

-1 by removing the newline

Create a form with two fields: i (Text,Editable,Multi-value) and o (Text,Computed,Multi-value). Enter the following formula in o:

l:="Inky":"Pinky":"Blinky":"Clyde";@If(@Like(i;"%-%");l;@Replace(l;i;""))


From Notes client, create a new document using the form, enter the name(s) in the i field and press F9 to refresh the document. Answer displayed in field o.

This takes advantage of the fact that @Like and @Replace can can both be used either on a string or on a list of strings.

C# 135 bytes126 bytes

string[] g{"Blinky","Inky","Pinky","Clyde"};Console.WriteLine(String.Join(",",i.Contains("Pac-Man")?g:g.Except(i).ToArray()));


(where i is a string array containing the input)

After looking at the other examples, I see that C# is rather a verbose language :)

• You can get 126 bytes by removing the spaces and the newline. – acrolith Jul 21 '16 at 1:31

## Pyke, 45393837 32 bytes

.d𖭺𐎪膎㧫l4dc].^D\-R{!*


Try it here!

.d𖭺𐎪膎㧫l4dc - dictionary_lookup('blinky inky pinky clyde').title().split()
].^ - xor(^, input)
D\-R{!* - ^*("-" not in input)


## Batch, 141 bytes

@set g= Blinky Inky Pinky Clyde
@for %%a in (%*)do @if %%a==Pac-Man goto l
@for %%a in (%*)do call set g=%%g: %%a=%%
@l
@echo(%g:~1,-1%


(Subtract 6 bytes for :~1,-1 if leading and trailing whitespace is acceptable.) Requires Pac-Man in title case but the ghosts are case insensitive.

# Japt, 38 bytes (Non-competing)

Takes input as an array of strings, outputs an array of strings

B¦nky Inky Pky CÒè¸kUøPac-M ?N:U


Try it online