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 Modules
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.

Module 4

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

Module 7

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.

Module 8

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

Module 9

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

Module 10

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

Module 11

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

Module 12

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 (Module 9), 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

Module 13

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

Module 14

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

Module 15

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?
####################
########## #########

Module 16

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

Module 17

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

Module 18

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

Module 19

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 (Module 19). 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".

Module 20

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

Module 21

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.

Module 22

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 Module 24 and each key moved it on; the prompt was clean, but the listing keeps the gets because kbd() was used.

Module 23

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

Module 24

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.

Module 25

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.

Module 26

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.

Module 27

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();

Light blue walls on black, yellow bat, white message.

Module 28

28.1

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

@@ -56,5 +56,5 @@
     if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
         p->dx = -p->dx;
-    if (p->y <= TOPWALL + 1)
+    if (p->y <= TOPWALL + 1 || p->y >= BATROW - 1)
         p->dy = -p->dy;
 }
@@ -89,5 +89,5 @@
     draw_bat(&paddle);
     curoff();
-    while (b.y < BATROW) {
+    while (kbd() != 'Q') {
         move_ball(&b);
         draw_ball(&b);
@@ -96,5 +96,5 @@
     curon();
     curat(0, 22);
-    printf("Lost. Press ENTER");
+    printf("Stopped. Press ENTER");
     gets(line);
     cls40();

Row 21 is treated as the top wall is: the ball turns on the row next to it, so it never lands on the bat. It never stops; Q ends it with Stopped. Press ENTER.

28.2

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

@@ -56,6 +56,9 @@
     if (p->x <= PLAYLEFT || p->x >= PLAYRIGHT)
         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 +85,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):

@@ -23,4 +23,5 @@
 bat paddle;
 ball b;
+int ticks;

 void draw_court()
@@ -93,8 +94,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).

Module 29

29.1

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

@@ -83,4 +83,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 +111,5 @@
     char line[40];
     int c;
-    paddle.width = 5;
+    paddle.width = 7;
     paddle.left = 18;
     b.x = 20;

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):

@@ -13,4 +13,5 @@
 #define LEFTKEY '['
 #define RIGHTKEY ']'
+#define BATSPEED 2

 typedef struct {
@@ -52,14 +53,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 >= PLAYLEFT) {
+        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 - 1 + BATSPEED <= PLAYRIGHT) {
         curat(p->left, BATROW);
-        putchar(' ');
-        p->left++;
+        for (i = 0; i < BATSPEED; i++)
+            putchar(' ');
+        p->left += BATSPEED;
         draw_bat(p);
     }

With BATSPEED 2 the bat moves two columns a tick and rubs two out; no smear. The room checks keep the same margin: the bat moves only if the whole step fits.

29.3

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

@@ -124,4 +124,6 @@
         if (c == RIGHTKEY)
             move_bat(&paddle, 1);
+        if (c == 'Q')
+            break;
         move_ball(&b, &paddle);
         if (b.y >= BATROW)
@@ -134,5 +136,8 @@
     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.

Module 30

30.1

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

@@ -87,5 +87,5 @@
     putchar(' ');
     p->dy = -p->dy;
-    score += 10;
+    score += 10 * (BRICKROWS - r);
     remaining--;
     draw_score();

A brick in the bottom row scores 10, as before; each row above scores 10 more, up to 40 at the top.

30.2

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

@@ -11,4 +11,5 @@
 #define BALLCHAR 200
 #define BRICKCHAR 201
+#define HARDCHAR 202
 #define BRICKROWS 4
 #define BRICKCOLS 18
@@ -52,4 +53,5 @@
     shapedef(BALLCHAR, 0x00, 0x30, 0x78, 0xfc, 0xfc, 0x78, 0x30, 0x00);
     shapedef(BRICKCHAR, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00);
+    shapedef(HARDCHAR, 0xf8, 0xa8, 0xd8, 0xa8, 0xd8, 0xa8, 0xf8, 0x00);
 }

