Quine-McCluskey on Arduino Mega1280

Hello, I have coded a boolean algebra calculator for Arduino, it takes the S column of a truth table for a 2, 3 or 4 variable truth table and find the simplified expression for that truth table. I don't need this anymore. I am sharing this so you can pass it around and use it as a tool that doesn't usually exist on arduinos. The formatting is horrible, there are small logical mistake and it only run on big arduino like the mega 1280. But it seems to work most of the time (I have not succeeded in getting a wrong answer after 100 tests). If someone want to make it into a library, improve on it, or make it more lisible, or anything like this you are welcome. I am only a beginner programmer. It took me a month to program this and it's horribly presented.

But apparently I cannot add file nor links so I don't know how to share it...

Chasing links is not normal here. Read the pinned post re 'How to get the best from the forum'

It's my first post so I can't add files...

No need to add files, we don't want you to ad files. If you have not read the pinned post re 'How to get the most from the forum', especially the part about posting source code ^^^^ << that's a clue, it even says CODE.

What is your question, it's very hard to assist when all you say is

it seems to work most of the time

and

there are small logical mistake

I don't have a question I don't need it any more I just wanted to share it for anyone that needs it, no matter how badly it's written if I had it a month ago it would have saved me 2 weeks of work.

Ok, so go ahead and post it. Since you mentioned it's a mess, use the Arduino IDE Tools Auto Format first to clean it up a bit, then Edit Copy For Forum and then paste into your post.

One of my colleague showed me how to turn it into a cpp and h. I think that would be more useful to do that. This way even if it's a mess at least anyone can use it. I am currently working on that.

OK, so this is the cpp file.

#include "QuineMcCluskeyandPetrick.h"

// Solver universel
static void clearArrays() {
  for (int i = 0; i < 26; i++) {
      //processed[i] = ""; // Clear each string in the array
      letterCounts[i] = 0; // Reset each integer to 0
  }
}

String QuineMcCluskeyandPetrick(String input) {
  String result;

  clearArrays();

  // Check the length of the input string
  if (input.length() == 4) {
    result = solve2x2(input);
  } 
  else if (input.length() == 8) {
    result = solve2x4(input);
  } 
  else if (input.length() == 16) {
    result = solve4x4(input);
  } 
  else {
    result = "Invalid length";
  }

  return result;
}

//Solver 4 par 4 

// Define a 2D array stored in program memory
static const char data[18][2][17] PROGMEM = {
    {"1111111111111111", "1"},
    {"0111111111111111", "A+B+C+D"},
    {"1011111111111111", "A+B+C+D'"},
    {"1101111111111111", "A+B+C'+D"},
    {"1110111111111111", "A+B+C'+D'"},
    {"1111011111111111", "A+B'+C+D"},
    {"1111101111111111", "A+B'+C+D'"},
    {"1111110111111111", "A+B'+C'+D"},
    {"1111111011111111", "A+B'+C'+D'"},
    {"1111111101111111", "A'+B+C+D"},
    {"1111111110111111", "A'+B+C+D'"},
    {"1111111111011111", "A'+B+C'+D"},
    {"1111111111101111", "A'+B+C'+D'"},
    {"1111111111110111", "A'+B'+C+D"},
    {"1111111111111011", "A'+B'+C+D'"},
    {"1111111111111101", "A'+B'+C'+D"},
    {"1111111111111110", "A'+B'+C'+D'"},
    {"0000000000000000", "0"}
};

static String findValue(String searchStr) {
  char buffer[17]; // Temporary buffer to store retrieved strings (16 characters + null terminator)
  
  for (int i = 0; i < 18; i++) {
    // Retrieve the binary string from the first column of the current row
    strcpy_P(buffer, data[i][0]);

    if (searchStr == String(buffer)) { // Compare the search string with the retrieved string
      // Retrieve the value from the second column
      strcpy_P(buffer, data[i][1]);
      return String(buffer); // Return the corresponding value as a String
    }
  }
  
  return "Not found"; // Return "Not found" if the search string isn't found
}

static String processBinaryInput(String binaryInput) {
  // Array to store positions of '1's
  int positions[16];
  size_t size = 0;

  // Convert binary string to positions of '1's
  for (int i = 0; i < 16; i++) {
    if (binaryInput.charAt(i) == '1') {
      positions[size] = i;  // Store the index of '1'
      size++;  // Increase the size of positions array
    }
  }

  // Print the positions array for debugging
  Serial.print("Positions: ");
  for (int i = 0; i < size; i++) {
    Serial.print(positions[i]);
    Serial.print(" ");
  }
  Serial.println();

  // Call the function to process values and get the result
  return processValues(positions, size);
}

static String solve4x4(String input) {
  // Ensure the input length is 16
  if (input.length() != 16) {
    return "Error: Input must be a 16-character string.";
  }

  // Count the number of '1's in the input
  int countOnes = 0;
  for (int i = 0; i < input.length(); i++) {
    if (input[i] == '1') {
      countOnes++;
    }
  }

  // Apply Function A if count is 0, 16, or 1
  if (countOnes == 0 || countOnes == 16 || countOnes == 15) {
    return findValue(input); // Pass the input to the function
  } else {
    return processBinaryInput(input); // Pass the input to the function
  }
}

//Solveur 2 par 2

// Define the 2D array stored in program memory
static const char data2x2[18][2][10] PROGMEM = {
    {"0000", "0"},
    {"0001", "AB"},
    {"0010", "AB'"},
    {"0011", "A"},
    {"0100", "A'B"},
    {"0101", "B"},
    {"0110", "AB'+A'B"},
    {"0111", "A+B"},
    {"1000", "A'B'"},
    {"1001", "A'B'+AB"},
    {"1010", "B'"},
    {"1011", "B'+A"},
    {"1100", "A'"},
    {"1101", "A'+B"},
    {"1110", "A'+B'"},
    {"1111", "1"}
};

// Function to find the string and return the value from the second column
static String solve2x2(String searchStr) {
  char buffer[20]; // Temporary buffer for data retrieval (max 7 characters + null terminator)

  for (int i = 0; i < 16; i++) {
    // Retrieve the binary string (first column) from `PROGMEM`
    strcpy_P(buffer, data2x2[i][0]);

    if (searchStr == String(buffer)) { // Compare search string with retrieved string
      // Retrieve the corresponding value (second column) from `PROGMEM`
      strcpy_P(buffer, data2x2[i][1]);
      return String(buffer); // Return the corresponding value as a String
    }
  }

  return "Not found"; // Return "Not found" if the search string isn't found
}

