HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Mimicking T9 cell messaging

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cellmimickingmessaging

Problem

Today I solved a question from Google Code Jam: mimicking a cell phone keypad messaging.

Here is the program, with goto statements. I know it is an unstructured style to use goto, but I still did because it improved speed.

```
#include

int main()
{
char c, c1 = NULL;
int top;

top:
while((c = getchar()) != '\n')
{
if (c == ' ')printf("0");

if(c == 'a' || c == 'b' || c == 'c')
{
if(c1 == 'a' || c1 == 'b' || c1 == 'c')
printf(" ");
if(c == 'a') printf("2");
if(c == 'b') printf("22");
if(c == 'c') printf("222");
c1 = c;
goto top;

}

if(c == 'd' || c == 'e' || c == 'f')
{
if(c1 == 'd' || c1 == 'e' || c1 == 'f')
printf(" ");
if(c == 'd') printf("3");
if(c == 'e') printf("33");
if(c == 'f') printf("333");
c1 = c;
goto top;

}

if(c == 'g' || c == 'h' || c == 'i')
{
if(c1 == 'g' || c1 == 'h' || c1 == 'i')
printf(" ");

if(c == 'g') printf("4");
if(c == 'h') printf("44");
if(c == 'i') printf("444");
c1 = c;
goto top;

}

if(c == 'j' || c == 'k' || c == 'l')
{
if(c1 == 'j' || c1 == 'k' || c1 == 'l')
printf(" ");

if(c == 'j') printf("5");
if(c == 'k') printf("55");
if(c == 'l') printf("555");
c1 = c;
goto top;

}

if(c == 'm' || c == 'n' || c == 'o')
{
if(c1 == 'm' || c1 == 'n' || c1 == 'o')
printf(" ");

if(c == 'm') printf("6");
if(c == 'n') printf("66");
if(c == 'o') printf("666");
c1 = c;
goto top;

}

if(c == 'p' || c == 'q' || c == 'r' || c == 's')
{
if(c1 == 'p' || c1 == 'q' || c1 == 'r' || c1 == 's')

Solution

Terminating when getchar() encounters \n is poor practice. If the program encounters EOF before Newline, then it will enter an infinite loop.

Considering that you only support lowercase, it would be nice if you folded the input to lowercase.

That is one long, uninspired while-loop, full of cut-and-paste code. I recommend a completely different approach. Defining a print_t9() function makes the code more meaningful and reusable.

#include 
#include 
#include 
#include 

/**
 * Determines the key and the number of repetitions of that key to type
 * character c in T9.  If c is a supported character, returns true.
 * If c is unsupported, returns false, and the contents of *key and *reps
 * are undefined.
 */
static _Bool t9_lookup(char c, int *key, int *reps) {
    static const char t9_table[][5] = {
                " ",            /*   0   */
        "",     "abc", "def",   /* 1 2 3 */
        "ghi",  "jkl", "mno",   /* 4 5 6 */
        "pqrs", "tuv", "wxyz"   /* 7 8 9 */
    };

    c = tolower(c);
    for (*key = 0; *key < sizeof(t9_table); (*key)++) {
        char *p;
        if ((p = strchr(t9_table[*key], c))) {
            if (reps) {
                *reps = p - t9_table[*key] + 1;
            }
            return true;
        }
    }
    return false;
}

/**
 * If c is one of the supported characters, prints the T9 representation and
 * returns true.  Otherwise, returns false.  If the T9 representation uses the
 * same key as the previous character, a space is printed as a separator.
 */
_Bool print_t9(FILE *output, char c, char prev_c) {
    int key, reps, prev_key;
    if (!t9_lookup(c, &key, &reps)) return false;

    if (t9_lookup(prev_c, &prev_key, NULL) && key == prev_key) {
        fprintf(output, " ");
    }
    while (reps--) {
        fprintf(output, "%d", key);
    }
    return true;
}

int main() {
    for (char prev_c = '\0', c; EOF != (c = getchar()); prev_c = c) {
        print_t9(stdout, c, prev_c) || putchar(c);
    }
    return 0;
}


You should probably support digits as well, to be typed with one additional keypress. All it would take to support that enhancement is a simple change:

static const char t9_table[][6] = {
                 " 0",
        "1",     "abc2", "def3",
        "ghi4",  "jkl5", "mno6",
        "pqrs7", "tuv8", "wxyz9"
    };

Code Snippets

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

/**
 * Determines the key and the number of repetitions of that key to type
 * character c in T9.  If c is a supported character, returns true.
 * If c is unsupported, returns false, and the contents of *key and *reps
 * are undefined.
 */
static _Bool t9_lookup(char c, int *key, int *reps) {
    static const char t9_table[][5] = {
                " ",            /*   0   */
        "",     "abc", "def",   /* 1 2 3 */
        "ghi",  "jkl", "mno",   /* 4 5 6 */
        "pqrs", "tuv", "wxyz"   /* 7 8 9 */
    };

    c = tolower(c);
    for (*key = 0; *key < sizeof(t9_table); (*key)++) {
        char *p;
        if ((p = strchr(t9_table[*key], c))) {
            if (reps) {
                *reps = p - t9_table[*key] + 1;
            }
            return true;
        }
    }
    return false;
}

/**
 * If c is one of the supported characters, prints the T9 representation and
 * returns true.  Otherwise, returns false.  If the T9 representation uses the
 * same key as the previous character, a space is printed as a separator.
 */
_Bool print_t9(FILE *output, char c, char prev_c) {
    int key, reps, prev_key;
    if (!t9_lookup(c, &key, &reps)) return false;

    if (t9_lookup(prev_c, &prev_key, NULL) && key == prev_key) {
        fprintf(output, " ");
    }
    while (reps--) {
        fprintf(output, "%d", key);
    }
    return true;
}

int main() {
    for (char prev_c = '\0', c; EOF != (c = getchar()); prev_c = c) {
        print_t9(stdout, c, prev_c) || putchar(c);
    }
    return 0;
}
static const char t9_table[][6] = {
                 " 0",
        "1",     "abc2", "def3",
        "ghi4",  "jkl5", "mno6",
        "pqrs7", "tuv8", "wxyz9"
    };

Context

StackExchange Code Review Q#20462, answer score: 2

Revisions (0)

No revisions yet.