I have written a solution to the blood-type matching problem, as described at https://projectlovelace.net/problems/blood-types/. The problem is to determine whether a given recipient (in this case, argv[1]
) will find a match for a blood transfusion in an array of available donors (argv + 2
).
- Input blood type:
B+
- Input list of available blood types:
A- B+ AB+ O+ B+ B-
- Output:
match
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
typedef struct {
enum { O, A, B, AB } abo;
enum { P, M } rh;
} Blood;
const int abo[4][4] = {
{ O, O, O, O }, // O
{ O, A, O, A }, // A // *
{ O, B, O, B }, // B // *
{ O, A, B, AB }, // AB
};
const int rh[2][2] = {
{ P, M }, // P
{ M, M }, // M // *
};
Blood
parse(char *s){
char rh0 = s[strlen(s)-1];
char *abo0 = strdup(s);
abo0[strlen(s)-1] = '\0';
Blood b = {
!strncmp(abo0, "O", 1) ? O
: !strncmp(abo0, "A", 1) ? A
: !strncmp(abo0, "B", 1) ? B
: !strncmp(abo0, "AB", 2) ? AB
: -1,
rh0 == '+' ? P
: rh0 == '-' ? M
: -1,
};
return b;
}
int
main(int argc, char *argv[]) {
if(argc < 3)
err(1, "no arguments given\n");
int n = argc - 2;
char *a0 = argv[1];
char **as = argv + 2;
Blood b0 = parse(a0);
Blood *bs = malloc(sizeof(Blood) * n);
for(int i = 0; i < n; i++)
bs[i] = parse(as[i]);
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 2; j++) {
for(int k = 0; k < n; k++) {
if(abo[b0.abo][i] == bs[k].abo && rh[b0.rh][j] == bs[k].rh) {
printf("match\n");
return 0;
}
}
}
}
printf("no match\n");
return 1;
}
which works correctly in my tests, but uses some hacks. Specifically, lines marked with // *
have repeated values of enums, since I couldn't find a way to make loop sizes conditional on blood types.
What would be a better way, without forcing the blood type enums to be the same size? And more generally, is there a simpler version of the blood-type matching algorithm?
malloc
may fail ifargc
is too large. I wouldn't expect an excersise program to be nuke-proof. IMHO this is at most a potential weaknes (if theparse()
routine is ever used outside tis application), not a bug... :) There are more serious problems with the code than proper handling an improper input! \$\endgroup\$