//Solver 2 par 4

// Function to expand the 8-bit input binary string to a 16-bit binary string
static String expandTo16Bit(String input) {
  String expanded = "";
  
  // Loop through each bit of the input string and repeat it
  for (int i = 0; i < input.length(); i++) {
    // Add the bit twice to the expanded string
    expanded += input.charAt(i);
    expanded += input.charAt(i);
  }

  return expanded;
}

// solve2x4 function that applies two transformations and outputs the result
static String solve2x4(String inputBinary) {
  // Apply functionA to the input binary
  String resultA = expandTo16Bit(inputBinary);

  // Apply functionB to the result of functionA
  String resultB = solve4x4(resultA);

  // Return the final result
  return resultB;
}

static String processValues(int values[], size_t size) {

    // Groups to hold the binary strings
    String groups[5][10]; // 5 groups (0 to 4 ones), each can hold up to 10 items
    int decimalGroups[5][10]; // 5 groups (0 to 4 ones), each can hold up to 10 items
    int groupSizes[5];    // To track the size of each group

    // Call the function with the input list
    processValuesWithTracking(values, size, groups, decimalGroups, groupSizes);

    // Print all groups with decimal values and the corresponding binary string
    Serial.println("Groups and corresponding binary strings:");
    printGroupsWithDecimalAndTracking(groups, decimalGroups, groupSizes);

    createPairsAcrossGroups(groups, decimalGroups, groupSizes);
    createPairsAcrossGroups(groups, decimalGroups, groupSizes);

    processTranslatedGroups(groups, groupSizes);

    String sortedTerms = sortTranslatedTerms(groups, groupSizes);

    // Print the sorted terms
    Serial.println("Sorted Translated Terms:");
    Serial.println(sortedTerms);

    processSortedTerms(sortedTerms);

    String result = "";

    String implicantCoverage[16];   // Array to store implicants
    int mintermsCovered[16][16];   // 2D array to store minterms covered by each implicant
    int implicantCount = 0;        // Counter for implicants
    String mintermImplicants[16];

    // Call the function with all required arguments
    findCoveredMinterms(sortedTerms, result, implicantCoverage, mintermsCovered, implicantCount);

    // Print the results
    Serial.println("Result:");
    Serial.println(result);

    Serial.println("Implicants and their covered minterms:");
    for (int i = 0; i < implicantCount; i++) {
        Serial.print(implicantCoverage[i] + ": ");
        for (int j = 0; j < 16; j++) {
            if (mintermsCovered[i][j] == -1) break; // Stop if no more minterms
            Serial.print(mintermsCovered[i][j]);
            Serial.print(" ");
        }
        Serial.println();
    }

    // Output the result to the Serial Monitor
    Serial.println("The expressions that uniquely cover minterms are:");
    Serial.println(result);

    // Step 3: Call findImplicantsForMinterms
    findImplicantsForMinterms(implicantCoverage, mintermsCovered, implicantCount, mintermImplicants);

    // Step 4: Print the result
    for (int i = 0; i < 16; i++) {
        if (mintermImplicants[i].length() > 0) {
            Serial.print("Minterm ");
            Serial.print(i);
            Serial.print(": ");
            Serial.println(mintermImplicants[i]);
        }
    }

    String formattedImplicants[16];
    formatMintermImplicants(mintermImplicants, formattedImplicants);

    // Print the result
    for (int i = 0; i < 16; i++) {
        if (formattedImplicants[i].length() > 0) {
            Serial.print("Minterm ");
            Serial.print(i);
            Serial.print(": ");
            Serial.println(formattedImplicants[i]);
        }
    }

    String combined = combineFormattedImplicants(formattedImplicants);
    Serial.print("Combined implicants: ");
    Serial.println(combined);

    String output = addQuotesBetweenPlusAndParentheses(combined);

    Serial.println("Output: " + output);

    // Declare variables with exotic names to hold the results
    String chimericOutput = "";
    String crypticMappings = "";

    // Call the function with the input string
    replaceTerms(output, chimericOutput, crypticMappings);

    // Define a POS input string
    String posInput = chimericOutput;
    String sopOutput = "";

    // Initial Sum of Product (SoP) expression
    String sop = posInput;
    Serial.println("Initial Expression: ");
    Serial.println(sop);

    while (true) {
        // Locate the first two sets of parentheses
        int firstOpen = sop.indexOf('(');
        int firstClose = sop.indexOf(')', firstOpen);
        int secondOpen = sop.indexOf('(', firstClose);
        int secondClose = sop.indexOf(')', secondOpen);

        // Break if there are no two pairs of parentheses left
        if (firstOpen == -1 || firstClose == -1 || secondOpen == -1 || secondClose == -1) {
            Serial.println("Final Expanded Expression: ");
            Serial.println(sop);
            break;
        }

        // Extract parts
        String firstPart = sop.substring(firstOpen + 1, firstClose);
        String secondPart = sop.substring(secondOpen + 1, secondClose);

        // Multiply, simplify, and retain one of each duplicate
        String expanded = multiplyAndSimplify(firstPart, secondPart);

        // Replace the first two sets of parentheses with the expanded result
        sop = sop.substring(0, firstOpen) + "(" + expanded + ")" + sop.substring(secondClose + 1);

        // Debug: Print updated expression
        Serial.println("Updated Expression:");
        Serial.println(sop);
    }

    // Example input
    String RA = sop;

    // Call the groupLetters function
    groupLetters10(RA);

    Serial.println(crypticMappings);

    String singleString = convertCrypticMappingToString(crypticMappings);
    Serial.println(singleString);  // Print the result to the serial monitor

    RA.replace("(", "");  // Replace all '(' with an empty string
    RA.replace(")", "");  // Replace all ')' with an empty string

    // Process the input string and count occurrences for each term
    processInput(singleString);

    String encodedMessage = "";  // String to hold the final output

    bool first = true;  // Flag to track if it's the first result
    for (char letter = 'A'; letter <= 'Z'; letter++) {
        int index = letter - 'A';  // Convert 'A' to index 0, 'B' to index 1, etc.
        if (letterCounts[index] > 0) {
            if (!first) {
                encodedMessage += ", ";  // Add a comma before subsequent results
            }
            first = false;  // After the first result, set the flag to false
            encodedMessage += letter;  // Add the letter to the string
            encodedMessage += letterCounts[index];  // Add the count for the letter
        }
    }

    // Now you can print the result string to the serial monitor
    Serial.println(encodedMessage);

    Serial.println();
    Serial.println(RA);

    // Example usage
    String words = RA;
    String binomes = encodedMessage;
    String leastPointsWord = calculateWordPoints(words, binomes);

    // Now you can use the result in your code, here we're printing it to the serial monitor
    Serial.print("Word with least points: ");
    Serial.println(leastPointsWord);

    String inputWord = leastPointsWord;
    String description = singleString;

    // Get the replaced term result
    String nt = replaceLettersWithTerms(inputWord, description);

    // Return the final result (nt)
    return nt;
}