@@ -59,8 +61,13 @@
     for (r = 0; r < BRICKROWS; r++)
         for (c = 0; c < BRICKCOLS; c++) {
-            bricks[r][c] = 1;
+            bricks[r][c] = (r == 0) ? 2 : 1;
             curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
-            putchar(BRICKCHAR);
-            putchar(BRICKCHAR);
+            if (r == 0) {
+                putchar(HARDCHAR);
+                putchar(HARDCHAR);
+            } else {
+                putchar(BRICKCHAR);
+                putchar(BRICKCHAR);
+            }
         }
     remaining = BRICKROWS * BRICKCOLS;
@@ -82,6 +89,14 @@
     if (bricks[r][c] == 0)
         return;
-    bricks[r][c] = 0;
+    bricks[r][c]--;
     curat(PLAYLEFT + 2 * c, FIRSTBRICKROW + r);
+    if (bricks[r][c] == 1) {
+        putchar(BRICKCHAR);
+        putchar(BRICKCHAR);
+        p->dy = -p->dy;
+        p->x = p->oldx;
+        p->y = p->oldy;
+        return;
+    }
     putchar(' ');
     putchar(' ');

The top row is drawn with character 202 and takes two hits, turning into an ordinary brick on the first. On that first hit the ball is put back on the square it came from: left where it was, it would be drawn on a brick that is still there, and its rub-out would take half the brick with it.

30.3

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

@@ -70,5 +70,5 @@
 {
     curat(0, 22);
-    printf("Score: %d", score);
+    printf("Score: %d  Bricks: %d ", score, remaining);
 }

Score: 0 Bricks: 72, counting down.

Module 31

31.1

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

@@ -71,6 +71,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(' ');
 }

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

31.2

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

@@ -96,9 +96,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();
 }
@@ -200,5 +214,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):

@@ -17,4 +17,5 @@
 #define LIVES 3
 #define LAUNCHKEY ' '
+#define BONUS 100
 #define LEFTKEY '['
 #define RIGHTKEY ']'
@@ -32,5 +33,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives;
+int score, remaining, lives, bonus_given;

 void draw_court()
@@ -120,4 +121,8 @@
     score += 10;
     remaining--;
+    if (score >= BONUS && bonus_given == 0) {
+        bonus_given = 1;
+        lives++;
+    }
     draw_score();
 }

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

Module 32

32.1

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

@@ -33,4 +33,5 @@
 char bricks[BRICKROWS][BRICKCOLS];
 int score, remaining, lives, level, tick;
+int rowtick[BRICKROWS];

 void draw_court()
@@ -121,6 +122,5 @@
     remaining--;
     draw_score();
-    if (remaining == BRICKROWS * BRICKCOLS / 2 && tick > 1)
-        tick--;
+    tick = rowtick[r];
 }

@@ -196,4 +196,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):

@@ -209,4 +209,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):

@@ -204,4 +204,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.)

Module 33

33.1

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

@@ -39,5 +39,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives, level, tick, oldcol;
+int score, remaining, lives, level, tick, oldcol, high;
 int brickcol[BRICKROWS] = { 0x91, 0xB1, 0x31, 0x71 };

@@ -123,5 +123,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);
@@ -290,4 +292,6 @@
         title();
         play();
+        if (score > high)
+            high = score;
         message("Game over.  Again? (Y/N)");
         c = rawin();

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

33.2

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

@@ -39,5 +39,5 @@
 ball b;
 char bricks[BRICKROWS][BRICKCOLS];
-int score, remaining, lives, level, tick, oldcol;
+int score, remaining, lives, level, tick, oldcol, high;
 int brickcol[BRICKROWS] = { 0x91, 0xB1, 0x31, 0x71 };

@@ -123,5 +123,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);
@@ -278,6 +280,29 @@
     }
     curon();
+}
+
+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,4 +310,5 @@
     int c;
     define_shapes();
+    load_high();
     oldcol = peek(0xfb38);
     bcol(BACKDROP);
@@ -290,4 +316,8 @@
         title();
         play();
+        if (score > high) {
+            high = score;
+            save_high();
+        }
         message("Game over.  Again? (Y/N)");
         c = rawin();

After the game, DISP BREAKOUT.HI shows 610, and the next start of the program shows it on the title.

33.3

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

@@ -262,4 +262,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)

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

Module 34

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 Module 34 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.

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.