//=============================================================================
// Contents    : AOJ ITP1_6_B
//               足りないトランプのカードを発見する
// Input       : 持っているカードの枚数 n
//               n 組の数字と絵柄(スペード'S'、ハート'H'、クラブ'C'、ダイヤ'D')
//               例)S 10　：　スペードの 10 を示す
// Output      : 足りないカード
// Constraints : 絵柄がスペード、ハート、クラブ、ダイヤの順番で出力
//               絵柄が同じ場合は、数字が小さい順に出力
// Author      : 廣部智也
// LastUpdate  : 2020/07/03
// Since       : 2020/06/17
//=============================================================================

#include <stdio.h>
#include <stdlib.h>                                                     // exit 関数を使用するため

#define LOWER_LIMIT_n     0
#define UPPER_LIMIT_n    52
#define LOWER_LIMIT_rank  1
#define UPPER_LIMIT_rank 13

enum {
    spade = 1,
    heart,
    club,
    diamond,
};

// 入力エラーを判断する関数
int Input_error( int number, int lower_limit, int upper_limit );        

// 所有しているカード情報を反映させる関数
void possess_cards( int n, char mark, int rank, int cards[] );          

// 不足カードを表示する関数
void lack_cards( int cards[] );                                         

int main(){

    int  n         = 0;
    char mark      = 'A';
    int  rank      = 0;
    int  cards[52] = {};
    
    int i = 0;
    
    // データの初期設定
    for ( i = 0; i < 13; i++ ){
        cards[i]    = spade;                                        // cards[0]〜[12]で
                                                                    // スペードの1、スペードの2、…、スペード13の不足を判断
        cards[13+i] = heart;                                        // [13]～[25]でハート
        cards[26+i] = club;                                         // [26]～[38]でハート
        cards[39+i] = diamond;                                      // [39]～[51]でハート
    }
        
    // データの入力：カードの所持数
    scanf("%d", &n );
    
    Input_error( n , LOWER_LIMIT_n, UPPER_LIMIT_n );

    // データの処理：所有カード情報の反映
    possess_cards( n, mark, rank, cards );
    
    // データの出力：不足カードを表示
    lack_cards( cards );

    return 0;
}



//====================================================================================================
// Contents    : 所有しているカード情報を格納
//               入力されたカードに該当する配列の値を 0 にする。
//               → lack_cards 関数で、値が 0 のときはそのカードを所有していると判断し、表示されない。
// Example     : mark = C、rank = 5 のとき
//               クラブの5を持っている情報をcards関数に反映させたい
//               cards[0]~[12]がスペード、cards[13]~[25]がハート、cards[26]~[38]がクラブの情報
//               cards[30(=rank+25)]の値を 0 にする
// Input       : mark、rank (所有しているカード情報)
// Output      : (所有しているカードに該当するcards配列の値が 0 になる)
// Author      : 廣部智也
// LastUpdate  : 2020/06/29
// Since       : 2020/06/17
//====================================================================================================

void possess_cards( int n, char mark, int rank, int cards[] ){
    
    int m = n;
    
    while( m-- > 0 ){
        
        // データの入力：所有しているカードの情報
        scanf("%s %d", &mark , &rank );
        
        Input_error( rank , LOWER_LIMIT_rank, UPPER_LIMIT_rank );
        
        // データの処理：所有カードの情報を反映
        if( mark == 'S' ){
            cards[rank-1]  = 0;                                     // スペードの"1"の所有情報はcards["0"]にある → -1
        }
        else if( mark == 'H' ){
            cards[rank+12] = 0;                                     // 12 = 13(スペードの枚数) - 1
        }
        else if( mark == 'C' ){
            cards[rank+25] = 0;                                     // 25 = 26(スペードとハートの枚数) - 1
        }
        else if( mark == 'D' ){
            cards[rank+38] = 0;
        }
        else{
            printf("Input error\n");
            exit(1);
        }
        
    }

    return;
}



//===========================================================================
// Contents    : 不足しているカードを出力
//               所有しているカードは、possess_cards関数において
//               cards配列の値が 0 になっていることで、出力されない。
// Example     : cards[30] はクラブの5の所有情報をもっており、3か0の値が格納
//               cards[30] = 3 のとき、"C 5"が表示される
//                 ※ 5 = 30(i) - 26(スペードとハートの枚数) + 1 = i - 25
//               cards[30] = 0 のとき、このカードは持っているので表示されない
// Author      : 廣部智也
// LastUpdate  : 2020/06/29
// Since       : 2020/06/17
//===========================================================================

void lack_cards( int cards[] ){

    int i = 0;
    
    for( i = 0; i < 52; i++ ){
        switch( cards[i] ) {
            case spade:
                printf("S %d\n", i + 1 );                           // cards["0"]はスペードの"1"の所有情報 → +1
                break;
            case heart:
                printf("H %d\n", i - 12 );
                break;
            case club:
                printf("C %d\n", i - 25 );
                break;
            case diamond:
                printf("D %d\n", i - 38 );
                break;
            case 0:
                break;
            default:
                printf("error\n");
                break;
        };
        
    }
    
    return;
}



//============================================================
// Contents    : 入力エラーを判断
// Input       : 調べる変数, 下限, 上限
// Output      : エラーなら強制終了
// Author      : 廣部智也
// LastUpdate  : 2020/06/05
// Since       : 2020/06/05
//============================================================

int Input_error( int number, int lower_limit, int upper_limit ){
    
    if( number < lower_limit || number > upper_limit ){
        printf("Input error\n");
        exit(1);
    }

    return 0;
}


Measured memory_bytes: 2044