static void processValuesWithTracking(const int* values, size_t size, String groups[5][10], int decimalGroups[5][10], int groupSizes[5]) {
  // Initialize group sizes
  for (int i = 0; i < 5; i++) {
    groupSizes[i] = 0;
  }

  // Process each value in the input list
  for (size_t k = 0; k < size; k++) {
    int num = values[k];

    // Convert the number to a 4-bit binary string
    String binary = "";
    for (int i = 3; i >= 0; i--) {
      binary += String((num >> i) & 1);
    }

    // Count the number of 1s in the binary string
    int oneCount = 0;
    for (size_t j = 0; j < binary.length(); j++) {
      if (binary[j] == '1') {
        oneCount++;
      }
    }

    // Add to the corresponding group
    if (oneCount >= 0 && oneCount <= 4) {
      int index = groupSizes[oneCount]; // Current size of the group
      groups[oneCount][index] = binary; // Add binary string to the group
      decimalGroups[oneCount][index] = num; // Add decimal value to the group
      groupSizes[oneCount]++; // Increment the size of the group
    }
  }
}

static void printGroupsWithDecimalAndTracking(String groups[5][10], int decimalGroups[5][10], int groupSizes[5]) {
  String allGroupsOutput = "";

  // Iterate over each group and add the group information to the output string
  for (int i = 0; i < 5; i++) {
    allGroupsOutput += "Group with " + String(i) + " ones:\n";
    
    if (groupSizes[i] > 0) {
      for (int j = 0; j < groupSizes[i]; j++) {
        allGroupsOutput += String(decimalGroups[i][j]) + ": " + groups[i][j] + "\n";
      }
    } else {
      allGroupsOutput += "No entries in this group.\n";
    }
  }

  // Print all groups at once
  Serial.println(allGroupsOutput);
}

static void createPairsAcrossGroups(String groups[5][10], int decimalGroups[5][10], int groupSizes[5]) {
  String newGroups[5][10];       // Temporary storage for new groups
  int newGroupSizes[5] = {0};    // Sizes of temporary groups
  bool madeChange;               // Tracks if any new term was created

  do {
    madeChange = false;
    bool used[5][10] = {{false}}; // Tracks whether terms were used in the current iteration

    // Iterate through all pairs of groups (not just adjacent)
    for (int i = 0; i < 5; i++) {
      for (int j = i + 1; j < 5; j++) {  // Compare group i with group j (i < j)
        for (int k = 0; k < groupSizes[i]; k++) {
          for (int l = 0; l < groupSizes[j]; l++) {
            String bin1 = groups[i][k];
            String bin2 = groups[j][l];
            
            // Find the difference between the two binary terms
            int diffCount = 0, diffIndex = -1;
            for (int bit = 0; bit < bin1.length(); bit++) {
              if (bin1[bit] != bin2[bit]) {
                diffCount++;
                diffIndex = bit;
              }
            }

            if (diffCount == 1) {  // Terms differ by exactly one bit
              String newTerm = bin1;
              newTerm[diffIndex] = '-';  // Replace differing bit with '-'
              
              // Check if the new term already exists in the new group
              bool isDuplicate = false;
              for (int m = 0; m < newGroupSizes[i]; m++) {
                if (newGroups[i][m] == newTerm) {
                  isDuplicate = true;
                  break;
                }
              }

              if (!isDuplicate) {
                newGroups[i][newGroupSizes[i]] = newTerm; // Add new term
                newGroupSizes[i]++;
                madeChange = true;
                
                // Debugging: Log the new term and which terms created it
                Serial.print("New group formed by: ");
                Serial.print(bin1);
                Serial.print(" and ");
                Serial.print(bin2);
                Serial.print(" -> New term: ");
                Serial.println(newTerm);
              }

              used[i][k] = true;       // Mark original terms as used
              used[j][l] = true;       // Mark original terms as used
            }
          }
        }
      }
    }

    // Debugging: Print the current state of the groups and used array
    Serial.println("Current groups after comparison:");
    for (int i = 0; i < 5; i++) {
      Serial.print("Group ");
      Serial.print(i);
      Serial.print(" (size ");
      Serial.print(groupSizes[i]);
      Serial.println("):");
      for (int j = 0; j < groupSizes[i]; j++) {
        Serial.println(groups[i][j]);
      }
    }

    // Update groups: retain unused terms and add new terms
    for (int i = 0; i < 5; i++) {
      int newIndex = 0;

      // Retain unused terms
      for (int j = 0; j < groupSizes[i]; j++) {
        if (!used[i][j]) {
          groups[i][newIndex] = groups[i][j];
          decimalGroups[i][newIndex] = decimalGroups[i][j];
          newIndex++;
        }
      }

      // Add new terms from this iteration
      for (int j = 0; j < newGroupSizes[i]; j++) {
        groups[i][newIndex] = newGroups[i][j];
        newIndex++;
      }

      // Update group size
      groupSizes[i] = newIndex;
    }

    // Clear new groups for the next iteration
    for (int i = 0; i < 5; i++) {
      newGroupSizes[i] = 0;
    }

    // Debugging: Print the groups after adding new terms and updating sizes
    Serial.println("Groups after adding new terms:");
    for (int i = 0; i < 5; i++) {
      Serial.print("Group ");
      Serial.print(i);
      Serial.print(" (size ");
      Serial.print(groupSizes[i]);
      Serial.println("):");
      for (int j = 0; j < groupSizes[i]; j++) {
        Serial.println(groups[i][j]);
      }
    }

  } while (madeChange);  // Repeat until no changes are made

  // Debugging: Print final groups before removing duplicates
  Serial.println("Final groups before duplicates removal:");
  for (int i = 0; i < 5; i++) {
    if (groupSizes[i] > 0) {
      Serial.print("Group with ");
      Serial.print(i);
      Serial.println(" ones:");
      for (int j = 0; j < groupSizes[i]; j++) {
        Serial.println(groups[i][j]);
      }
    }
  }

  // Remove duplicates from the final groups
  for (int i = 0; i < 5; i++) {
    removeDuplicates(groups[i], groupSizes[i]);
  }

  // Debugging: Print final groups after duplicates removal
  Serial.println("Final groups after duplicates removal:");
  for (int i = 0; i < 5; i++) {
    if (groupSizes[i] > 0) {
      Serial.print("Group with ");
      Serial.print(i);
      Serial.println(" ones:");
      for (int j = 0; j < groupSizes[i]; j++) {
        Serial.println(groups[i][j]);
      }
    }
  }
}


