[sci.electronics] VCR+: the first 1000 codes

shirriff@sprite.berkeley.edu (Ken Shirriff) (05/23/91)

I wrote the following C program to decode the first 1000 VCR+ codes.
I did this for the challenge of trying to unravel the code.
Let me know if you find any errors.
(Note: in Chicago, channel 3 seems to be channel 32 for some reason.)
Thanks to Andy Kinsman for his assistance.

Ken Shirriff			shirriff@sprite.Berkeley.EDU

-----------------------cut here------------------------------------

/*
 * Copyright 1991 Ken Shirriff   shirriff@sprite.Berkeley.EDU
 */

char *tn[8] = { "6:30", "4:00", "7:30", "4:30", "3:30", "5:30", "6:00", "2:30"};

main(argc,argv)
int argc;
char **argv;
{
    int num, month;
    int line, day;
    int time, chan;
    int shift;
    int wrap;
    int decnum;
    int num0;
    int table[32][32];

    if (argc != 3) {
	printf("Usage: decode num month\n");
	exit(-1);
    }
    num = atoi(argv[1]);
    num0 = num;
    month = atoi(argv[2]);
    decnum = decode100(num%100);

    if (num==103 || num==387 || num==474 || num==536 || num==658 ||
	    num==745 || num==929) {
	printf("number %d does not fall into the range of the others\n", num);
    } else if (num <= 100) {
	/*
	 * Swap 1-9 decoded with 1-9 encoded
	 */
	if (1<= num && num<=9) {
	    decnum = num;
	} else if (decnum<=9) {
	    decnum = decode100(decnum);
	}
	day = 1 + (decnum-1)/32;
	line = (decnum+day-1)%32;
    } else {
retry:
	/*
	 * We decode the last two digits.
	 * Then we shift according to the first digit.
	 * Each shift moves us 3 days over and 7 lines down.
	 * But since we are using the sheared table, the 3 days over
	 * results in moving 4 days down.
	 */
	shift = (11 + num/100 - shift100(decnum))%10;
	day = 1 + (decnum-1)/32; /* 1-4 */
	line = (decnum-1)%32;  /* 0-31 sheared table */
	line += shift*4; /* 0-31 + wrap */
	/*
	 * If we've moved down more than 32 lines, we have to wrap back.
	 */
	wrap = line/32;
	day += shift*3 + wrap;
	line += day; /* Undo the shear */
	decnum = ((line-day-1)%31)+(day-1)*32+1; /* sheared table number*/
	/*
	 * If we decode a number >100 into something in the first 100,
	 * we have to take the number there and start over.
	 * This ensures that numbers 1-100 map into codes 1-100.
	 */
	if (decnum<100) {
	    /*
	     * Get the appropriate entry from the first columns, and start over.
	     */
	    num = decode100(num%100);
	    decnum = decode100(num);
	    goto retry;
	}
    }

    /*
     * Apply the month correction.
     */
    line = (line+day*month)&31;

    /*
     * Decode the line into the time and channel.
     */
    time = ((line&16)>>2) | ((line&4)>>1) | (line&1);
    chan = (((line&8)>>2) | ((line&2)>>1))+1;
    printf("Code %d in month %d = %s, ch %d on day %d\n", num0, month,
	    tn[time], chan, day);
}

/*
 * Decode 0-99 into a sequential number 1-100:
 * 1
 * .. 33
 * ..    65
 * .. .. .. 97
 * .. .. .. ..
 * .. .. .. 100
 * 32     
 *    64
 *       96
 */
int
decode100(num)
{
    int day;
    int row, col, rem, div;

    /*
     * 4 special cases that make the modulo operations messy
     */
    switch (num) {
	case 87:
	    return 97;
	case 58:
	    return 98;
	case 29:
	    return 99;
	case 0:
	    return 100;
    }

    /*
     * Break up into 7 rows of 5 columns on 3 days.
     * The numbers are broken mod 29 and then broken in half again.
     */
    rem = num%29;
    div = num/29;
    if (rem<16-div) {
	row = 3-div;
    } else {
	row = 6-div;
	rem -= 13;
    }
    col = 4-(rem-1)/3;
    day = (rem-1)%3;

    /*
     * The numbers are then assigned consecutively down the columns.
     */
    return col*7+row + day*31;
}

/*
 * Compute the 100's digit shift.
 */
int
shift100(num)
{
    int shift;
    int i,j;

    i = (num+30)%31;
    j = (num+30)/31;

    shift = ((i+1)/10)*7 + j*4 + i*3;
    if ((i==8 || i==28) && (j==2 || j==3)) shift += 7;
    if (i==6 && j==4) shift += 8;
    if ((i==17 || i==18) && j==3) shift += 7;
    shift = shift%10;
    return shift;
}