Merge branch 'master' into gh-pages
This commit is contained in:
commit
65da4c1d45
47 changed files with 12504 additions and 74 deletions
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.:
|
||||
|
||||
|
|
|
|||
332
_posts/2017-09-21-puzzled-programmers.md
Normal file
332
_posts/2017-09-21-puzzled-programmers.md
Normal 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*
|
||||
Loading…
Reference in a new issue