// Helper function to remove duplicates from a group
static void removeDuplicates(String group[10], int &size) {
  for (int i = 0; i < size; i++) {
    for (int j = i + 1; j < size; j++) {
      if (group[i] == group[j]) {
        // Shift elements to remove duplicate
        for (int k = j; k < size - 1; k++) {
          group[k] = group[k + 1];
        }
        size--;  // Decrease the size of the group
        j--;  // Recheck the new element at index j
      }
    }
  }
}

static String translateTerm(String binTerm) {
  String translatedTerm = "";

  // Iterate over each bit in the binary term (4 bits)
  for (int i = 0; i < 4; i++) {
    char bit = binTerm[i];

    if (bit == '1') {
      // '1' translates to 'A', 'B', 'C', or 'D'
      if (i == 0) translatedTerm += "A";
      else if (i == 1) translatedTerm += "B";
      else if (i == 2) translatedTerm += "C";
      else if (i == 3) translatedTerm += "D";
    } 
    else if (bit == '0') {
      // '0' translates to 'A', 'B', 'C', or 'D' with a '
      if (i == 0) translatedTerm += "A'";
      else if (i == 1) translatedTerm += "B'";
      else if (i == 2) translatedTerm += "C'";
      else if (i == 3) translatedTerm += "D'";
    }
    else if (bit == '-') {
      // If there's a '-', suppress the letter at that position
      // Don't append anything for this position
      continue;
    }
  }

  return translatedTerm;
}

static void processTranslatedGroups(String groups[5][10], int groupSizes[5]) {
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < groupSizes[i]; j++) {
      // Translate each binary term in the group
      String translatedTerm = translateTerm(groups[i][j]);
      Serial.print("Original: ");
      Serial.print(groups[i][j]);
      Serial.print(" -> Translated: ");
      Serial.println(translatedTerm);
    }
  }
}

static String sortTranslatedTerms(String groups[5][10], int groupSizes[5]) {
  // Create an array to store the translated terms
  String allTranslatedTerms[50];
  int index = 0;

  // Collect all translated terms into one array
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < groupSizes[i]; j++) {
      String translatedTerm = translateTerm(groups[i][j]);
      allTranslatedTerms[index++] = translatedTerm;
    }
  }

  // Sort all translated terms alphabetically, taking apostrophes into account
  for (int i = 0; i < index - 1; i++) {
    for (int j = i + 1; j < index; j++) {
      if (compareTerms(allTranslatedTerms[i], allTranslatedTerms[j])) {
        String temp = allTranslatedTerms[i];
        allTranslatedTerms[i] = allTranslatedTerms[j];
        allTranslatedTerms[j] = temp;
      }
    }
  }

  // Join the sorted translated terms into a single string for easy display
  String sortedTerms = "";
  for (int i = 0; i < index; i++) {
    sortedTerms += allTranslatedTerms[i] + " ";
  }

  return sortedTerms;
}

static bool compareTerms(String term1, String term2) {
  int len1 = term1.length();
  int len2 = term2.length();

  int minLength = min(len1, len2);
  for (int i = 0; i < minLength; i++) {
    char char1 = term1[i];
    char char2 = term2[i];

    if (char1 == '\'') char1 = term1[i + 1];  // Skip the apostrophe
    if (char2 == '\'') char2 = term2[i + 1];  // Skip the apostrophe

    if (char1 != char2) {
      return char1 < char2;  // Alphabetically compare letters
    }
  }

  return len1 < len2;  // If they are the same up to the shortest length, consider their lengths
}

static void getMinterms(String term, int minterms[], int &mintermCount) {
  mintermCount = 0;

  // We assume there are four variables: A, B, C, D
  // A -> bit 3, B -> bit 2, C -> bit 1, D -> bit 0
  int totalMinterms = 16;

  // Array to store which variables are fixed by the term
  bool variableStates[4] = {false, false, false, false};  // A, B, C, D
  bool isNegated[4] = {false, false, false, false};        // A', B', C', D'

  // Check each character of the term to determine the state of each variable
  for (int i = 0; i < term.length(); i++) {
    char ch = term[i];
    int varIndex = -1;

    // Identify which variable the character corresponds to (A, B, C, D)
    if (ch == 'A') varIndex = 0;
    else if (ch == 'B') varIndex = 1;
    else if (ch == 'C') varIndex = 2;
    else if (ch == 'D') varIndex = 3;

    if (varIndex != -1) {
      // If the next character is a `'`, it's negated
      if (i + 1 < term.length() && term[i + 1] == '\'') {
        isNegated[varIndex] = true; // Negated variable
        i++; // Skip the `'`
      } else {
        isNegated[varIndex] = false; // Non-negated variable
      }

      variableStates[varIndex] = true; // The variable is now fixed
    }
  }

  // Iterate over all 16 possible minterms
  for (int i = 0; i < totalMinterms; i++) {
    bool match = true;

    // Check for each variable (A, B, C, D)
    for (int j = 0; j < 4; j++) {
      if (variableStates[j]) { // This variable is fixed by the term
        bool bitSet = (i >> (3 - j)) & 1; // Get the bit for the variable

        // If it's negated, it must be 0
        if (isNegated[j] && bitSet) {
          match = false;
          break;
        }

        // If it's not negated, it must be 1
        if (!isNegated[j] && !bitSet) {
          match = false;
          break;
        }
      }
    }

    // If the minterm matches, add it to the list
    if (match) {
      minterms[mintermCount] = i;
      mintermCount++;
    }
  }
}

