Breakout, the game the course builds in HiSoft C, running on the Tatung Einstein: coloured brick rows, the bat and the ball on a black court
← Back to Courses
module
37

Appendix II - Worked Solutions

One solution to each exercise, compiled and run as every listing in the course was. Yours need not match; it needs to work. Where a solution's output depends on what was typed, the note says what was typed. Every program begins with #include STDIO.H and ends with #include ?STDIO.LIB? (after ?EIN.LIB? or ?CPM.LIB? where those are used), as in the sections.

S4

4.1

#include STDIO.H

main()
{
    printf("Gavin\n");
    printf("ZX81\n");
    printf("1982\n");
}

#include ?STDIO.LIB?
Gavin
ZX81
1982

4.2

#include STDIO.H

main()
{
    printf("Gavin, ZX81, 1982\n");
}

#include ?STDIO.LIB?
Gavin, ZX81, 1982

S7

7.1

No program: (a) printf("x") with no ; is reported at once, missing ';' at the line after; (b) printf("x" is reported at once, missing ')'; (c) prinf is reported at the end, ERROR - 27 - undefined symbol prinf; (d) two mains are reported at once, ERROR 21 ... duplicate declaration - storage class mismatch at the second.

7.2

#include STDIO.H

main()
{
    int a
    a = 1
    printf("%d\n", a);
}

#include ?STDIO.LIB?

The compiler reported only the first: ERROR 48 AT LINE 6 IN FILE E72.C / bad declaration. Fix it (E, edit, GRPH-K X) and the compile restarts and finds the second.

S8

8.1

#include STDIO.H

main()
{
    printf("%-12s%6d\n", "Tea", 120);
    printf("%-12s%6d\n", "Biscuits", 85);
    printf("%-12s%6d\n", "Newspaper", 1250);
}

#include ?STDIO.LIB?
Tea            120
Biscuits        85
Newspaper     1250

8.2

#include STDIO.H

main()
{
    printf("%4x%4o%4d\n", 1, 1, 1);
    printf("%4x%4o%4d\n", 2, 2, 2);
    printf("%4x%4o%4d\n", 3, 3, 3);
    printf("%4x%4o%4d\n", 4, 4, 4);
    printf("%4x%4o%4d\n", 5, 5, 5);
}

#include ?STDIO.LIB?
   1   1   1
   2   2   2
   3   3   3
   4   4   4
   5   5   5

8.3

#include STDIO.H

main()
{
    printf("%d%% of %dK is %dK\n", 50, 64, 32);
}

#include ?STDIO.LIB?
50% of 64K is 32K

S9

9.1

#include STDIO.H

main()
{
    printf("%d minutes in a day\n", 24 * 60);
    printf("%d seconds in a day\n", 24 * 60 * 60);
}

#include ?STDIO.LIB?

86400 does not fit an int: 86400 - 65536 = 20864.

1440 minutes in a day
20864 seconds in a day

9.2

#include STDIO.H

main()
{
    printf("%d\n", 65535);
    printf("%u\n", -1);
}

#include ?STDIO.LIB?
-1
65535

9.3

#include STDIO.H

main()
{
    printf("%d\n", 0100);
}

#include ?STDIO.LIB?

0100 is octal: 64.

64

S10

10.1

#include STDIO.H

main()
{
    int year, born, age;
    year = 2026;
    born = 1970;
    age = year - born;
    printf("born %d, age %d\n", born, age);
}

#include ?STDIO.LIB?
born 1970, age 56

10.2

#include STDIO.H

main()
{
    int a, b, keep;
    a = 3;
    b = 8;
    printf("before: %d %d\n", a, b);
    keep = a;
    a = b;
    b = keep;
    printf("after: %d %d\n", a, b);
}

#include ?STDIO.LIB?
before: 3 8
after: 8 3

10.3

#include STDIO.H

int lives = 3;

main()
{
    printf("%d\n", lives);
    lives = lives - 1;
    printf("%d\n", lives);
}

#include ?STDIO.LIB?
3
2

S11

11.1

#include STDIO.H

main()
{
    int temp;
    temp = 14;
    if (temp < 0)
        printf("freezing\n");
    else if (temp < 10)
        printf("cold\n");
    else if (temp < 20)
        printf("mild\n");
    else
        printf("hot\n");
}

#include ?STDIO.LIB?
mild

11.2

#include STDIO.H

main()
{
    int a, b, c, big;
    a = 4;
    b = 9;
    c = 6;
    big = a;
    if (b > big)
        big = b;
    if (c > big)
        big = c;
    printf("%d\n", big);
    big = a > b ? (a > c ? a : c) : (b > c ? b : c);
    printf("%d\n", big);
}

#include ?STDIO.LIB?
9
9

11.3

#include STDIO.H

main()
{
    int year;
    year = 1984;
    if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
        printf("%d is a leap year\n", year);
    else
        printf("%d is not\n", year);
}

#include ?STDIO.LIB?
1984 is a leap year

S12

12.1

#include STDIO.H

main()
{
    int i, j;
    for (i = 1; i <= 4; i++) {
        for (j = 1; j <= 4; j++)
            printf("%3d", i * j);
        printf("\n");
    }
}

#include ?STDIO.LIB?
  1  2  3  4
  2  4  6  8
  3  6  9 12
  4  8 12 16

12.2

#include STDIO.H

main()
{
    int p;
    p = 1;
    while (p > 0) {
        printf("%d ", p);
        p = p * 2;
    }
    printf("\n");
}

#include ?STDIO.LIB?

16384 doubled is 32768, which an int holds as -32768 (S9), and you would expect p > 0 to stop the loop there. On this compiler it did not: -32768 was printed as well, and the loop stopped only when the next doubling gave 0. A test that does not lean on the sign - while (p <= 16384) - stops at the last true power of two.

1 2 4 8 16 32 64 128 256 512 1024 2048 4
096 8192 16384 -32768

12.3

#include STDIO.H

main()
{
    int i, count;
    count = 0;
    for (i = 1; i <= 1000; i++)
        if (i % 7 == 0 && i % 5 != 0)
            count++;
    printf("%d\n", count);
}

#include ?STDIO.LIB?
114

S13

13.1

#include STDIO.H

cube(n) int n;
{
    return n * n * n;
}

main()
{
    int i;
    for (i = 1; i <= 5; i++)
        printf("%d cubed is %d\n", i, cube(i));
    for (i = 30; i <= 33; i++)
        printf("%d cubed is %d\n", i, cube(i));
}

#include ?STDIO.LIB?

32 cubed is 32768, which does not fit: it prints -32768, and 33 cubed is wrong too. 31 is the last correct cube.

1 cubed is 1
2 cubed is 8
3 cubed is 27
4 cubed is 64
5 cubed is 125
30 cubed is 27000
31 cubed is 29791
32 cubed is -32768
33 cubed is -29599

13.2

#include STDIO.H

smaller(a, b) int a, b;
{
    if (a < b)
        return a;
    return b;
}

smallest(a, b, c) int a, b, c;
{
    return smaller(smaller(a, b), c);
}

main()
{
    printf("%d %d %d\n", smallest(1, 2, 3), smallest(2, 3, 1), smallest(3, 1, 2));
    printf("%d %d %d\n", smallest(1, 3, 2), smallest(2, 1, 3), smallest(3, 2, 1));
}

#include ?STDIO.LIB?
1 1 1
1 1 1

13.3

#include STDIO.H

power(base, n) int base, n;
{
    if (n == 0)
        return 1;
    return base * power(base, n - 1);
}

main()
{
    int i;
    for (i = 1; i <= 11; i++)
        printf("3 to the %d is %d\n", i, power(3, i));
}

#include ?STDIO.LIB?

3 to the 10th is 59049, which does not fit an int: it comes out as -6487, and the 11th is wrong too.

3 to the 1 is 3
3 to the 2 is 9
3 to the 3 is 27
3 to the 4 is 81
3 to the 5 is 243
3 to the 6 is 729
3 to the 7 is 2187
3 to the 8 is 6561
3 to the 9 is 19683
3 to the 10 is -6487
3 to the 11 is -19461

S14

14.1

#include STDIO.H

main()
{
    char line[40];
    int a, b;
    printf("First number: ");
    gets(line);
    a = atoi(line);
    printf("Second number: ");
    gets(line);
    b = atoi(line);
    printf("sum %d, difference %d, product %d\n", a + b, a - b, a * b);
}

#include ?STDIO.LIB?

Typed 12 and 5.

First number: 12
Second number: 5
sum 17, difference 7, product 60

14.2

#include STDIO.H

main()
{
    char line[40];
    int c, n;
    printf("Type a line: ");
    n = 0;
    while ((c = getchar()) != '\n')
        line[n++] = c;
    while (n > 0)
        printf("%c", line[--n]);
    printf("\n");
}

#include ?STDIO.LIB?

Typed Einstein (with CAPS LOCK on).

Type a line: EINSTEIN
NIETSNIE

14.3

#include STDIO.H

main()
{
    int c;
    printf("Press any key\n");
    c = rawin();
    printf("%d, or %x in hex\n", c, c);
}

#include ?STDIO.LIB?

Pressed e with CAPS LOCK on: 69, E.

Press any key
69, or 45 in hex

S15

15.1

#include STDIO.H

main()
{
    int sq[10], i;
    for (i = 0; i < 10; i++)
        sq[i] = (i + 1) * (i + 1);
    for (i = 9; i >= 0; i--)
        printf("%d ", sq[i]);
    printf("\n");
}

#include ?STDIO.LIB?
100 81 64 49 36 25 16 9 4 1

15.2

#include STDIO.H

int marks[6] = { 40, 72, 15, 99, 63, 8 };

biggest(a, n) int a[], n;
{
    int i, best;
    best = a[0];
    for (i = 1; i < n; i++)
        if (a[i] > best)
            best = a[i];
    return best;
}

main()
{
    printf("%d\n", biggest(marks, 6));
    printf("%d\n", biggest(marks, 3));
}

#include ?STDIO.LIB?
99
72

15.3

#include STDIO.H

main()
{
    char row[41];
    int i;
    for (i = 0; i < 20; i++)
        row[i] = '#';
    row[20] = 0;
    printf("%s\n", row);
    row[10] = ' ';
    printf("%s\n", row);
}

#include ?STDIO.LIB?
####################
########## #########

S16

16.1

#include STDIO.H

both(a, b) int *a, *b;
{
    int sum;
    sum = *a + *b;
    *a = sum;
    *b = sum;
}

main()
{
    int x, y;
    x = 3;
    y = 4;
    both(&x, &y);
    printf("%d %d\n", x, y);
}

#include ?STDIO.LIB?
7 7

16.2

#include STDIO.H

count(s) char *s;
{
    int n;
    n = 0;
    while (*s++)
        n++;
    return n;
}

main()
{
    printf("%d %d\n", count("Einstein"), count(""));
}

#include ?STDIO.LIB?
8 0

16.3

#include STDIO.H

typedef char *char_ptr;

main()
{
    char *p;
    int i;
    p = cast(char_ptr) 0x7000;
    for (i = 0; i < 16; i++)
        p[i] = i;
    for (i = 0; i < 16; i++)
        printf("%d ", peek(0x7000 + i));
    printf("\n");
}

#include ?STDIO.LIB?
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

S17

17.1

#include STDIO.H

count(s, c) char *s, c;
{
    int n;
    n = 0;
    while (*s) {
        if (*s == c)
            n++;
        s++;
    }
    return n;
}

main()
{
    printf("%d %d %d\n", count("Einstein", 'n'), count("Einstein", 'z'), count("", 'a'));
}

#include ?STDIO.LIB?
2 0 0

17.2

#include STDIO.H

main()
{
    char line[40];
    int i;
    printf("Type a line: ");
    gets(line);
    for (i = 0; line[i]; i++)
        if (line[i] == ' ')
            line[i] = '_';
    printf("%s\n", line);
}

#include ?STDIO.LIB?

Typed the tatung einstein (CAPS LOCK on).

Type a line: THE TATUNG EINSTEIN
THE_TATUNG_EINSTEIN

17.3

#include STDIO.H

ends(s, c) char *s, c;
{
    int n;
    n = strlen(s);
    if (n == 0)
        return 0;
    return s[n - 1] == c;
}

main()
{
    printf("%d %d %d\n", ends("Einstein", 'n'), ends("Einstein", 'E'), ends("", 'n'));
}

#include ?STDIO.LIB?
1 0 0

S18

18.1

#include STDIO.H

typedef struct {
    int x, y;
} point;

taxi(a, b) point *a, *b;
{
    return abs(a->x - b->x) + abs(a->y - b->y);
}

main()
{
    point p, q;
    p.x = 1;
    p.y = 1;
    q.x = 4;
    q.y = 6;
    printf("%d %d\n", taxi(&p, &q), taxi(&q, &p));
}

#include ?STDIO.LIB?
8 8

18.2

#include STDIO.H

typedef struct {
    int x, y, dx, dy;
} ball;

ball balls[3];

main()
{
    int i, t;
    for (i = 0; i < 3; i++) {
        balls[i].x = 10 * i;
        balls[i].y = 0;
        balls[i].dx = 1;
        balls[i].dy = i + 1;
    }
    for (t = 0; t < 3; t++)
        for (i = 0; i < 3; i++) {
            balls[i].x += balls[i].dx;
            balls[i].y += balls[i].dy;
        }
    for (i = 0; i < 3; i++)
        printf("ball %d at (%d,%d)\n", i, balls[i].x, balls[i].y);
}

#include ?STDIO.LIB?
ball 0 at (3,3)
ball 1 at (13,6)
ball 2 at (23,9)

18.3

#include STDIO.H

typedef struct {
    char name[10];
    int score;
} player;

main()
{
    player best;
    strcpy(best.name, "Gavin");
    best.score = 1500;
    printf("%s has %d\n", best.name, best.score);
    printf("%d bytes\n", sizeof(player));
}

#include ?STDIO.LIB?
Gavin has 1500
12 bytes

S19

19.1

#include STDIO.H

#define ROWS 3
#define COLS 8

main()
{
    char grid[ROWS][COLS + 1];
    int r, c;
    for (r = 0; r < ROWS; r++) {
        for (c = 0; c < COLS; c++)
            grid[r][c] = '.';
        grid[r][COLS] = 0;
    }
    for (r = 0; r < ROWS; r++)
        printf("%s\n", grid[r]);
}

#include ?STDIO.LIB?
........
........
........

19.2

#include STDIO.H

square(x) int x;
{
    return x * x;
}

main()
{
    printf("%d\n", square(12));
}

#include ?STDIO.LIB?

#define SQUARE(x) x * x is refused: RESTRICTION: macros may not have parameters (S19). The function is the answer: 144.

19.3

#include STDIO.H
#include MY.H

main()
{
    printf("%s\n", GREETING);
}

#include ?STDIO.LIB?

With MY.H on the disc containing #define GREETING "Hello, Einstein".

S20

20.1

#include STDIO.H

main()
{
    FILE *f;
    char line[40];
    int i;
    f = fopen("NAMES.TXT", "w");
    for (i = 1; i <= 3; i++) {
        printf("Name %d: ", i);
        gets(line);
        fputs(line, f);
        fputs("\n", f);
    }
    fclose(f);
    f = fopen("NAMES.TXT", "r");
    i = 1;
    while (fgets(line, 40, f))
        printf("%d. %s", i++, line);
    fclose(f);
}

#include ?STDIO.LIB?

Typed Ada, Grace, Alan (CAPS LOCK on).

Name 1: ADA
Name 2: GRACE
Name 3: ALAN
1. ADA
2. GRACE
3. ALAN

20.2

#include STDIO.H

main()
{
    FILE *f;
    char line[40];
    int score;
    f = fopen("SCORE.TXT", "r");
    if (f == 0) {
        printf("no score file\n");
        return;
    }
    fgets(line, 40, f);
    fclose(f);
    score = atoi(line) + 10;
    f = fopen("SCORE.TXT", "w");
    fprintf(f, "%d\n", score);
    fclose(f);
    printf("score is now %d\n", score);
}

#include ?STDIO.LIB?

and E202A.C:

#include STDIO.H

main()
{
    FILE *f;
    f = fopen("SCORE.TXT", "w");
    fprintf(f, "%d\n", 100);
    fclose(f);
    printf("written\n");
}

#include ?STDIO.LIB?

E202A.C writes the file first (below). Three runs of E202B printed score is now 110, 120, 130.

score is now 110

20.3

#include STDIO.H

main()
{
    FILE *f;
    int c, lines;
    f = fopen("STDIO.H", "r");
    lines = 0;
    while ((c = getc(f)) != EOF)
        if (c == 10)
            lines++;
    fclose(f);
    printf("%d lines\n", lines);
}

#include ?STDIO.LIB?
134 lines

S21

21.1

#include STDIO.H

typedef int *int_ptr;

main()
{
    int *p, i, sum;
    p = cast(int_ptr) malloc(10 * sizeof(int));
    for (i = 0; i < 10; i++)
        p[i] = i + 1;
    sum = 0;
    for (i = 0; i < 10; i++)
        sum += p[i];
    printf("%d\n", sum);
    free(p);
}

#include ?STDIO.LIB?
55

21.2

#include STDIO.H

main()
{
    int n;
    n = 0;
    while (malloc(1000) != 0)
        n++;
    printf("%d blocks of 1000\n", n);
}

#include ?STDIO.LIB?

heap full is printed by malloc itself on the call that fails.

heap full
52 blocks of 1000

21.3

#include STDIO.H

deeper(n) int n;
{
    char pad[100];
    if (n % 50 == 0)
        printf("%d ", n);
    deeper(n + 1);
}

main()
{
    deeper(1);
}

#include ?STDIO.LIB?

It printed 50 100 150 ... 500 and then stack overflow, and the prompt came back.

S22

22.1

#include STDIO.H

main()
{
    int c;
    char line[40];
    printf("Arrows; Q to stop\n");
    for (;;) {
        while ((c = kbd()) == 0)
            ;
        if (c == '[')
            printf("left\n");
        if (c == ']')
            printf("right\n");
        if (c == 'Q')
            break;
        while (kbd() != 0)
            ;
    }
    printf("Press ENTER to finish\n");
    gets(line);
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

LEFT, RIGHT, then Q.

22.2

#include STDIO.H

main()
{
    int n;
    char line[40];
    printf("Hold SPACE\n");
    while (kbd() != ' ')
        ;
    n = 0;
    while (kbd() == ' ')
        n++;
    printf("%d times round\n", n);
    printf("Press ENTER to finish\n");
    gets(line);
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

SPACE held for about a second: 227 passes.

22.3

#include STDIO.H

waitkey()
{
    int c;
    while ((c = kbd()) == 0)
        ;
    while (kbd() != 0)
        ;
    return c;
}

main()
{
    char line[40];
    cls40();
    curat(10, 5);
    printf("X");
    curat(0, 22);
    waitkey();
    curat(0, 15);
    printf("again");
    waitkey();
    cls40();
    printf("Press ENTER to finish\n");
    gets(line);
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

The screen appeared as in S24 and each key moved it on; the prompt was clean, but the listing keeps the gets because kbd() was used.

S23

23.1

#include STDIO.H

void clear()
{
    rawout(14);
}

void at(h, v)
{
    poke(0xfb4a, h);
    poke(0xfb4b, v);
}

main()
{
    clear();
    at(10, 5);
    printf("here");
    at(0, 22);
    rawin();
    clear();
}

#include ?STDIO.LIB?

It compiles with ?STDIO.LIB? alone: rawout is built in and poke is in the standard library. here appears at column 10, row 5.

23.2

#include STDIO.H

void home()
{
    poke(0xfb4a, 0);
    poke(0xfb4b, 0);
}

main()
{
    cls40();
    curat(5, 5);
    printf("middle");
    home();
    printf("top");
    curat(0, 22);
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

top at the top left over middle at (5,5).

23.3

#include STDIO.H

dpeek(addr) unsigned addr;
{
    return peek(addr) + 256 * peek(addr + 1);
}

main()
{
    doke(0x7000, 1234);
    printf("%d %d %d\n", peek(0x7000), peek(0x7001), dpeek(0x7000));
    doke(0x7000, -1);
    printf("%u\n", dpeek(0x7000));
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

doke writes the low byte first: 210 then 4 for 1234; dpeek reads them back; -1 reads back as 65535.

210 4 1234
65535

S24

24.1

#include STDIO.H

main()
{
    int i;
    cls40();
    for (i = 0; i < 40; i++) {
        curat(i, 0);
        putchar('#');
        curat(i, 20);
        putchar('#');
    }
    for (i = 1; i < 20; i++) {
        curat(0, i);
        putchar('#');
        curat(39, i);
        putchar('#');
    }
    curat(0, 22);
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

A box of # round the top twenty-one rows.

24.2

#include STDIO.H

main()
{
    int i;
    cls40();
    for (i = 0; i < 10; i++) {
        curat(38, i);
        printf("%2d", i);
    }
    curat(0, 22);
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

0 to 9 in the last two columns of rows 0-9.

24.3

#include STDIO.H

main()
{
    int score, i, j;
    cls40();
    curat(31, 0);
    printf("Score: 0");
    for (score = 1; score <= 20; score++) {
        for (j = 0; j < 3000; j++)
            ;
        curat(38, 0);
        printf("%d", score);
    }
    curat(0, 22);
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

Score: 0 at the top right, counting up to 20 in place.

S25

25.1

#include STDIO.H

main()
{
    int i;
    cls40();
    shapedef(201, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
    curat(10, 5);
    for (i = 0; i < 20; i++)
        putchar(201);
    curat(0, 22);
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

Twenty bricks in a row on row 5, each with a one-pixel gap at the right and the bottom.

25.2

#include STDIO.H

main()
{
    int c;
    cls40();
    for (c = 1; c <= 15; c++) {
        curat(0, 10);
        printf("colour %d ", c);
        bcol(c);
        rawin();
    }
    bcol(4);
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

The backdrop changes at each key through the fifteen colours and ends dark blue.

25.3

#include STDIO.H

void spriteshape(s, n)
{
    s <<= 2;
    s += 0x3b02;
    vpoke(s, n);
}

main()
{
    int x;
    cls40();
    mag(0);
    spriteshape(0, 'O');
    spritecol(0, 0x0F);
    for (x = 0; x <= 240; x += 4) {
        spritepos(0, x, 90);
        while ((inp(9) & 0x80) == 0)
            ;
    }
    curat(0, 22);
    printf("done");
    rawin();
    cls40();
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

The sprite crosses the screen in about a second and done appears.

S26

26.1

#include STDIO.H

main()
{
    int i;
    cls40();
    curat(0, 5);
    printf("put-start\n");
    for (i = 0; i < 1000; i++) {
        putchar('*');
        if (i % 40 == 39)
            putchar(13);
    }
    printf("\nput-end\n");
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

About 3.7 seconds for the thousand, printed on one row and overwritten - the same four milliseconds a character as with curat.

26.2

#include STDIO.H

void wait_frames(n) int n;
{
    while (n-- > 0)
        while ((inp(9) & 0x80) == 0)
            ;
}

main()
{
    int i;
    printf("count-start\n");
    for (i = 1; i <= 10; i++) {
        printf("%d ", i);
        wait_frames(50);
    }
    printf("\ncount-end\n");
}

#include ?EIN.LIB?
#include ?STDIO.LIB?

1 to 10 appear one a second, then count-end.

26.3

TICK.C is Code 1200 149A (666 bytes), KEYS.C 1465 (613), SCREEN.C 1429 (553). The gets in KEYS.C and the frame loop in TICK.C cost most: gets brings its library function in.

S27

27.1

Starting from BREAK1.C, the changes (- lines out, + lines in, @@ marks where):

@@ -7,4 +7,5 @@
 #define WALL '#'
 #define BATCHAR '='
+#define BOTTOMROW 22

 typedef struct {
@@ -30,4 +31,14 @@
 }

+void draw_message(s) char *s;
+{
+    int i;
+    curat(0, BOTTOMROW);
+    for (i = 0; i < 40; i++)
+        putchar(' ');
+    curat(0, BOTTOMROW);
+    printf("%s", s);
+}
+
 void draw_bat(b) bat *b;
 {
@@ -45,11 +56,11 @@
     draw_court();
     draw_bat(&paddle);
-    curat(0, 22);
+    draw_message("Any key");
     curoff();
     rawin();
     curon();
+    draw_message("Press ENTER to finish");
+    gets(line);
     cls40();
-    printf("Press ENTER to finish\n");
-    gets(line);
 }

Any key on the bottom row, then Press ENTER to finish in its place.

27.2

Starting from BREAK1.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,5 +5,6 @@
 #define TOPWALL 0
 #define BATROW 21
-#define WALL '#'
+#define TOPCHAR '-'
+#define SIDECHAR '|'
 #define BATCHAR '='

@@ -20,11 +21,11 @@
     for (i = LEFTWALL; i <= RIGHTWALL; i++) {
         curat(i, TOPWALL);
-        putchar(WALL);
+        putchar(TOPCHAR);
     }
     for (i = TOPWALL + 1; i <= BATROW; i++) {
         curat(LEFTWALL, i);
-        putchar(WALL);
+        putchar(SIDECHAR);
         curat(RIGHTWALL, i);
-        putchar(WALL);
+        putchar(SIDECHAR);
     }
 }

- along the top, | down the sides - which the Einstein draws as a double bar.

27.3

Starting from BREAK1.C, the changes (- lines out, + lines in, @@ marks where):

@@ -18,4 +18,5 @@
     int i;
     cls40();
+    tcol(0x51);
     for (i = LEFTWALL; i <= RIGHTWALL; i++) {
         curat(i, TOPWALL);
@@ -33,4 +34,5 @@
 {
     int i;
+    tcol(0xB1);
     curat(b->left, BATROW);
     for (i = 0; i < b->width; i++)
@@ -45,4 +47,5 @@
     draw_court();
     draw_bat(&paddle);
+    tcol(0xF4);
     curat(0, 22);
     curoff();

Cyan walls on black, yellow bat, white message.

S28

28.1

Starting from BREAK2.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -54,7 +52,7 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
-    if (p->y <= TOPWALL + 1)
+    if (p->y <= TOPWALL + 1 || p->y >= BATROW)
         p->dy = -p->dy;
 }
@@ -89,5 +87,5 @@
     draw_bat(&paddle);
     curoff();
-    while (b.y < BATROW) {
+    while (kbd() != 'Q') {
         move_ball(&b);
         draw_ball(&b);
@@ -96,5 +94,5 @@
     curon();
     curat(0, 22);
-    printf("Lost. Press ENTER");
+    printf("Stopped. Press ENTER");
     gets(line);
     cls40();

The ball bounces off row 21 as off the top and never stops; Q ends it with Stopped. Press ENTER.

28.2

Starting from BREAK2.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -54,8 +52,11 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
-    if (p->y <= TOPWALL + 1)
+    if (p->y <= TOPWALL + 1) {
         p->dy = -p->dy;
+        if (p->dx == 0)
+            p->dx = 1;
+    }
 }

@@ -82,5 +83,5 @@
     b.x = 20;
     b.y = 12;
-    b.dx = 1;
+    b.dx = 0;
     b.dy = -1;
     b.oldx = b.x;

Straight up the middle, off the top, and then diagonally: the first bounce gives it dx = 1.

28.3

Starting from BREAK2.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -23,4 +21,5 @@
 bat paddle;
 ball b;
+int ticks;

 void draw_court()
@@ -54,5 +53,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -93,8 +92,9 @@
         draw_ball(&b);
         wait_frames(TICK);
+        ticks++;
     }
     curon();
     curat(0, 22);
-    printf("Lost. Press ENTER");
+    printf("Lost after %d ticks. Press ENTER", ticks);
     gets(line);
     cls40();

Lost after 31 ticks. Press ENTER for the ball starting at (20, 12).

S29

29.1

Starting from BREAK3.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -52,5 +50,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -58,5 +56,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -73,5 +71,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -83,4 +81,8 @@
         if (hit == 0)
             p->dx = -1;
+        if (hit == 1)
+            p->dx = -1;
+        if (hit == q->width - 2)
+            p->dx = 1;
         if (hit == q->width - 1)
             p->dx = 1;
@@ -107,5 +109,5 @@
     char line[40];
     int c;
-    paddle.width = 5;
+    paddle.width = 7;
     paddle.left = 18;
     b.x = 20;
@@ -118,5 +120,5 @@
     draw_bat(&paddle);
     curoff();
-    for (;;) {
+    while (b.y <= BATROW) {
         c = kbd();
         if (c == LEFTKEY)
@@ -125,11 +127,7 @@
             move_bat(&paddle, 1);
         move_ball(&b, &paddle);
-        if (b.y >= BATROW)
-            break;
         draw_ball(&b);
         wait_frames(TICK);
     }
-    curat(b.oldx, b.oldy);
-    putchar(' ');
     curon();
     curat(0, 22);

A seven-wide bat; the two end columns send the ball outward, the next two the same, the middle three leave dx alone.

29.2

Starting from BREAK3.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -13,4 +11,5 @@
 #define LEFTKEY '['
 #define RIGHTKEY ']'
+#define BATSPEED 2

 typedef struct {
@@ -52,14 +51,17 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
-        p->left--;
+    int i;
+    if (dir < 0 && p->left - BATSPEED > LEFTWALL) {
+        p->left -= BATSPEED;
         curat(p->left + p->width, BATROW);
-        putchar(' ');
+        for (i = 0; i < BATSPEED; i++)
+            putchar(' ');
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width + BATSPEED <= RIGHTWALL) {
         curat(p->left, BATROW);
-        putchar(' ');
-        p->left++;
+        for (i = 0; i < BATSPEED; i++)
+            putchar(' ');
+        p->left += BATSPEED;
         draw_bat(p);
     }
@@ -73,5 +75,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -118,5 +120,5 @@
     draw_bat(&paddle);
     curoff();
-    for (;;) {
+    while (b.y <= BATROW) {
         c = kbd();
         if (c == LEFTKEY)
@@ -125,11 +127,7 @@
             move_bat(&paddle, 1);
         move_ball(&b, &paddle);
-        if (b.y >= BATROW)
-            break;
         draw_ball(&b);
         wait_frames(TICK);
     }
-    curat(b.oldx, b.oldy);
-    putchar(' ');
     curon();
     curat(0, 22);

With BATSPEED 2 the bat moves two columns a tick and rubs two out; no smear.

29.3

Starting from BREAK3.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -52,5 +50,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -58,5 +56,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -73,5 +71,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -118,5 +116,5 @@
     draw_bat(&paddle);
     curoff();
-    for (;;) {
+    while (b.y <= BATROW) {
         c = kbd();
         if (c == LEFTKEY)
@@ -124,15 +122,16 @@
         if (c == RIGHTKEY)
             move_bat(&paddle, 1);
+        if (c == 'Q')
+            break;
         move_ball(&b, &paddle);
-        if (b.y >= BATROW)
-            break;
         draw_ball(&b);
         wait_frames(TICK);
     }
-    curat(b.oldx, b.oldy);
-    putchar(' ');
     curon();
     curat(0, 22);
-    printf("Lost. Press ENTER");
+    if (b.y >= BATROW)
+        printf("Lost. Press ENTER");
+    else
+        printf("Quit. Press ENTER");
     gets(line);
     cls40();

Q gives Quit. Press ENTER.

S30

30.1

Starting from BREAK4.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
@@ -50,6 +48,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -60,5 +58,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -77,5 +75,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -83,9 +81,9 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
     p->dy = -p->dy;
-    score += 10;
+    score += 10 * (BRICKROWS - r);
     remaining--;
     draw_score();
@@ -102,5 +100,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -108,5 +106,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -123,5 +121,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)

The bottom row scores 10, the top 40.

30.2

Starting from BREAK4.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,12 +5,11 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
 #define BALLCHAR 200
 #define BRICKCHAR 201
+#define HARDCHAR 202
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
@@ -50,6 +49,7 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
+    shapedef(HARDCHAR, 0xfe, 0xaa, 0xd6, 0xaa, 0xd6, 0xaa, 0xfe, 0x00);
 }

@@ -59,8 +59,13 @@
     for (r = 0; r < BRICKROWS; r++)
         for (c = 0; c < BRICKCOLS; c++) {
-            bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
-            putchar(BRICKCHAR);
-            putchar(BRICKCHAR);
+            bricks[r][c] = (r == 0) ? 2 : 1;
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
+            if (r == 0) {
+                putchar(HARDCHAR);
+                putchar(HARDCHAR);
+            } else {
+                putchar(BRICKCHAR);
+                putchar(BRICKCHAR);
+            }
         }
     remaining = BRICKROWS * BRICKCOLS;
@@ -77,11 +82,17 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
     if (bricks[r][c] == 0)
         return;
-    bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    bricks[r][c]--;
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
+    if (bricks[r][c] == 1) {
+        putchar(BRICKCHAR);
+        putchar(BRICKCHAR);
+        p->dy = -p->dy;
+        return;
+    }
     putchar(' ');
     putchar(' ');
@@ -102,5 +113,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -108,5 +119,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -123,5 +134,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)

The top row is drawn with character 202 and takes two hits, turning into an ordinary brick on the first.

30.3

Starting from BREAK4.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
@@ -50,6 +48,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -60,5 +58,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -70,5 +68,5 @@
 {
     curat(0, 22);
-    printf("Score: %d", score);
+    printf("Score: %d  Bricks: %d ", score, remaining);
 }

@@ -77,5 +75,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -83,5 +81,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -102,5 +100,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -108,5 +106,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -123,5 +121,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)

Score: 0 Bricks: 76, counting down.

S31

31.1

Starting from BREAK5.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
@@ -52,6 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +60,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -71,6 +69,11 @@
 void draw_score()
 {
+    int i;
     curat(0, 22);
-    printf("Score: %4d  Lives: %d           ", score, lives);
+    printf("Score: %4d  Lives: ", score);
+    for (i = 0; i < lives; i++)
+        putchar(BALLCHAR);
+    for (i = lives; i < 12; i++)
+        putchar(' ');
 }

@@ -108,5 +111,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +117,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -133,5 +136,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -139,5 +142,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -154,5 +157,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)

Lives: followed by three ball characters, then two, then one.

31.2

Starting from BREAK5.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
@@ -52,6 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +60,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -96,9 +94,23 @@
 }

-void wait_launch()
-{
+void wait_launch(p, q) ball *p; bat *q;
+{
+    int c;
     message("SPACE to launch");
-    while (kbd() != LAUNCHKEY)
-        ;
+    for (;;) {
+        c = kbd();
+        if (c == LAUNCHKEY)
+            break;
+        if (c == LEFTKEY || c == RIGHTKEY) {
+            curat(p->x, p->y);
+            putchar(' ');
+            move_bat(q, c == LEFTKEY ? -1 : 1);
+            p->x = q->left + q->width / 2;
+            p->oldx = p->x;
+            curat(p->x, p->y);
+            putchar(BALLCHAR);
+            wait_frames(TICK);
+        }
+    }
     draw_score();
 }
@@ -108,5 +120,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +126,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -133,5 +145,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -139,5 +151,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -154,5 +166,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -200,5 +212,5 @@
     while (lives > 0 && remaining > 0) {
         place_ball(&b, &paddle);
-        wait_launch();
+        wait_launch(&b, &paddle);
         while (remaining > 0) {
             c = kbd();

LEFT and RIGHT move the bat while SPACE to launch shows, and the ball rides on it.

31.3

Starting from BREAK5.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,9 +10,10 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define TICK 3
 #define LIVES 3
 #define LAUNCHKEY ' '
+#define BONUS 100
 #define LEFTKEY '['
 #define RIGHTKEY ']'
@@ -32,5 +31,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives;
+int score, remaining, lives, bonus_given;

 void draw_court()
@@ -52,6 +51,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +61,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -108,5 +107,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +113,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -120,4 +119,8 @@
     score += 10;
     remaining--;
+    if (score >= BONUS && bonus_given == 0) {
+        bonus_given = 1;
+        lives++;
+    }
     draw_score();
 }
@@ -133,5 +136,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -139,5 +142,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -154,5 +157,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)

With BONUS 100 for the test, a fourth ball was granted once the score passed 100.

S32

32.1

Starting from BREAK6.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
@@ -33,4 +31,5 @@
 char bricks[BRICKROWS][BRICKCOLS];
 int score, remaining, lives, level, tick;
+int rowtick[BRICKROWS];

 void draw_court()
@@ -52,6 +51,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +61,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -108,5 +107,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +113,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -121,6 +120,5 @@
     remaining--;
     draw_score();
-    if (remaining == BRICKROWS * BRICKCOLS / 2 && tick > 1)
-        tick--;
+    tick = rowtick[r];
 }

@@ -135,5 +133,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -141,5 +139,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -156,5 +154,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -196,4 +194,8 @@
     level = 1;
     tick = STARTTICK;
+    rowtick[0] = 1;
+    rowtick[1] = 2;
+    rowtick[2] = 3;
+    rowtick[3] = 4;
     define_shapes();
     draw_court();

rowtick[] holds a tick per brick row; a hit on the top row sets the tick to 1.

32.2

Starting from BREAK6.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
@@ -52,6 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +60,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -108,5 +106,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +112,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -135,5 +133,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -141,5 +139,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -156,5 +154,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -209,4 +207,6 @@
                 tick = 1;
             draw_bricks();
+            message("Level up!");
+            wait_frames(50);
             draw_score();
         }

Level up! on the status row for a second before the next ball, once a wall is cleared.

32.3

Starting from BREAK6.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,6 +5,4 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
 #define WALL '#'
 #define BATCHAR '='
@@ -12,5 +10,5 @@
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
@@ -52,6 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -62,5 +60,5 @@
         for (c = 0; c < BRICKCOLS; c++) {
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -108,5 +106,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -114,5 +112,5 @@
         return;
     bricks[r][c] = 0;
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -135,5 +133,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -141,5 +139,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -156,5 +154,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -204,4 +202,7 @@
     while (lives > 0) {
         if (remaining == 0) {
+            score += 100 * level;
+            message("Wall cleared: bonus!");
+            wait_frames(50);
             level++;
             tick = STARTTICK - level + 1;

Wall cleared: bonus! and 100 * level added, once a wall is cleared. (Clearing a wall takes a player; the code path is draw_bricks, as at the start.)

S33

33.1

Starting from BREAK7.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,23 +5,14 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
-#define WALL 202
+#define WALL '#'
 #define BATCHAR '='
 #define BALLCHAR 200
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
 #define LIVES 3
 #define LAUNCHKEY ' '
-#define WALLCOL 0x51
-#define BATCOL 0xF1
-#define BALLCOL 0xF1
-#define TEXTCOL 0xE1
-#define TITLECOL 0xB1
-#define BACKDROP 1
-#define DEFAULTBACKDROP 4
 #define LEFTKEY '['
 #define RIGHTKEY ']'
@@ -39,6 +30,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives, level, tick, oldcol;
-int brickcol[BRICKROWS] = { 0x91, 0xB1, 0x31, 0x71 };
+int score, remaining, lives, level, tick, high;

 void draw_court()
@@ -46,5 +36,4 @@
     int i;
     cls40();
-    tcol(WALLCOL);
     for (i = LEFTWALL; i <= RIGHTWALL; i++) {
         curat(i, TOPWALL);
@@ -61,7 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
-    shapedef(WALL, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -71,7 +59,6 @@
     for (r = 0; r < BRICKROWS; r++)
         for (c = 0; c < BRICKCOLS; c++) {
-            tcol(brickcol[r]);
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -82,5 +69,4 @@
 void draw_score()
 {
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("Score: %4d  Lives: %d  Level: %d ", score, lives, level);
@@ -90,5 +76,4 @@
 {
     int i;
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("%s", s);
@@ -105,5 +90,4 @@
     p->dx = 1;
     p->dy = -1;
-    tcol(BALLCOL);
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -113,8 +97,6 @@
 {
     cls40();
-    tcol(TITLECOL);
     curat(12, 6);
     printf("B R E A K O U T");
-    tcol(TEXTCOL);
     curat(8, 10);
     printf("[ and ] move the bat");
@@ -123,5 +105,7 @@
     curat(8, 14);
     printf("%d lives; clear the bricks", LIVES);
-    curat(8, 17);
+    curat(8, 16);
+    printf("High score: %d", high);
+    curat(8, 18);
     printf("Press any key to play");
     curat(0, 22);
@@ -141,5 +125,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -148,6 +132,5 @@
     bricks[r][c] = 0;
     beep();
-    tcol(brickcol[r]);
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -163,5 +146,4 @@
 {
     int i;
-    tcol(BATCOL);
     curat(p->left, BATROW);
     for (i = 0; i < p->width; i++)
@@ -171,5 +153,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -177,5 +159,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -192,5 +174,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -207,17 +189,8 @@
 }

-row_colour(y) int y;
-{
-    if (y >= FIRSTBRICKROW && y < FIRSTBRICKROW + BRICKROWS)
-        return brickcol[y - FIRSTBRICKROW];
-    return BALLCOL;
-}
-
 void draw_ball(p) ball *p;
 {
-    tcol(row_colour(p->oldy));
     curat(p->oldx, p->oldy);
     putchar(' ');
-    tcol(row_colour(p->y));
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -285,9 +258,9 @@
     int c;
     define_shapes();
-    oldcol = peek(0xfb38);
-    bcol(BACKDROP);
     for (;;) {
         title();
         play();
+        if (score > high)
+            high = score;
         message("Game over.  Again? (Y/N)");
         c = rawin();
@@ -295,6 +268,4 @@
             break;
     }
-    tcol(oldcol);
-    bcol(DEFAULTBACKDROP);
     cls40();
     printf("Press ENTER to finish\n");

High score: 0 on the title, and High score: 130 on the title after a game that scored 130.

33.2

Starting from BREAK7.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,23 +5,14 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
-#define WALL 202
+#define WALL '#'
 #define BATCHAR '='
 #define BALLCHAR 200
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
 #define LIVES 3
 #define LAUNCHKEY ' '
-#define WALLCOL 0x51
-#define BATCOL 0xF1
-#define BALLCOL 0xF1
-#define TEXTCOL 0xE1
-#define TITLECOL 0xB1
-#define BACKDROP 1
-#define DEFAULTBACKDROP 4
 #define LEFTKEY '['
 #define RIGHTKEY ']'
@@ -39,6 +30,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives, level, tick, oldcol;
-int brickcol[BRICKROWS] = { 0x91, 0xB1, 0x31, 0x71 };
+int score, remaining, lives, level, tick, high;

 void draw_court()
@@ -46,5 +36,4 @@
     int i;
     cls40();
-    tcol(WALLCOL);
     for (i = LEFTWALL; i <= RIGHTWALL; i++) {
         curat(i, TOPWALL);
@@ -61,7 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
-    shapedef(WALL, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -71,7 +59,6 @@
     for (r = 0; r < BRICKROWS; r++)
         for (c = 0; c < BRICKCOLS; c++) {
-            tcol(brickcol[r]);
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -82,5 +69,4 @@
 void draw_score()
 {
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("Score: %4d  Lives: %d  Level: %d ", score, lives, level);
@@ -90,5 +76,4 @@
 {
     int i;
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("%s", s);
@@ -105,5 +90,4 @@
     p->dx = 1;
     p->dy = -1;
-    tcol(BALLCOL);
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -113,8 +97,6 @@
 {
     cls40();
-    tcol(TITLECOL);
     curat(12, 6);
     printf("B R E A K O U T");
-    tcol(TEXTCOL);
     curat(8, 10);
     printf("[ and ] move the bat");
@@ -123,5 +105,7 @@
     curat(8, 14);
     printf("%d lives; clear the bricks", LIVES);
-    curat(8, 17);
+    curat(8, 16);
+    printf("High score: %d", high);
+    curat(8, 18);
     printf("Press any key to play");
     curat(0, 22);
@@ -141,5 +125,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -148,6 +132,5 @@
     bricks[r][c] = 0;
     beep();
-    tcol(brickcol[r]);
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -163,5 +146,4 @@
 {
     int i;
-    tcol(BATCOL);
     curat(p->left, BATROW);
     for (i = 0; i < p->width; i++)
@@ -171,5 +153,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -177,5 +159,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -192,5 +174,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -207,17 +189,8 @@
 }

-row_colour(y) int y;
-{
-    if (y >= FIRSTBRICKROW && y < FIRSTBRICKROW + BRICKROWS)
-        return brickcol[y - FIRSTBRICKROW];
-    return BALLCOL;
-}
-
 void draw_ball(p) ball *p;
 {
-    tcol(row_colour(p->oldy));
     curat(p->oldx, p->oldy);
     putchar(' ');
-    tcol(row_colour(p->y));
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -280,4 +253,27 @@
 }

+void load_high()
+{
+    FILE *f;
+    char line[40];
+    high = 0;
+    f = fopen("BREAKOUT.HI", "r");
+    if (f == 0)
+        return;
+    fgets(line, 40, f);
+    fclose(f);
+    high = atoi(line);
+}
+
+void save_high()
+{
+    FILE *f;
+    f = fopen("BREAKOUT.HI", "w");
+    if (f == 0)
+        return;
+    fprintf(f, "%d\n", high);
+    fclose(f);
+}
+
 main()
 {
@@ -285,9 +281,12 @@
     int c;
     define_shapes();
-    oldcol = peek(0xfb38);
-    bcol(BACKDROP);
+    load_high();
     for (;;) {
         title();
         play();
+        if (score > high) {
+            high = score;
+            save_high();
+        }
         message("Game over.  Again? (Y/N)");
         c = rawin();
@@ -295,6 +294,4 @@
             break;
     }
-    tcol(oldcol);
-    bcol(DEFAULTBACKDROP);
     cls40();
     printf("Press ENTER to finish\n");

After the game, DISP BREAKOUT.HI shows 130, and the next start shows it on the title.

33.3

Starting from BREAK7.C, the changes (- lines out, + lines in, @@ marks where):

@@ -5,23 +5,14 @@
 #define TOPWALL 0
 #define BATROW 21
-#define PLAYLEFT 2
-#define PLAYRIGHT 37
-#define WALL 202
+#define WALL '#'
 #define BATCHAR '='
 #define BALLCHAR 200
 #define BRICKCHAR 201
 #define BRICKROWS 4
-#define BRICKCOLS 18
+#define BRICKCOLS 19
 #define FIRSTBRICKROW 2
 #define STARTTICK 4
 #define LIVES 3
 #define LAUNCHKEY ' '
-#define WALLCOL 0x51
-#define BATCOL 0xF1
-#define BALLCOL 0xF1
-#define TEXTCOL 0xE1
-#define TITLECOL 0xB1
-#define BACKDROP 1
-#define DEFAULTBACKDROP 4
 #define LEFTKEY '['
 #define RIGHTKEY ']'
@@ -39,6 +30,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives, level, tick, oldcol;
-int brickcol[BRICKROWS] = { 0x91, 0xB1, 0x31, 0x71 };
+int score, remaining, lives, level, tick;

 void draw_court()
@@ -46,5 +36,4 @@
     int i;
     cls40();
-    tcol(WALLCOL);
     for (i = LEFTWALL; i <= RIGHTWALL; i++) {
         curat(i, TOPWALL);
@@ -61,7 +50,6 @@
 void define_shapes()
 {
-    shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
-    shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
-    shapedef(WALL, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc);
+    shapedef(BALLCHAR, 0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00);
+    shapedef(BRICKCHAR, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00);
 }

@@ -71,7 +59,6 @@
     for (r = 0; r < BRICKROWS; r++)
         for (c = 0; c < BRICKCOLS; c++) {
-            tcol(brickcol[r]);
             bricks[r][c] = 1;
-            curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+            curat(1 + 2 * c, FIRSTBRICKROW + r);
             putchar(BRICKCHAR);
             putchar(BRICKCHAR);
@@ -82,5 +69,4 @@
 void draw_score()
 {
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("Score: %4d  Lives: %d  Level: %d ", score, lives, level);
@@ -90,5 +76,4 @@
 {
     int i;
-    tcol(TEXTCOL);
     curat(0, 22);
     printf("%s", s);
@@ -105,5 +90,4 @@
     p->dx = 1;
     p->dy = -1;
-    tcol(BALLCOL);
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -113,8 +97,6 @@
 {
     cls40();
-    tcol(TITLECOL);
     curat(12, 6);
     printf("B R E A K O U T");
-    tcol(TEXTCOL);
     curat(8, 10);
     printf("[ and ] move the bat");
@@ -141,5 +123,5 @@
     int r, c;
     r = p->y - FIRSTBRICKROW;
-    c = (p->x - PLAYLEFT) / 2;
+    c = (p->x - 1) / 2;
     if (r < 0 || r >= BRICKROWS || c < 0 || c >= BRICKCOLS)
         return;
@@ -148,6 +130,5 @@
     bricks[r][c] = 0;
     beep();
-    tcol(brickcol[r]);
-    curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    curat(1 + 2 * c, FIRSTBRICKROW + r);
     putchar(' ');
     putchar(' ');
@@ -163,5 +144,4 @@
 {
     int i;
-    tcol(BATCOL);
     curat(p->left, BATROW);
     for (i = 0; i < p->width; i++)
@@ -171,5 +151,5 @@
 void move_bat(p, dir) bat *p; int dir;
 {
-    if (dir < 0 && p->left > PLAYLEFT) {
+    if (dir < 0 && p->left > LEFTWALL + 1) {
         p->left--;
         curat(p->left + p->width, BATROW);
@@ -177,5 +157,5 @@
         draw_bat(p);
     }
-    if (dir > 0 && p->left + p->width - 1 < PLAYRIGHT) {
+    if (dir > 0 && p->left + p->width < RIGHTWALL) {
         curat(p->left, BATROW);
         putchar(' ');
@@ -192,5 +172,5 @@
     p->x += p->dx;
     p->y += p->dy;
-    if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
+    if (p->x <= LEFTWALL + 1 || p->x >= RIGHTWALL - 1)
         p->dx = -p->dx;
     if (p->y <= TOPWALL + 1)
@@ -207,17 +187,8 @@
 }

-row_colour(y) int y;
-{
-    if (y >= FIRSTBRICKROW && y < FIRSTBRICKROW + BRICKROWS)
-        return brickcol[y - FIRSTBRICKROW];
-    return BALLCOL;
-}
-
 void draw_ball(p) ball *p;
 {
-    tcol(row_colour(p->oldy));
     curat(p->oldx, p->oldy);
     putchar(' ');
-    tcol(row_colour(p->y));
     curat(p->x, p->y);
     putchar(BALLCHAR);
@@ -262,4 +233,12 @@
             if (c == RIGHTKEY)
                 move_bat(&paddle, 1);
+            if (c == 'P') {
+                message("Paused - any key");
+                while (kbd() != 0)
+                    ;
+                while (kbd() == 0)
+                    ;
+                draw_score();
+            }
             move_ball(&b, &paddle);
             if (b.y >= BATROW)
@@ -285,6 +264,4 @@
     int c;
     define_shapes();
-    oldcol = peek(0xfb38);
-    bcol(BACKDROP);
     for (;;) {
         title();
@@ -295,6 +272,4 @@
             break;
     }
-    tcol(oldcol);
-    bcol(DEFAULTBACKDROP);
     cls40();
     printf("Press ENTER to finish\n");

P shows Paused - any key on the status row; a key resumes and the score is redrawn.

S34

34.1

#include STDIO.H

main()
{
    int argc, i;
    char **argv;
    char buffer[80];
    cpm_cmd_line(&argc, &argv, buffer);
    for (i = 1; i < argc; i++) {
        printf("%s", argv[i]);
        if (i < argc - 1)
            printf(" ");
    }
    printf("\n");
}

#include ?CPM.LIB?
#include ?STDIO.LIB?

E341 THE TATUNG EINSTEIN prints THE TATUNG EINSTEIN; E341 alone prints an empty line.

THE TATUNG EINSTEIN

34.2

#include STDIO.H

extern char *strupper();

main()
{
    int argc, c, n;
    char **argv;
    char buffer[80];
    char *text;
    FILE *f;
    cpm_cmd_line(&argc, &argv, buffer);
    if (argc < 2) {
        printf("UPPER filename\n");
        return;
    }
    f = fopen(argv[1], "r");
    if (f == 0) {
        printf("no such file\n");
        return;
    }
    text = malloc(5000);
    n = 0;
    while ((c = getc(f)) != EOF && n < 4999)
        text[n++] = c;
    text[n] = 0;
    fclose(f);
    strupper(text);
    printf("%s", text);
}

#include ?CPM.LIB?
#include ?STDIO.LIB?

E342 SMALL.TXT, with SMALL.TXT holding two lines, prints them in capitals; E342 NOSUCH.TXT prints no such file. read_file would do the reading, but it does not say how many bytes it read, and strupper needs the 0 straight after them, so the solution reads with getc and puts the 0 itself. The extern char *strupper(); line is needed, and S34 says why.

ONE LINE OF TEXT
AND ANOTHER

34.3

#include STDIO.H

main()
{
    int argc, c;
    char **argv;
    char buffer[80];
    cpm_cmd_line(&argc, &argv, buffer);
    if (argc < 2) {
        printf("WIPE filename\n");
        return;
    }
    printf("Delete %s - sure? ", argv[1]);
    c = rawin();
    if (c == 'Y' || c == 'y') {
        unlink(argv[1]);
        printf("\ngone\n");
    } else
        printf("\nkept\n");
}

#include ?CPM.LIB?
#include ?STDIO.LIB?

E343 SMALL.TXT and N: kept; with Y: gone, and DIR SMALL.TXT says No File.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.