[Question]
  [
A little known fact about vampires is that they must drink the blood of victim that has a compatible donor blood type. The compatibility matrix for vampires is the same as the regular [red blood cell donor/recipient matrix](http://en.wikipedia.org/wiki/Blood_type#Red_blood_cell_compatibility). This can be summarized by the following [American Red Cross table](http://chapters.redcross.org/br/northernohio/INFO/bloodtype.html) 
```
Type    You Can Give Blood To    You Can Receive Blood From
A+      A+, AB+                  A+, A-, O+, O-
O+      O+, A+, B+,AB+           O+, O-
B+      B+, AB+                  B+, B-, O+, O-
AB+     AB+                      everyone
A-      A+, A-, AB+, AB-         A-, O-
O-      everyone                 O-
B-      B+, B-, AB+, AB-         B-  O-
AB-     AB+, AB-                 AB-, A-, B-, O-
```
### Challenge
Write a function or program that takes a blood type as input and outputs two lists:
1. the unordered list of types that may receive donation of the input type
2. the unordered list of types that may give donation to the input type
If you write a function, then please also provide a test program to call that function with a few examples, so I can easily test it. In this case, the test program would not count towards your score.
### Input
Input must be a string representing exactly one of the 8 possible red blood cell types `O−` `O+` `A−` `A+` `B−` `B+` `AB−` `AB+`. Input may be given via the normal methods (STDIN, command-line args, function args, etc).
If any other input is given then the program/function must return empty output or throw an error. Normally strict input-checking is not great in [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'") questions, but I felt given the life-death implications of getting blood types wrong that I should add this rule.
### Output
Output will be two human-readable lists of blood types in whatever format is suitable for your language. In the special cases where one of the output list contains all 8 types, this list may optionally be replaced with a single item list containing `everyone`.
Normal output will go to one of the normal places (STDOUT, function return, etc).
### Other rules
* [Standard loopholes](http://meta.codegolf.stackexchange.com/questions/1061/standard-loopholes-which-are-no-longer-funny) are banned
* You may use whatever pre-existing 3rd party libraries you need, so long as they are not designed explicitly for this purpose.
### Examples
* For input `AB-`, the two output lists would be: `{AB+, AB-}, {AB-, A-, B-, O-}`
* For input `AB+`, the two output lists would be: `{AB+}, {O−, O+, A−, A+, B−, B+, AB−, AB+}` or `{AB+}, {everyone}`
---
Personal note: Please consider donating blood if you are able to. Without the transfusion I received a few years ago, I might not be here today, so I feel very grateful towards those who are able to donate!
  
[Answer]
# [Clip](http://esolangs.org/wiki/Clip), 69
```
*cTx\{fFx`Tf[tFtx}T`[Fx[y!VVx"O-"Vy"O-"}[TC"A+ B+ AB+ O+ A- B- AB- O-
```
Input: `AB-`
Output: `{{"AB+", "AB-"}, {"A-", "B-", "AB-", "O-"}}`
## Explanation
A blood type `x` can give to `y` if all of `x`'s antigens are included in `y`. The program defines the function `F` as whether `x` can give to `y`, and `T` as the list of types.
```
*cTx                 .- If T contains x (the input)         -.
    \                .- Print                               -.
     {             ` .- a list of                           -.
      fFx`T          .- filter each t in T with F(x,t)      -.
           f[tFtx}T  .- filter each t in T with F(t,x)      -.
[Fx[y              } .- F is a function of x and y          -.
     !V              .- all letters of ... are included in ...   -.
       Vx"O-"        .- x, with O and - removed             -.
             Vy"O-"  .- y, with O and - removed             -. 
[TC"A+ B+ AB+ O+ A- B- AB- O-   .- T is the list of types -.
```
[Answer]
# Java 8, 373
```
import java.util.*;void f(String s){List<String>l=new ArrayList(Arrays.asList("A+,B+,AB+,O+,A-,B-,AB-,O-".split(","))),m=new ArrayList(l);int i=l.contains(s)?1:0/0;l.removeIf(x->g(s,x)<1);m.removeIf(x->g(x,s)<1);System.out.print(l+","+m);}int g(String s,String t){for(char c:s.replaceAll("O|-","").toCharArray())if(!t.replaceAll("O|-","").contains(""+c))return 0;return 1;}
```
## Explanation
```
void f(String s) {
    List<String> l = new ArrayList(Arrays.asList("A+,B+,AB+,O+,A-,B-,AB-,O-".split(","))),
                 m = new ArrayList(l);
    int i = l.contains(s) ? 1 : 0 / 0;
    l.removeIf(x -> g(s, x) < 1);
    m.removeIf(x -> g(x, s) < 1);
    System.out.print(l + "," + m);
}
int g(String s, String t) {
    for (char c : s.replaceAll("O|-", "").toCharArray()) {
        if (!t.replaceAll("O|-", "").contains("" + c)) {
            return 0;
        }
    }
    return 1;
}
```
Run it here: <http://repl.it/e98/1>
Note that `static` had to be added to each method to call them from the main method.
[Answer]
# Pyth, 61 59 50
```
L-{b"O-"M!-yGyHJmsd*c"A O B AB"d"+-"I}zJfgzTJfgYzJ
```
[Run it here.](https://pyth.herokuapp.com/?code=L-%7Bb%22O-%22M!-yGyHJmsd*c%22A+O+B+AB%22d%22%2B-%22I%7DzJfgzTJfgYzJ&input=B%2B&debug=0)
Explanation:
```
L-{b"O-"                         Create function y(b) that makes a set from b's 
                                 characters minus O and -.
M!-yGyH                          Create function g(G,H) that checks if y(G) is 
                                 a subset of y(H).
J                                Assign to J...
 msd                             The concatenation of every element in...
    *c"A O B AB"d"+-"            The Cartesian product of A O B AB and + -.
I}zJ                             If input in J then...
    fgzTJ                        Print all elements e in J if g(input, e).
    fgYzJ                        Print all elements e in J if g(e, input).
```
[Answer]
# CJam, 64 bytes
```
"AB"_a+'O+"+-"m*:s:TT{}+Tqa#=a+T4=f&_)f{\-!}\)f-:!]{T]z::*La-p}/
```
The `m*:s` part comes from [Martin's CJam answer](https://codegolf.stackexchange.com/a/47994/25180). (I didn't read the other parts yet.)
There will be still some serious problems because they'll be never sure about the order of the two lists. And `Block ArrayList &` might be implemented in later versions of CJam.
### Explanation
```
"AB"_a+'O+         " Generate ['A 'B \"AB\" 'O]. ";
"+-"m*:s:T         " Generate the list of blood types and store in T. ";
T{}+
    Tqa#           " Find the input in T. ";
=                  " Find the blood type by the index.
                     If not found, return a block to cause an error. ";
a+                 " Append the verified input to T. ";
T4=                " AB+. ";
f&                 " Intersect each blood type with AB+. ";
_)f{\-!}           " Check emptiness of input - each item. ";
\)f-:!             " Check emptiness of each item - input. ";
]{                 " For both lists: ";
    T]z::*         " Replace items in T where there is a 0 with empty strings. ";
    La-            " Remove empty strings. ";
    p              " Print. ";
}/
```
[Answer]
# Prolog, ~~119~~ 110 bytes
```
u(A,B):-member(A:B,[a:ab,b:ab,o:a,o:b,o:ab]);A=B,member(A,[a,ab,b,o]).
g(X,Y):-(X= -A;X=A),(Y= -B;Y=B),u(A,B).
```
*Remarks*: 
1. Blood types have the following properties: everytime you have a `-` (e.g. `a-`), you can give to the same people as the one who have positive equivalent of your group (e.g. `a`), as well as their negative counterpart (e.g. `a` gives to `ab`, so `a-` gives to `ab` and `ab-`). Based on this property, and *abusing the notations a little bit* to make use of the minus and plus operators, we can factor a lot of cases. *Please tell me if you find it acceptable*. If you prefer having the original (postfix) syntax, here is a non-golfed version:
```
blood(X):-member(R,['a+','o+','b+','ab+','a-','b-','ab-']).
give('o-',R):-blood(R).
give(X,X):-blood(X).
give('a+','ab+').
give('b+','ab+').
give('o+','a+').
give('o+','b+').
give('o+','ab+').
give('a-','a+').
give('a-','ab+').
give('a-','ab-').
give('b-','b+').
give('b-','ab+').
give('b-','ab-').
give('ab-','ab+').
```
2. This is Prolog, so the interactive environment allows to query everything as requested (see example below). Granted, we don't have lists strictly as an output, but this is equivalent. 
We also naturally handle error cases as a consequence.
## Example
```
donors(X,L) :- findall(Y,g(Y,X),L).
receivers(X,L) :- findall(Y,g(X,Y),L).
test :-
    member(X,[a,o,b,ab,-a,-o,-b,-ab]),
    donors(X,D),
    receivers(X,R),
    writeln(X:give_to(R):receive_from(D)),
    fail.
test.
```
Then, we execute `test`:
```
a : give_to([ab, a]) : receive_from([o, a])
o : give_to([a, b, ab, o]) : receive_from([o])
b : give_to([ab, b]) : receive_from([o, b])
ab : give_to([ab]) : receive_from([a, b, o, ab])
-(a) : give_to([+(ab), +(a), -(ab), -(a)]) : receive_from([-(o), -(a)])
-(o) : give_to([+(a), +(b), +(ab), +(o), -(a), -(b), -(ab), -(o)]) : receive_from([-(o)])
-(b) : give_to([+(ab), +(b), -(ab), -(b)]) : receive_from([-(o), -(b)])
-(ab) : give_to([+(ab), -(ab)]) : receive_from([-(a), -(b), -(o), -(ab)])
```
... which, without proper formatting, is the same matrix as the one given in the question.
## Details
The predicate `g/2` is the *give* relationship: `g(X,Y)` means *people of blood type X may give blood to people of blood type Y*.
Find receivers for group `a`:
```
[eclipse]: g(a,R).    
R = ab
Yes (0.00s cpu, solution 1, maybe more) ? ;
R = a
Yes (0.00s cpu, solution 2)
```
Find receivers for `orange_juice` (should fail):
```
[eclipse] g(orange_juice,L).
No (0.00s cpu)
```
Find donors for `O-`:
```
[eclipse] g(X,-o).
X = -(o)
Yes (0.00s cpu)
```
Who can give what? :
```
[eclipse] g(X,Y).
.... 27 answers ....
```
We do not go into an infinite recursion loop (it was the case in preliminary tests).
[Answer]
# Javascript, 167
```
p=function(t){o="";if((x=(l="O- O+ B- B+ A- A+ AB- AB+".split(" ")).indexOf(t))<0)return;n=2;while(n--){y=8;while(y--)if([y,x][n]-(y&x)==0)o+=" "+l[y];o+=";"}return o}
```
ungolfed:
```
function p(btype){
    output = "";
    btypeList = "O- O+ B- B+ A- A+ AB- AB+".split(" ");
    btypeInt = btypeList.indexOf(btype);
    // thus we have the scheme
    // btypeInt = 0b(has A antigen)(has B antigen)(has rhesus antigen)
    if(btypeInt < 0) // i.e. broken blood type string
        return;
    for(receiving = 7; receiving >= 0; receiving--)
        if(giving - (receiving & btypeInt) == 0)
            // i.e. the receiving person has at least all the antigens of our donor
            output += " " + btypeList[receiving];
    output += ";";
    for(giving = 7; giving >= 0; giving--)
        if(btypeInt - (receiving & btypeInt) == 0)
            // i.e. the giving person has no antigens that our patient doesn't have
            output += " " + btypeList[receiving];
    return output;
}
```
testing function:
```
function tester(){
    btypeList = "O- O+ B- B+ A- A+ AB- AB+".split(" ");
    for(i=0; i<8; i++){
        console.log("Patient is " + btypeList[i])
        console.log(p(btypeList[i]))
    }
    console.log("Erroneous blood type => returns void:")
    console.log(p("asdf"))
}
```
Encoding the blood type in binary has the advantage that another antigen (e.g. the [Kell antigen](http://en.wikipedia.org/wiki/Kell_antigen_system)) is easily incorporated into the code by just adding another bit.
---
Donate blood in Zurich, CH: [Blutspende Zürich](http://www.blutspendezuerich.ch/)
[Answer]
# CJam, 94 bytes
Wow, this is long... while I think I could probably golf this approach below 80, I think I might have done better by first computing the matrix and then simply picking out the correct row and column. Anyway, here it is:
```
'O'A'B"AB"]:A"+-"m*:sq_a@&!!*_)'++_&\"AB"&A{1$\-!},\;\m*::+p)'-+_&\"AB"&A1>{1$-!},'O+\;\m*::+p
```
[Test it here.](http://cjam.aditsu.net/#code='O'A'B%22AB%22%5D%3AA%22%2B-%22m*%3Asq_a%40%26!!*_)'%2B%2B_%26%5C%22AB%22%26A%7B1%24%5C-!%7D%2C%5C%3B%5Cm*%3A%3A%2Bp)'-%2B_%26%5C%22AB%22%26A1%3E%7B1%24-!%7D%2C'O%2B%5C%3B%5Cm*%3A%3A%2Bp&input=AB-)
I'll add an explanation when I'm done golfing.
[Answer]
# Groovy, 115
```
x={i=(l=('O-O+B-B+A-A+AB-AB+'=~/\w+./)[0..7]).indexOf(it);f=(0..7).&findAll;i<0?[]:[l[f{!(~it&i)}],l[f{!(it&~i)}]]}
```
The idea is to encode A, B and rhesus factor as one bit each. We can then inverse the bits to get all the antigens on the receiving side and use it to check that there is no corresponding antibodies on the giving side. This is more or less the same as the existing JavaScript solution.
Sample execution
```
groovy> println x("AB+") 
groovy> println x("AB-") 
groovy> println x("A+") 
groovy> println x("A-") 
groovy> println x("B+") 
groovy> println x("B-") 
groovy> println x("O+") 
groovy> println x("O-") 
groovy> println x("X") 
[[AB+], [O-, O+, B-, B+, A-, A+, AB-, AB+]]
[[AB-, AB+], [O-, B-, A-, AB-]]
[[A+, AB+], [O-, O+, A-, A+]]
[[A-, A+, AB-, AB+], [O-, A-]]
[[B+, AB+], [O-, O+, B-, B+]]
[[B-, B+, AB-, AB+], [O-, B-]]
[[O+, B+, A+, AB+], [O-, O+]]
[[O-, O+, B-, B+, A-, A+, AB-, AB+], [O-]]
[]
```
[Answer]
# Python, 187 bytes
Different approach:
```
def D(a,b):X=lambda c:c in a and 1-(c in b);return(X('A')+X('B')+X('+'))<1
T="O- O+ A- A+ B- B+ AB- AB+".split()
X=lambda t:(0,([u for u in T if D(t,u)],[u for u in T if D(u,t)]))[t in T]
```
Can probably be golfed a bit more. 
**Test:**
```
for t in T + ["zz"]:
    print t, X(t)
```
**Output:**
```
O- (['O-', 'O+', 'A-', 'A+', 'B-', 'B+', 'AB-', 'AB+'], ['O-'])
O+ (['O+', 'A+', 'B+', 'AB+'], ['O-', 'O+'])
A- (['A-', 'A+', 'AB-', 'AB+'], ['O-', 'A-'])
A+ (['A+', 'AB+'], ['O-', 'O+', 'A-', 'A+'])
B- (['B-', 'B+', 'AB-', 'AB+'], ['O-', 'B-'])
B+ (['B+', 'AB+'], ['O-', 'O+', 'B-', 'B+'])
AB- (['AB-', 'AB+'], ['O-', 'A-', 'B-', 'AB-'])
AB+ (['AB+'], ['O-', 'O+', 'A-', 'A+', 'B-', 'B+', 'AB-', 'AB+'])
zz 0
```
[Answer]
# Ruby, 237 232 223 221 210 207 bytes
Fixed some extraneous backslashes in the regular expressions and made it so it just prints out the lists as opposed to storing them to variables and then printing them. Sometimes you miss the obvious things when trying to golf!
```
o=->b{Regexp.new b.gsub(?O,?.).gsub(?+,'.?\\\+').gsub'-','.?(\W)'};b=gets.chop;t=["A+","B+","AB+","O+","A-","B-","AB-","O-"];exit if !t.include? b;p t.reject{|x|!x.match o.(b)};p t.reject{|x|!b.match o.(x)}
```
Ungolfed:
```
#!/usr/bin/ruby
b=gets.chomp;
types = ["A+","A-","B+","B-","AB+","AB-","O+","O-"];
exit if !types.include?(b);
regex1 = Regexp.new b.gsub("O",".").gsub('+','.?\\\+').gsub('-','.?(\\\+|\\\-)')
donate = types.reject {|x|!x.match(regex1)};
p donate;
receive = types.reject {|x| regex2 = Regexp.new x.gsub("O",".").gsub('+','.?\\\+').gsub('-','.?(\\\+|\\\-)'); !b.match(regex2)};
p receive;
```
Basically, I construct a custom regular expression for the blood type entered to check if you can donate to another blood type. I then iterate through the blood types and apply that same regex to them and check if they can donate to the one specified.
This can probably be golfed down even more. This is my first time attempting code golf, heh.
[Answer]
# Python 2, 168 bytes
This is the same method as Blackhole's answer. Exits with an error if the parameter is not found in the list of types.
```
def f(t):l='A+ O+ B+ AB+ A- O- B- AB-'.split();c=[9,15,12,8,153,255,204,136];i=l.index(t);print[s for s in l if c[i]&1<<l.index(s)],[s for s in l if c[l.index(s)]&1<<i]
```
**Less golfed:**
```
def f(t):
    l = 'A+ O+ B+ AB+ A- O- B- AB-'.split()
    c = [9, 15, 12, 8, 153, 255, 204, 136]
    i = l.index(t)
    x = [s for s in l if c[i] & 1 << l.index(s)]
    y = [s for s in l if c[l.index(s)] & 1 << i]
    print x, y
```
Run it here: <http://repl.it/eaB>
I also tried a couple other slight changes, but couldn't get it any shorter...
```
#172 bytes
def f(t):l='A+ O+ B+ AB+ A- O- B- AB-'.split();c=[9,15,12,8,153,255,204,136];a=lambda x:l.index(x);i=a(t);print[s for s in l if c[i]&1<<a(s)],[s for s in l if c[a(s)]&1<<i]
#171 bytes
def f(t):l='A+ O+ B+ AB+ A- O- B- AB-'.split();c=[9,15,12,8,153,255,204,136];a=lambda x:l.index(x);print[s for s in l if c[a(t)]&1<<a(s)],[s for s in l if c[a(s)]&1<<a(t)]
```
[Answer]
# PHP (287 bytes):
Yeah, this is pretty long, but it works as expected.
It may be possible to shorten a lot:
```
!preg_match('@^(AB?|B|O)[+-]$@',$t=$_GET[T])&&die("$t invalid");$S=array_flip($D=split(0,'O+0A+0B+0AB+0O-0A-0B-0AB-'));$L=[[1230,40],[13,1504],[23,2604],[3,$r=12345670],[$r,4],[1537,54],[2637,64],[37,7564]];for($j=0;$j<2;){foreach(str_split($L[$S[$t]][$j++])as$v)echo$D[$v].' ';echo'
';}
```
This is not easy to read and was't easy to write.
It works as intended, outputting the ones you can give to and the ones you can receive from on another line.
This requires a URL parameter `T=` with the type.
[Answer]
# CJam, 80 bytes
This is still too long. Probably I can shave off 4 to 5 bytes more.
```
U1023_XKC30D]2/La+"AB"a"OAB"1/+:Mr):P;a#=_P"+-":G&+!!{AfbMff=G1/Pf|]z{~m*:s}%}*`
```
For any invalid input, either prints an empty array, or throws an error.
[Try it online here](http://cjam.aditsu.net/#code=U1023_XKC30D%5D2%2FLa%2B%22AB%22a%22OAB%221%2F%2B%3AMr)%3AP%3Ba%23%3D_P%22%2B-%22%3AG%26%2B!!%7BAfbMff%3DG1%2FPf%7C%5Dz%7B~m*%3As%7D%25%7D*%60&input=A-%2B) or [run the whole test suite](http://cjam.aditsu.net/#code=8%7BU1023_XKC30D%5D2%2FLa%2B%22AB%22a%22OAB%221%2F%2B%3AMl)%3AP%3Ba%23%3D_P%22%2B-%22%3AG%26%2B!!%7BAfbMff%3DG1%2FPf%7C%5Dz%7B~m*%3As%7D%25%7D*p%7D*&input=A%2B%0AO%2B%0AB%2B%0AAB%2B%0AA-%0AO-%0AB-%0AAB-)
[Answer]
# APL, 66
```
(↓⊃∧/(↓t∘.∊v)(≥,[.5]≤)¨t∊⊃v⌷⍨v⍳⊂⍞)/¨⊂v←,'+-'∘.,⍨('O'∘,,⊂)2↑t←'AB+'
```
[Try it here.](http://tryapl.org/?a=%7B%28%u2193%u2283%u2227/%28%u2193t%u2218.%u220Av%29%28%u2265%2C%5B.5%5D%u2264%29%A8t%u220A%u2283v%u2337%u2368v%u2373%u2282%u2375%29/%A8%u2282v%u2190%2C%27+-%27%u2218.%2C%u2368%28%27O%27%u2218%2C%2C%u2282%292%u2191t%u2190%27AB+%27%7D%27A+%27&run)
[Answer]
# C, 224
```
#define d(x)for(i=0;i<8;i++)if((i x j)==j)printf("%s%s%s%c ",i&2?"A":"",i&4?"B":"",i&6?"":"0","-+"[i&1]);puts("");
main(i,j){char d[4],*c=&d;scanf("%s",c);j=(c[2]?c++,2:0)+(c[1]-'+'?0:1)+(*c>='A'?2:0)+(*c>'A'?2:0);d(&)d(|)}
```
De-golfed it shows:
```
/* j = 1*(has+) + 2*(hasA) + 4*(hasB) */
#define d(x) for(i=0;i<8;i++) \
                 if((i x j)==j) \
                      printf("%s%s%s%c ",i&2?"A":"",i&4?"B":"",i&6?"":"0","-+"[i&1]); \
             puts("");
main(i,j)
{
    char d[4], *c=&d;
    scanf("%s",c);
    j= (c[2]? (c++,2):0)            /* ABx */
            + (c[1]-'+'?0:1)
            + (c[0]>='A'?2:0)
            + (c[0]>'A'?2:0);
    // print possible receipients, and then donators
    d(&)
    d(|)
}
```
[Answer]
## PHP - ~~215~~ ~~212~~ 206 bytes
```
function($t){$c=[9,15,12,8,153,255,204,136];if(($a=array_search($t,$l=split(1,'A+1O+1B+1AB+1A-1O-1B-1AB-')))===!1)die;foreach($l as$k=>$v){if($c[$a]&1<<$k)$x[]=$v;if($c[$k]&1<<$a)$y[]=$v;}var_dump($x,$y);}
```
Here is the ungolfed version:
```
function ($type)
{
    $typesList = ['A+', 'O+', 'B+', 'AB+', 'A-', 'O-', 'B-', 'AB-'];
    $donationCompatibilityList = [
        0b00001001,
        0b00001111,
        0b00001100,
        0b00001000,
        0b10011001,
        0b11111111,
        0b11001100,
        0b10001000,
    ];
    $idType = array_search($type, $typesList);
    if ($idType === false) {
        die;
    }
    $canGiveToList = [];
    $canReceiveFromList = [];
    foreach ($typesList as $currentIdType => $currentType)
    {
        if ($donationCompatibilityList[$idType] & 1 << $currentIdType ) {
            $canGiveToList[] = $currentType;
        }
        if ($donationCompatibilityList[$currentIdType ] & 1 << $idType) {
            $canReceiveFromList[] = $currentType;
        }
    }
    var_dump($canGiveToList, $canReceiveFromList);
}
```
Thanks to [manatwork](https://codegolf.stackexchange.com/users/4198/manatwork) for saving 4 bytes.
[Answer]
# Perl, 107 ~~112~~
Finally encoding the type names in numbers gave the shorter code.
```
#!perl -p
$x=y/AB+/421/r%9;@a=grep{~$x&$_%9||push@b,$_;!($x&~($_%9))}map{("$_-",$_.1)}0,2,4,42;$_="@a
@b";y/421/AB+/
```
Older version
```
#!perl -p
$x=y/AB+/421/r%9;@a=grep!($x&~$_),0..7;@b=grep!(~$x&$_),0..7;$_="@a
@b";s/\d/(map{("$_+","$_-")}0,A,B,AB)[$&]/eg
```
[Answer]
# Pyth, 58
Partly the same as orlp's [solution](https://codegolf.stackexchange.com/a/48026/30164), but somewhat different and completely self-designed.
```
M&n+eGeH"+-"!f!}T+H\OPGJsm,+d\++d\-c"O A B AB"dfgzYJfgZzJJ
```
## Explanation
```
M                          create a function g(G,H) that returns
  n+eGeH"+-"                 G[-1] + H[-1] is not "+-"
 &                          and
            !f!}T+H\OPG      chars of G[:-1] not in H + "O" is falsy (empty)
J                          J =
 s                          merge
  m                          map
   ,+d\++d\-                  lambda d: (d + "+", d + "-")
            c"O A B AB"d      over ["O", "A", "B", "AB"]
fgzYJ                      print all J's items x where g(input, x)
fgZzJ                      print all J's items x where g(x, input)
```
[Answer]
# J, 120 bytes
```
   f=.3 :';"1(2 8$,(s-:"*<y,'' '')#8 2 8$#:213472854600871062656691437010712264449x)#s=.<;.2''A+ B+ AB+ O+ A- B- AB- O- '''
   f 'A+'
A+ AB+      
A+ O+ A- O- 
   f 'AB-'
AB+ AB-      
A- B- AB- O- 
```
The function fails on invalid inputs. The big decimal number is the encoding of the full compatibility matrix.
(Very long solution for multiple reasons.)
[Try it online here.](http://tryj.tk/)
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), 29 bytes
```
„ABD`'O)„+-âJÐIkVāY&èê,āY~èê,
```
[Try it online!](https://tio.run/##yy9OTMpM/f//UcM8RyeXBHV/TSBLW/fwIq/DEzyzw440RqodXnF4lQ6QUQdm/P/vpA0A "05AB1E – Try It Online")
]