// Function to process sorted terms and print their corresponding minterms
static void processSortedTerms(String sortedTerms) {
  String term = "";

  // Array to store minterms
  int minterms[16];  // There are 16 possible minterms (for 4 variables)
  int mintermCount = 0;  // Counter for the number of minterms

  // Trim leading/trailing spaces to avoid issues with empty terms
  sortedTerms.trim();

  // Split the sortedTerms into individual terms by space
  for (int i = 0; i < sortedTerms.length(); i++) {
    char ch = sortedTerms[i];

    // If we reach a space, process the current term
    if (ch == ' ') {
      if (term.length() > 0) {
        // Get the minterms for the current term
        getMinterms(term, minterms, mintermCount);

        // Print the term and the corresponding minterms
        Serial.print("Term: ");
        Serial.print(term);
        Serial.print(" -> Minterms: ");
        for (int j = 0; j < mintermCount; j++) {
          Serial.print(minterms[j]);
          if (j < mintermCount - 1) {
            Serial.print(", ");
          }
        }
        Serial.println();

        // Reset term for the next iteration
        term = "";
        mintermCount = 0;  // Reset minterm count for the next term
      }
    } else {
      term += ch;  // Add the character to the current term
    }
  }

  // Process the last term if any (after the final space)
  if (term.length() > 0) {
    getMinterms(term, minterms, mintermCount);
    Serial.print("Term: ");
    Serial.print(term);
    Serial.print(" -> Minterms: ");
    for (int j = 0; j < mintermCount; j++) {
      Serial.print(minterms[j]);
      if (j < mintermCount - 1) {
        Serial.print(", ");
      }
    }
    Serial.println();
  }
}

static void findCoveredMinterms(String sortedTerms, String &result, String (&implicantCoverage)[16], int (&mintermsCovered)[16][16], int &implicantCount) {
  int mintermCount[16] = {0};   // To store the count of terms covering each minterm
  String uniqueTermForMinterm[16]; // To store the term uniquely covering each minterm
  String terms[16];             // To store all unique terms parsed from sortedTerms
  int termCount = 0;

  // Initialize the result string
  result = "";

  // Parse the sortedTerms into individual terms
  for (int i = 0; i < sortedTerms.length(); i++) {
    String term = "";

    // Collect each term
    while (i < sortedTerms.length() && sortedTerms[i] != ' ') {
      term += sortedTerms[i];
      i++;
    }

    // Avoid adding duplicate terms
    bool isDuplicate = false;
    for (int j = 0; j < termCount; j++) {
      if (terms[j] == term) {
        isDuplicate = true;
        break;
      }
    }

    if (!isDuplicate && term.length() > 0) {
      terms[termCount++] = term;
    }
  }

  // Map minterms to terms and track coverage
  implicantCount = 0; // Reset implicant count
  for (int i = 0; i < termCount; i++) {
    int termMinterms[16];
    int termMintermCount = 0;

    // Get the minterms for the current term
    getMinterms(terms[i], termMinterms, termMintermCount);

    // Store the implicant in the implicantCoverage array
    implicantCoverage[implicantCount] = terms[i];

    // Reset the minterms covered by this implicant
    for (int j = 0; j < 16; j++) {
      mintermsCovered[implicantCount][j] = -1; // -1 indicates no coverage
    }

    // Update minterm coverage and record the term
    for (int j = 0; j < termMintermCount; j++) {
      int minterm = termMinterms[j];

      // Track minterms covered by this term
      mintermsCovered[implicantCount][j] = minterm;

      if (mintermCount[minterm] == 0) {
        // If no other term covers this minterm yet, record this term
        uniqueTermForMinterm[minterm] = terms[i];
      } else {
        // If the minterm is already covered by another term, clear unique record
        uniqueTermForMinterm[minterm] = "";
      }

      // Increment coverage count for this minterm
      mintermCount[minterm]++;
    }

    // Increment the implicant count
    implicantCount++;
  }

  // Add terms to the result where minterms are uniquely covered
  for (int i = 0; i < 16; i++) {
    if (mintermCount[i] == 1 && uniqueTermForMinterm[i].length() > 0) {
      if (result.indexOf(uniqueTermForMinterm[i]) == -1) { // Avoid duplicate terms in the result
        result += uniqueTermForMinterm[i];
        result += " ";
      }
    }
  }
}

// Function to find implicants for minterms
static void findImplicantsForMinterms(String implicantCoverage[], 
                               int mintermsCovered[][16], 
                               int implicantCount, 
                               String mintermImplicants[]) {

    // Initialize the result array with empty strings
    for (int i = 0; i < 16; i++) {
        mintermImplicants[i] = "";
    }

    // Loop over all implicants
    for (int i = 0; i < implicantCount; i++) {
        Serial.print("Processing implicant: ");
        Serial.println(implicantCoverage[i]);

        for (int j = 0; j < 16; j++) {
            int minterm = mintermsCovered[i][j];
            if (minterm == -1) {
                // No more minterms covered by this implicant
                break;
            }

            // Append the implicant to the list of the corresponding minterm, if not already added
            if (mintermImplicants[minterm].length() > 0) {
                // Check if the implicant is already added to the minterm
                if (mintermImplicants[minterm].indexOf(implicantCoverage[i]) == -1) {
                    mintermImplicants[minterm] += ":"; // Add separator if it's not the first implicant
                    mintermImplicants[minterm] += implicantCoverage[i];
                }
            } else {
                // First implicant for this minterm
                mintermImplicants[minterm] += implicantCoverage[i];
            }

            Serial.print("Minterm ");
            Serial.print(minterm);
            Serial.print(" covered by implicant: ");
            Serial.println(implicantCoverage[i]);
        }
    }
}

