
import java.io.*;
import java.util.*;

import static java.lang.Double.parseDouble;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import static java.lang.System.exit;


public class Main {

    static BufferedReader in;
    static PrintWriter out;
    static StringTokenizer tok;
    static boolean isLocal = false;


    class Item {
        String color;
        int cost;
        int value;
        int id;

        public Item(String color, int cost, int value, int id) {
            this.color = color;
            this.cost = cost;
            this.value = value;
            this.id = id;
        }
    }

    int n, dp_1 = -1000000;
    int budget;
    Item[] items;

    boolean checkMax(int numW, int numBlue, int numR, int numBlack) {
        return numW <= 1 && numBlue <= 5 && numR <= 5 && numBlack <= 3;
    }

    boolean checkMin(int numW, int numBlue, int numR, int numBlack) {
        return numW == 1 && numBlue >= 3 && numR >= 3 && numBlack >= 1;
    }

    boolean canAddItem(Item item, int numW, int numBlue, int numR, int numBlack, int currSpent) {
        if (item.color.equals("W")) numW++;
        if (item.color.equals("Blue")) numBlue++;
        if (item.color.equals("R")) numR++;
        if (item.color.equals("Black")) numBlack++;
        currSpent += item.cost;
        return checkMax(numW, numBlue, numR, numBlack) && currSpent <= budget && numW + numBlue + numR + numBlack <= 12;
    }

    int dp[][][][][][];

    int go(int i, int numW, int numBlue, int numR, int numBlack, int currSpent) {
        if (n - i + numW + numBlue + numR + numBlack < 12) return -10000;
        if (i == n)
            return (checkMin(numW, numBlue, numR, numBlack) && numW + numBlue + numR + numBlack == 12) ? 0 : -10000;
//        if (dp[numW][numBlack][numR][numBlue][i][currSpent] != dp_1)
//            return dp[numW][numBlack][numR][numBlue][i][currSpent];
        int res = -10000;
        res = max(res, go((int) (i + 1), numW, numBlue, numR, numBlack, currSpent));
        if (canAddItem(items[i], numW, numBlue, numR, numBlack, currSpent)) {
            if (items[i].color.equals("W")) numW++;
            if (items[i].color.equals("Blue")) numBlue++;
            if (items[i].color.equals("R")) numR++;
            if (items[i].color.equals("Black")) numBlack++;
            res = max(res, items[i].value + go( i + 1, numW, numBlue, numR, numBlack, (items[i].cost + currSpent)));
        }
        return //dp[numW][numBlack][numR][numBlue][i][currSpent] =
                res;
    }

    int ans;

    void Case() throws IOException {
        n = nextInt();
        budget = nextInt();
        items = new Item[n];
        for (int i = 0; i < n; i++) items[i] = new Item(next(), nextInt(), nextInt(), nextInt());
        dp = new int[2][4][6][6][n][budget + 1];
        for (int a = 0; a <= 1; a++)
            for (int i = 0; i <= 3; i++)
                for (int j = 0; j <= 5; j++)
                    for (int k = 0; k <= 5; k++)
                        for (int l = 0; l < n; l++)
                            for (int m = 0; m <= budget; m++)
                                dp[a][i][j][k][l][m] = dp_1;
        ans = go( 0,  0,  0,  0,  0,  0);
        out.println(ans);
        out.flush();
    }


    void solve() throws Exception {
        int t = nextInt();
        while (t-- > 0) Case();
    }

    private int gcd(int a, int b) {
        while (b > 0) {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    int min(int x, int y) {
        return Integer.min(x, y);
    }

    int max(int x, int y) {
        return Integer.max(x, y);
    }

    long min(long x, long y) {
        return Long.min(x, y);
    }

    long max(long x, long y) {
        return Long.max(x, y);
    }

    int[] sort(int[] arr) {
        sort(arr, 0, arr.length - 1);
        return arr;
    }

    void sort(int arr[], int l, int r) {
        if (l < r) {
            int m = (l + r) / 2;
            sort(arr, l, m);
            sort(arr, m + 1, r);
            merge(arr, l, m, r);
        }
    }

    void merge(int arr[], int l, int m, int r) {
        int n1 = m - l + 1;
        int n2 = r - m;
        int L[] = new int[n1];
        int R[] = new int[n2];
        for (int i = 0; i < n1; ++i)
            L[i] = arr[l + i];
        for (int j = 0; j < n2; ++j)
            R[j] = arr[m + 1 + j];
        int i = 0, j = 0;
        int k = l;
        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                arr[k] = L[i];
                i++;
            } else {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
        while (i < n1) {
            arr[k] = L[i];
            i++;
            k++;
        }
        while (j < n2) {
            arr[k] = R[j];
            j++;
            k++;
        }
    }

    class Seg implements Comparable<Seg> {
        int st, end;

        public Seg(int st, int end) {
            this.st = st;
            this.end = end;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Seg seg = (Seg) o;
            return st == seg.st &&
                    end == seg.end;
        }

        @Override
        public int hashCode() {
            return Objects.hash(st, end);
        }

        @Override
        public int compareTo(Seg seg) {
            return st == seg.st ? Integer.compare(end, seg.end) : Integer.compare(st, seg.st);
        }
    }

    private int[] na(int n) throws IOException {
        int[] a = new int[n];
        for (int i = 0; i < n; i++) a[i] = nextInt();
        return a;
    }

    private long[] nal(int n) throws IOException {
        long[] a = new long[n];
        for (int i = 0; i < n; i++) a[i] = nextLong();
        return a;
    }

    int nextInt() throws IOException {
        return parseInt(next());
    }

    long nextLong() throws IOException {
        return parseLong(next());
    }

    double nextDouble() throws IOException {
        return parseDouble(next());
    }

    String next() throws IOException {
        while (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    public static void main(String[] args) throws Exception {
        try {
            if (isLocal) {
                in = new BufferedReader(new FileReader("src/tests/sol.in"));
                out = new PrintWriter(new BufferedWriter(new FileWriter("src/tests/sol.out")));
            } else {
                in = new BufferedReader(new InputStreamReader(System.in));
                out = new PrintWriter(new OutputStreamWriter(System.out));
            }
//            long lStartTime = System.currentTimeMillis();
            new Main().solve();
//            long lEndTime = System.currentTimeMillis();
//            out.println("Elapsed time in seconds: " + (double) (lEndTime - lStartTime) / 1000.0);
            in.close();
            out.close();
        } catch (Throwable e) {
            e.printStackTrace();
            exit(1);
        }
    }
}
