Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2017-09-21 17:28:47 -07:00
commit 65da4c1d45
47 changed files with 12504 additions and 74 deletions

View file

@ -11,7 +11,7 @@ are simple XML files that describe a piece of software (an application, an opera
link to a PCjs machine configuration capable of running the software, along with a "ready-to-run" machine state file.
Conversely, a PCjs machine XML file can refer back to the manifest, to obtain a list of disk images.
Here are some [Demos](/apps/pc/) of "ready-to-run" apps on [PCjs](/docs/about/).
Here are some [Demos](/apps/pcx86/) of "ready-to-run" apps on [PCjs](/docs/about/).
There have been lots of server-side changes recently, including API improvements that make it easy (well, *easier*)
to dynamically create diskette images from a list of files, or even an entire folder (including all subfolders),

View file

@ -135,7 +135,7 @@ modes commonly used on the IBM VGA. Here's that table:
ATC[0x12]: PLANES 0x0F 0x0F 0x0F 0x0F 0x03 0x03 0x01 0x0F 0x0F 0x0F 0x0F 0x0F
ATC[0x13]: HPAN 0x08 0x08 0x08 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
In addition, I've created a [VGA Tests](/tests/pc/vga/) directory to hold VGA test and sample code that PCjs can
In addition, I've created a [VGA Tests](/tests/pcx86/vga/) directory to hold VGA test and sample code that PCjs can
now successfully run (for the most part). See that directory for more details.
*[@jeffpar](http://twitter.com/jeffpar)*

View file

@ -13,7 +13,7 @@ It turned out that that archive was a rabbit hole I could not *not* go down.
First, I collected all the other PC Tech Journal ZIP archives there (from December 1985 through January 1989),
recreated them as a set of [PC Tech Journal Disks](/disks/pcx86/shareware/pctj/), and added them to the
[PCjs Disk Library](/disks/pcx86/), so now you can "Load" and "Save" them in any [PCjs Machine](devices/pcx86/machine/).
[PCjs Disk Library](/disks/pcx86/), so now you can "Load" and "Save" them in any [PCjs Machine](/devices/pcx86/machine/).
Next, since I was also a fan of PC Magazine back in the day, I decided to do the same for all the PC Magazine ZIP
archives. So now there's a set of [PC Magazine Disks](/disks/pcx86/shareware/pcmag/) you can play with as well.

View file

@ -86,7 +86,7 @@ starts reading from the top of video memory after it reaches the bottom. So all
new lines at the top of the video memory again. If IBM had thought of that trick 5 years earlier, back in 1981,
think of all the years of shared flicker-grief that could have been avoided!
Today, in honor of all that flickering, I'm pleased to announce that [PCx86](devices/pcx86/machine/), one of the
Today, in honor of all that flickering, I'm pleased to announce that [PCx86](/devices/pcx86/machine/), one of the
PCjs emulators I'm always trying to improve, now offers **FLICKERING** on all IBM PC Color Graphics configurations.
If you feel the need to override it, you can add *flicker=0* to the URL of your favorite machine; e.g.:

View file

@ -0,0 +1,332 @@
---
layout: post
title: Puzzled Programmers
date: 2017-09-21 10:00:00
permalink: /blog/2017/09/21/
machines:
- id: ibm5160-msdos320
type: pcx86
resume: 1
config: /devices/pcx86/machine/5160/ega/640kb/machine.xml
drives: '[{name:"10Mb Hard Disk",type:3,path:"/disks/pcx86/fixed/10mb/MSDOS320-C400.json"}]'
autoMount:
A:
name: None
B:
name: None
---
One of books I used to have a copy of (and perhaps still do, in the bowels of my storage unit) was "Puzzled Programmers"
by Michael Wiesenberg. It was published by Microsoft Press in 1987, and I recently rediscovered an online copy in the
[Internet Archive's](https://archive.org) [Open Library](https://openlibrary.org):
> [Puzzled Programmers: 15 mind-boggling story puzzles to test your programming prowess, solutions in BASIC, Pascal, and C](https://openlibrary.org/books/OL2379315M/Puzzled_programmers)
Someone else was currently "borrowing" it, so I added myself to the wait-list, and a few days ago, the Internet Archive
notified me that it was available for reading. I started skimming it, and noticed that for each of the puzzles, it
included complete solutions in all the aforementioned languages: BASIC, Pascal, and C. I also noticed this portion of
the Introduction:
> **Timing the Programs on Your Computer**
> Run times are specified for each puzzle, but you should look at these times only as guidelines or, in the vernacular,
as ballpark figures. The figures given are for a Hewlett-Packard Vectra (IBM PC AT compatible) running at a clock speed
of 8 MHz. Obviously, the times will differ with other interpreters and on other computers. The following table gives you
some idea of how long a program ought to take on your particular system. This table shows timings on various systems
of the programs presented in the solution to Puzzle 5.
Computer BASIC Turbo Pascal Microsoft C
-------------------------------------------------------------------------------
Tandy 1000 (4.77 MHz) 2 minutes 11 seconds 1.3 seconds 2.4 seconds
IBM PC XT clone (4.77 MHz) 1 minute 58.5 seconds 1.3 seconds 2.3 seconds
IBM PC A T (6 MHz) 50 seconds 0.5 seconds 0.9 seconds
HP Vectra (8 MHz) 35 seconds 0.5 seconds 0.4 seconds
Macintosh Plus 8 seconds < 1 second < 1 second
Apple II C 2 minutes 20 seconds 23.6 seconds* n/a
-------------------------------------------------------------------------------
*Apple Pascal
This almost seemed like an invitation to try my hand at Puzzle #5, and to see how a PCjs "machine" fared.
### A Pleasant Fourthsum
I skipped ahead to page 27, "Puzzle 5: A Pleasant Fourthsum", and started reading. I have to admit that the story
completely failed to interest me. There were lots of irrelevant details about a delicious breakfast that this imaginary
bunch of successful twenty-somethings were enjoying, when suddenly one of them says:
"Before we get into the future of languages at I-Q, I've got a great computer puzzle for everyone."
which he then states in one sentence:
"Find a four-digit number that is the sum of the fourth powers of its digits."
and then the conversation returns to other random topics, like whether anyone should be worried that FORTRAN might
become a weapons guidance language, and whether they need to make lunch reservations -- when they've barely finished
breakfast!
Skipping ahead to the "Solutions" section, it turned out that the challenge was to actually find *all* four-digit
numbers, not just *a* number. Also, only numbers 1000 through 9999 are considered (no numbers with leading zeros).
Just for fun, I created [my own solution](/tests/node/puzzled/puzzle5.js) in JavaScript first:
```javascript
let p = new Array(10);
/**
* test(n)
*
* Returns true IFF the number matches the criteria.
*
* @param {number} n
* @returns {boolean}
*/
function test(n) {
let total = 0;
let value = n;
while (n) {
total += p[n % 10];
n = (n / 10)|0;
}
return total == value;
}
function run() {
let n = 1000;
for (let d = 0; d < 10; d++) {
p[d] = Math.pow(d, 4);
}
while (true) {
if (test(n)) console.log(n);
if (++n > 9999) break;
}
}
run();
```
then I looked at the solutions in "Puzzled Programmers". Here's the BASIC solution:
```basic
5 REM BASIC Solution to Puzzle #5 in "Puzzled Programmers" (c) 1987
10 DIM PWR(9)
20 FOR I = 0 TO 9
30 PWR(I) = I^4
40 NEXT I
50 H000 = 1000
60 FOR H = 1 TO 9
70 I00 = 0
80 FOR I = 0 TO 9
90 J0 = 0
100 FOR J = 0 TO 9
110 PARTSUM = H000 + I00 + J0
120 PART4THS = PWR(H) + PWR(I) + PWR(J)
130 FOR K = 0 TO 9
140 SUM = PARTSUM + K
150 IF PART4THS + PWR(K) <> SUM THEN 190
160 PRINT SUM; "= ";
170 PRINT USING "#^4 + "; H, I, J;
180 PRINT USING "#^4"; K
190 NEXT K
200 J0 = J0 + 10
210 NEXT J
220 I00 = I00 + 100
230 NEXT I
240 H000 = H000 + 1000
250 NEXT H
```
and the C solution (which I modified to loop 100 times, to make timing with a stopwatch easier):
```c
/* C solution to puzzle #5 in "Puzzled Programmers" (c) 1987 */
main()
{
int pwr[10], /* the fourth power of each digit */
h, /* the digit in the thousands position */
h000, /* h * 1000, that is, the value of the number
in the thousands position */
i, /* the digit in the hundreds position */
i00, /* i * 100, that is, the value of the number
in the hundreds position */
j, /* the digit in the tens position */
j0, /* i * 10, that is, the value of the number
in the tens position */
part4ths, /* h^4 + i^4 + j^4 */
partsum, /* h000 + i00 + j0 */
k, /* the digit in the ones position */
sum, l;
for (i = 0; i < 10; i++) pwr[i] = i * i * i * i;
for (l = 100; l-- > 0;) {
for (h000 = 1000, h = 1; h <= 9; h++, h000 += 1000) {
/* thousands digit */
for (i00 = i = 0; i <= 9; i++, i00 += 100) {
/* hundreds digit */
for ( j0 = j = 0; j <= 9; j++, j0 += 10) {
/* tens digit */
partsum = h000 + i00 + j0;
part4ths = pwr[h] + pwr[i] + pwr[j];
for ( k = 0; k <= 9; k++) { /* ones digit */
sum = partsum + k; /* this produces the four-digit
number */
if (part4ths + pwr[k] == sum) {
if (!l) printf("%d = %d^4 + %d^4 + %d^4 + %d^4\n",
sum, h, i, j, k);
}
}
}
}
}
}
}
```
Here's my own C solution, which is slightly smaller and faster than the book's solution:
```c
/* @jeffpar's optimized C solution to puzzle #5 */
main()
{
int p[10];
int d, l, n, s;
for (d = 0; d < 10; d++) p[d] = d * d * d * d;
for (l = 100; l-- > 0;) { /* loop 100 times for timing purposes */
for (n = 100; n < 1000; n++) {
/* I originally used a "do...while (t /= 10)" loop here
to create the power summation (where t was a copy of n),
but since we know n is a 3-digit number, we can inline
all three power references and minimize the number of
divisions; we also bias the sum by -(n*10) so that we
don't have to add (n*10) to d for the final comparison. */
s = p[n/100] + p[(n/10)%10] + p[n%10] - (n*10);
for (d = 0; d < 10; d++) {
if (s + p[d] == d) {
if (!l) printf("%d = %d^4 + %d^4 + %d^4 + %d^4\n",
n * 10 + d, n/100, (n/10)%10, n%10, d);
}
}
}
}
}
```
And finally, here's the book's Pascal solution:
```pascal
program sum4ths(input, output);
var
pwr: { the fourth power of each number, 0 to 9 }
array[0..9] of integer;
h, { the digit in the thousands position }
h000, { h * 1000, that is, the value of the number
in the thousands position }
i, { the digit in the hundreds position }
i00, { i * 100, that is, the value of the number in
the hundreds position }
j, { the digits in the tens position }
j0, { j * 10, that is, the value of the number in
the tens position }
part4ths, { h^4 + i^4 + j^4 }
partsum, { h000 + i00 + j0 }
k, { the digit in the ones position }
sum: integer;
begin
for i := 0 to 9 do pwr[i] := i * i * i * i;
h000 := 1000;
for h := 1 to 9 do begin { thousands digit }
i00 := 0;
for i := 0 to 9 do begin { hundreds digit }
j0 := 0;
for j := 0 to 9 do begin { tens digits }
partsum := h000 + i00 + j0;
part4ths := pwr[h] + pwr[i] + pwr[j];
for k := 0 to 9 do begin { ones digit }
sum := partsum + k; { this produces the four-digit number }
if part4ths + pwr[k] = sum then
writeln(sum, ' = ', h, '^4 + ', i, '^4 + ', j, '^4 + ', k, '^4')
end;
j0 := j0 + 10;
end;
i00 := i00 + 100;
end;
h000 := h000 + 1000;
end
end.
```
You can play with all these solutions in the 4.77Mhz IBM PC XT machine below. Use `CD \PUZZLED\PUZZLE5` to switch
to the directory for Puzzle #5.
To run the BASIC version, use `GWBASIC`, since the machine boots MS-DOS 3.20:
C:\PUZZLED\PUZZLE5>GWBASIC PUZZLE5.BAS
To compile and run the C version, you can use the pre-installed copy of Microsoft C 4.00:
C:\PUZZLED\PUZZLE5>cl puzzle5.c
Microsoft (R) C Compiler Version 4.00
Copyright (C) Microsoft Corp 1984, 1985, 1986. All rights reserved.
puzzle5.c
Microsoft (R) Overlay Linker Version 3.51
Copyright (C) Microsoft Corp 1983, 1984, 1985, 1986. All rights reserved.
Object Modules [.OBJ]: PUZZLE5.OBJ
Run File [PUZZLE5.EXE]: PUZZLE5.EXE/NOI
List File [NUL.MAP]: NUL
Libraries [.LIB]: ;
C:\PUZZLED\PUZZLE5>puzzle5
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
To compile and run the Pascal version, load diskette "IBM Pascal 1.00 (Combined)" in drive A, and then type the
commands shown below:
C:\PUZZLED\PUZZLE5>a:pas1
IBM Personal Computer Pascal Compiler
Version 1.00 (C)Copyright IBM Corp 1981
Source filename [.PAS]: puzzle5p
Object filename [PUZZLE5P.OBJ]:
Source listing [NUL.LST]:
Object listing [NUL.COD]: puzzle5p
Pass One No Errors Detected.
C:\PUZZLED\PUZZLE5>a:pas2
Code Area Size = #0296 (662)
Cons Area Size = #004C (76)
Data Area Size = #002A (42)
Pass Two No Errors Detected.
C:\PUZZLED\PUZZLE5>a:link
IBM Personal Computer Linker
Version 1.00 (C) Copyright IBM Corp 1981
Object Modules: puzzle5p
Run File: puzzle5p
List File [PUZZLE5P.MAP] :
Libraries [ ] :
Publics [No]:
Line Numbers [No]:
Stack size [Object file stack]:
Load Low [Yes]:
DSAllocation [No]:
C:\PUZZLED\PUZZLE5>puzzle5p
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
It appears that PCjs is somewhat faster than a real machine. For example, the author's BASIC solution ran
for almost two minutes on a PC XT clone, but it finishes in about one and a half minutes on the 4.77Mhz PC XT
configuration below.
Clearly, I still have some work to do if I want PCjs to faithfully simulate how *slow* these systems used to be.
{% include machine.html id="ibm5160-msdos320" %}
*[@jeffpar](http://twitter.com/jeffpar)*
*Sep 21, 2017*