// Function to format minterm implicants into readable format
static void formatMintermImplicants(String mintermImplicants[], String formattedImplicants[]) {
    // Iterate through each minterm
    for (int i = 0; i < 16; i++) {
        Serial.print("Formatting minterm ");
        Serial.println(i);

        // Check if the minterm has any implicants
        if (mintermImplicants[i].length() > 0) {
            String formatted = "(";
            bool firstImplicant = true;
            
            // Iterate through each character in the implicant string
            for (int j = 0; j < mintermImplicants[i].length(); j++) {
                // Find the end of the current implicant (until the colon or end of the string)
                int start = j;
                while (j < mintermImplicants[i].length() && mintermImplicants[i][j] != ':') {
                    j++;
                }

                // Extract the implicant substring
                String implicant = mintermImplicants[i].substring(start, j);
                
                // Add to the formatted result
                if (!firstImplicant) {
                    formatted += "+";
                }
                formatted += implicant;
                firstImplicant = false;  // Ensure "+" is added between implicants
            }

            formatted += ")";
            formattedImplicants[i] = formatted;
            Serial.print("Formatted implicants for minterm ");
            Serial.print(i);
            Serial.print(": ");
            Serial.println(formattedImplicants[i]);
        } else {
            formattedImplicants[i] = "";  // No implicants for this minterm
            Serial.print("No implicants for minterm ");
            Serial.println(i);
        }
    }
}

// Function to combine all formatted implicants into one string
static String combineFormattedImplicants(String formattedImplicants[]) {
    String combined = "";  // Initialize an empty string to store the result

    // Loop through each minterm
    for (int i = 0; i < 16; i++) {
        if (formattedImplicants[i].length() > 0) {
            // Add the formatted implicant enclosed in parentheses to the combined string
            combined += formattedImplicants[i];
        }
    }

    // Return the combined string
    return combined;
}

static String addQuotesBetweenPlusAndParentheses(String input) {
  String result = "";
  bool insideParentheses = false;
  bool quotingRequired = false;
  String temp = "";

  for (int i = 0; i < input.length(); i++) {
    char currentChar = input[i];

    if (currentChar == '(') {
      // Start of parentheses block
      if (temp.length() > 0) {
        // Add any collected content into quotes before starting new block
        result += "\"" + temp + "\"";
        temp = "";
      }
      result += "(";
      insideParentheses = true;
      quotingRequired = true;
    } else if (currentChar == ')') {
      // End of parentheses block
      if (temp.length() > 0) {
        result += "\"" + temp + "\"";
        temp = "";
      }
      result += ")";
      insideParentheses = false;
      quotingRequired = false;
    } else if (currentChar == '+') {
      // Plus symbol
      if (temp.length() > 0) {
        result += "\"" + temp + "\"";
        temp = "";
      }
      result += "+";
      quotingRequired = true;
    } else if (quotingRequired && !isspace(currentChar)) {
      // Collect content to be quoted
      temp += currentChar;
    } else {
      // Add non-quoted content (e.g., spaces)
      if (temp.length() > 0) {
        result += "\"" + temp + "\"";
        temp = "";
      }
      result += currentChar;
    }
  }

  // Add any leftover content
  if (temp.length() > 0) {
    result += "\"" + temp + "\"";
  }

  return result;
}

// Helper function to generate a random unique letter
static char generateRandomUniqueLetter(bool usedLetters[]) {
  char letter;
  do {
    letter = 'A' + random(0, 26);  // Pick a random letter between A and Z
  } while (usedLetters[letter - 'A']); // Ensure the letter hasn't been used already
  usedLetters[letter - 'A'] = true;   // Mark the letter as used
  return letter;
}

static void replaceTerms(String input, String &arcaneOutput, String &mysticMappings) {
  bool usedLetters[26] = {false};  // Array to keep track of used letters
  String terms[50];  // Array to store the unique terms (can store up to 50 terms)
  char letters[50];  // Array to store the corresponding letters for the terms
  int termCount = 0;  // Counter for the number of terms encountered

  // Split the input string based on the quote symbols
  int startIndex = -1;  // To store the starting index of the quoted term
  for (int i = 0; i < input.length(); i++) {
    if (input.charAt(i) == '"') {
      if (startIndex == -1) {
        startIndex = i;  // Found the start of a quoted term
      } else {
        String term = input.substring(startIndex + 1, i);  // Extract the term between quotes
        char randomLetter;

        // Check if the term already exists
        int foundIndex = -1;
        for (int j = 0; j < termCount; j++) {
          if (terms[j] == term) {
            foundIndex = j;
            break;
          }
        }

        // If the term already has a letter, use that letter, else assign a new letter
        if (foundIndex == -1) {
          randomLetter = generateRandomUniqueLetter(usedLetters);  // Get a random unique letter

          // Ensure we don't reuse the same letter
          if (randomLetter == '\0') {
            Serial.println("Error: No available letters left!");  // If we get '\0', we ran out of available letters
            return;  // Exit if no letters are available
          }

          // Store the new term and its corresponding letter
          terms[termCount] = term;
          letters[termCount] = randomLetter;
          termCount++;

          // Mark the letter as used
          usedLetters[randomLetter - 'A'] = true;

          // Debugging: Log the assigned letter
          Serial.print("Assigned letter: ");
          Serial.println(randomLetter);

          // Append the mapping to mysticMappings only the first time
          mysticMappings += String(randomLetter) + " -> \"" + term + "\"\n";
        } else {
          randomLetter = letters[foundIndex];  // Use the existing letter for the term
        }

        // Append the random letter to the output (only once per term)
        arcaneOutput += randomLetter;

        startIndex = -1;  // Reset for the next quote
      }
    } else if (startIndex == -1) {
      arcaneOutput += input.charAt(i);  // Append non-quoted characters to the result string
    }
  }

  // Print final outputs directly for inspection
  Serial.println("arcaneOutput: " + arcaneOutput);
  Serial.println("mysticMappings: " + mysticMappings);
}

static void groupLetters10(String input) {
  String currentGroup = "";  // To store the current group of letters
  String groups[50];  // Array to store the resulting groups
  int groupCount = 0;  // Counter for the number of groups

  // Loop through the string and create groups
  for (int i = 0; i < input.length(); i++) {
    char currentChar = input.charAt(i);

    // Check if the current character is a letter (A-Z, a-z)
    if (isAlpha(currentChar)) {
      // Add to the current group if it's a letter
      currentGroup += currentChar;
    } else {
      // If we encounter a non-letter, store the current group (if it's not empty)
      if (currentGroup.length() > 0) {
        groups[groupCount++] = currentGroup;  // Store the group
        currentGroup = "";  // Reset the current group
      }
    }
  }

  // If there is a group left at the end of the string, add it
  if (currentGroup.length() > 0) {
    groups[groupCount++] = currentGroup;
  }

  // Find the group(s) with the smallest length
  int minLength = input.length();  // Start with a large number
  for (int i = 0; i < groupCount; i++) {
    int groupLength = groups[i].length();
    if (groupLength < minLength) {
      minLength = groupLength;  // Update minimum length
    }
  }

  // Output the groups with the smallest length
  Serial.println("Groups with smallest length:");
  for (int i = 0; i < groupCount; i++) {
    if (groups[i].length() == minLength) {
      Serial.println(groups[i]);  // Print the group
    }
  }
}

// Function to convert crypticMappings to a single string
static String convertCrypticMappingToString(String mysticMappings) {
  String result = "";  // Initialize an empty string to store the final output
  int startIndex = 0;

  while (startIndex < mysticMappings.length()) {
    int newlineIndex = mysticMappings.indexOf('\n', startIndex);  // Find the next newline
    if (newlineIndex == -1) break;

    String line = mysticMappings.substring(startIndex, newlineIndex);  // Extract each line
    result += line + " ";  // Add the line followed by a space (or any separator you prefer)

    startIndex = newlineIndex + 1;  // Move to the next line
  }

  // Remove any extra space at the end of the result string
  if (result.length() > 0 && result[result.length() - 1] == ' ') {
    result.remove(result.length() - 1);
  }

  return result;  // Return the final concatenated string
}



static String processInput(String input) {

  String processed[26]; // Tracks processed (letter-term) combinations

  String result = "";  // Initialize the result string
  int startIndex = 0;
  
  while (startIndex < input.length()) {
      // A map to store counts for each letter

    int arrowIndex = input.indexOf("->", startIndex);
    if (arrowIndex == -1) break; // No more mappings

    int letterIndex = arrowIndex - 2; // Position of the letter
    char letter = input.charAt(letterIndex); // Get the letter (L, R, etc.)

    // Ensure that the letter is a valid alphabet character (A-Z)
    if (letter >= 'A' && letter <= 'Z') {
      // Find the start and end of the term inside the quotes
      int quoteStartIndex = input.indexOf('\"', arrowIndex);
      int quoteEndIndex = input.indexOf('\"', quoteStartIndex + 1);  // Initialize quoteEndIndex here

      // Extract the term inside the quotes
      String term = input.substring(quoteStartIndex + 1, quoteEndIndex);

      // Create a unique string representing the letter-term combination
      String letterTerm = String(letter) + "-" + term;

      // Check if this (letter, term) combination has already been processed
      int letterIndex = letter - 'A'; // Convert 'A' to index 0, 'B' to index 1, etc.
      bool isProcessed = false;



      // Check if we've processed this letter-term combination
      for (int i = 0; i < processed[letterIndex].length(); i++) {
        if (processed[letterIndex].substring(i, i + letterTerm.length()) == letterTerm) {
          isProcessed = true;
          break;
        }
      }

      if (isProcessed) {
        // If the term has already been processed for this letter, skip
        startIndex = quoteEndIndex + 1;
        continue;
      }

      // Count the number of characters in the term
      int termLength = term.length();

      // Update the count for the corresponding letter
      letterCounts[letterIndex] += termLength;

      // Add this (letter, term) combination to the processed list
      processed[letterIndex] += letterTerm + ",";  // Append this combination

      // Append the result to the string
      result += String(letter) + "->" + term + " (Length: " + String(termLength) + ")\n";
    }

    // Move the start index forward to continue searching
    startIndex = arrowIndex + 2;  // Move past the "->"
  }

  return result;
}



static String calculateWordPoints(String words, String binomes) {
  // Remove any whitespace from the input strings
  words.replace(" ", "");
  binomes.replace(" ", "");

  // Split the binomes into an array of letter-number pairs
  String binomesArr[10]; // Adjust size according to the expected number of binomes
  int numBinomes = 0;
  int startIdx = 0;
  for (int i = 0; i < binomes.length(); i++) {
    if (binomes.charAt(i) == ',') {
      binomesArr[numBinomes++] = binomes.substring(startIdx, i);
      startIdx = i + 1;
    }
  }
  binomesArr[numBinomes++] = binomes.substring(startIdx); // Add the last binome
  
  // Create a map (array) to store points for each letter
  int letterPoints[26] = {0}; // For A-Z letters
  
  // Populate the letter points based on the binomes
  for (int i = 0; i < numBinomes; i++) {
    String binome = binomesArr[i];
    char letter = binome.charAt(0);  // Letter is the first character
    int points = binome.substring(1).toInt();  // Get the number after the letter
    letterPoints[letter - 'A'] = points;  // Store the points corresponding to the letter
  }

  // Split the words into an array
  String wordsArr[10]; // Adjust size according to the expected number of words
  int numWords = 0;
  startIdx = 0;
  for (int i = 0; i < words.length(); i++) {
    if (words.charAt(i) == '+') {
      wordsArr[numWords++] = words.substring(startIdx, i);
      startIdx = i + 1;
    }
  }
  wordsArr[numWords++] = words.substring(startIdx); // Add the last word
  
  // Variables to track the least points and the words with the least points
  int minPointValue = 9999; // Use a reasonably large number as initial value
  String wordsWithMinPoints[10]; // Array to store words with the least points
  int numMinWords = 0;

  // Process each word and calculate the points
  for (int i = 0; i < numWords; i++) {
    String word = wordsArr[i];
    int wordPoints = 0;
    
    // Calculate the total points for the word
    for (int j = 0; j < word.length(); j++) {
      char letter = word.charAt(j);
      if (letter >= 'A' && letter <= 'Z') {
        wordPoints += letterPoints[letter - 'A'];
      }
    }

    // Print the word and its total points
    Serial.print(word);
    Serial.print(": ");
    Serial.println(wordPoints);

    // Track the least points and the words with the least points
    if (wordPoints < minPointValue) {
      minPointValue = wordPoints;
      wordsWithMinPoints[0] = word; // Reset the array with the new least point word
      numMinWords = 1;
    } else if (wordPoints == minPointValue) {
      wordsWithMinPoints[numMinWords++] = word; // Add to the array if it has the same least points
    }
  }

  // Print the minimum points value
  Serial.print("Minimum points value: ");
  Serial.println(minPointValue);

  // If there are multiple words with the least points, select one randomly
  String selectedWord = wordsWithMinPoints[random(numMinWords)];

  // Return the word with the least points
  return selectedWord;
}

static String replaceLettersWithTerms(String inputWord, String description) {
  // Remove spaces from the description string
  description.replace(" ", "");
  
  // Create a map for letter -> term mapping
  String result = "";
  
  // Loop through each character in the inputWord
  for (int i = 0; i < inputWord.length(); i++) {
    char letter = inputWord.charAt(i);
    String term = extractTermForLetter(letter, description);
    
    if (i > 0) {
      result += "+";
    }
    result += term;
  }
  
  return result;
}

static String extractTermForLetter(char letter, String description) {
  // Find the position of the letter in the description string
  String pattern = String(letter) + "->\"";
  int startPos = description.indexOf(pattern);
  
  if (startPos == -1) {
    return ""; // If no match found, return an empty string
  }
  
  // Extract the term associated with the letter
  startPos += pattern.length();  // Move position after "letter->"
  int endPos = description.indexOf("\"", startPos);  // Find the end of the term
  
  String term = description.substring(startPos, endPos);
  return term;
}

// Function to multiply terms and apply simplifications
static String multiplyAndSimplify(String part1, String part2) {
  String terms[MAX_TERMS];
  int termCount = 0;

  // Split part1 into terms
  int i = 0;
  while (i < part1.length()) {
    int endFirst = part1.indexOf('+', i);
    if (endFirst == -1) endFirst = part1.length();
    String term1 = part1.substring(i, endFirst);

    // Split part2 into terms
    int j = 0;
    while (j < part2.length()) {
      int endSecond = part2.indexOf('+', j);
      if (endSecond == -1) endSecond = part2.length();
      String term2 = part2.substring(j, endSecond);

      // Combine terms and remove duplicates within each term
      String newTerm = removeDuplicateLetters(term1 + term2);

      // Add to list if not already present
      bool isDuplicate = false;
      for (int k = 0; k < termCount; k++) {
        if (terms[k] == newTerm) {
          isDuplicate = true;
          break;
        }
      }
      if (!isDuplicate && termCount < MAX_TERMS) {
        terms[termCount++] = newTerm;
      }

      j = endSecond + 1;
    }

    i = endFirst + 1;
  }

  // Apply redundancy elimination (retain one instance of each term, remove redundant bigger terms)
  String simplified = removeRedundantTerms(terms, termCount);

  return simplified;
}

// Function to remove duplicate letters within a term
static String removeDuplicateLetters(String term) {
  String result = "";
  for (int i = 0; i < term.length(); i++) {
    char c = term[i];
    if (result.indexOf(c) == -1) {
      result += c;
    }
  }
  return result;
}

// Function to remove redundant terms (retain one instance of each unique term)
static String removeRedundantTerms(String terms[], int termCount) {
  String result = "";

  for (int i = 0; i < termCount; i++) {
    bool isRedundant = false;

    for (int j = 0; j < termCount; j++) {
      if (i != j && isSubset(terms[j], terms[i])) {
        // If the current term (i) is a superset of another term (j), mark it redundant
        isRedundant = true;
        break;
      }
    }

    // Retain non-redundant terms
    if (!isRedundant) {
      result += terms[i] + "+";
    }
  }

  // Remove trailing '+' if present
  if (result.endsWith("+")) {
    result = result.substring(0, result.length() - 1);
  }

  return result;
}

// Function to check if term1 is a subset of term2
static bool isSubset(String term1, String term2) {
  for (int i = 0; i < term1.length(); i++) {
    if (term2.indexOf(term1[i]) == -1) {
      return false; // A letter in term1 is not in term2
    }
  }
  return true;
}

And this this the .h file

#ifndef QUINEMCCLUSKEYANDPETRICK_H
#define QUINEMCCLUSKEYANDPETRICK_H

#include <Arduino.h>

static const int MAX_TERMS = 20;

static int letterCounts[26]; 

String QuineMcCluskeyandPetrick(String input); // Main function

static String findValue(String searchStr);
static void clearArrays();
static String processBinaryInput(String binaryInput);
static String solve2x2(String input);
static String solve2x4(String input);
static String solve4x4(String input);
static String processValues(int values[], size_t size);
static void processValuesWithTracking(const int* values, size_t size, String groups[5][10], int decimalGroups[5][10], int groupSizes[5]);
static void printGroupsWithDecimalAndTracking(String groups[5][10], int decimalGroups[5][10], int groupSizes[5]);
static void createPairsAcrossGroups(String groups[5][10], int decimalGroups[5][10], int groupSizes[5]);
static void removeDuplicates(String group[10], int &size);
static void processTranslatedGroups(String groups[5][10], int groupSizes[5]);
static String sortTranslatedTerms(String groups[5][10], int groupSizes[5]);
static bool compareTerms(String term1, String term2);
static void getMinterms(String term, int minterms[], int &mintermCount);
static void processSortedTerms(String sortedTerms);
static void findCoveredMinterms(String sortedTerms, String &result, String (&implicantCoverage)[16], int (&mintermsCovered)[16][16], int &implicantCount);
static void formatMintermImplicants(String mintermImplicants[], String formattedImplicants[]);
static String addQuotesBetweenPlusAndParentheses(String input);
static void replaceTerms(String input, String &arcaneOutput, String &mysticMappings);
static void groupLetters10(String input);
static String processInput(String input);
static String calculateWordPoints(String words, String binomes);
static String replaceLettersWithTerms(String inputWord, String description);
static String extractTermForLetter(char letter, String description);
static String multiplyAndSimplify(String part1, String part2);
static String removeDuplicateLetters(String term);
static String removeRedundantTerms(String terms[], int termCount);
static bool isSubset(String term1, String term2);
static void findImplicantsForMinterms(String implicantCoverage[], int mintermsCovered[][16], int implicantCount, String mintermImplicants[]);
static String convertCrypticMappingToString(String mysticMappings);
static String combineFormattedImplicants(String formattedImplicants[]);
static String expandTo16Bit(String input);
static char generateRandomUniqueLetter(bool usedLetters[]);

#endif

And finally this is the test ino file, where the input is the S column of an alphabetic truth table, it can be a 2 3 or 4 variables truth table.

#include <QuineMcCluskeyandPetrick.h>

void setup() {
  Serial.begin(9600);
  
  String input = "0111111111111100"; // Example input
  String result = QuineMcCluskeyandPetrick(input);
  Serial.println(result);
}

void loop() {
  // Your loop code
}