Date: Fri, 22 Jan 93 15:10:58 -0500 From: "swensotc@ACQ" Subject: QL Hacker's Journal #12 To: distribution:;@calando.acq.osd.mil (see end of body) Q L H A C K E R ' S J O U R N A L ---------------------------------------------------------- Number 12 Jan 1993 ---------------------------------------------------------- The QL Hacker's Journal (QHJ) is an amateur publication published by Tim Swenson strictly as a hobby and as a service to the QL Community. The QHJ is copyright by Tim Swenson and respective contributers, but may be freely copied and distributed (please do) to all QL users. The QHJ is always interested in article submissions. If interested, please send mail to the address below (Snail Mail or E-Mail). Electronic copies of the QHJ are available on disk or via e-mail from: QL Hacker's Journal c/o Tim Swenson 4773 W. Braddock Rd. #3 Alexandria, VA 22311 (703) 820-6657 swensotc@calando.acq.osd.mil tswenson@dgis.dtic.dla.mil (Be aware that my address will be changing soon) >From The Editor This issue is a smaller than I'd like. As the new owner of a Z88 I've been spending time playing with it. Not being good a soldering, I took me a while to make some cables for it. Plus, having a bad soldering pencil did not help matters. This will be the last issue before I move to Dayton, Ohio. I now plan to move in mid-February. Once I get established I'll put out another issue with my new mailing address on it (both e-mail and snail mail). Note to code submiters (what few there are): When submitting source code to the QHJ, remember that the line length of the QHJ is 60 chars. It would be appreciated if your source code came formated that way. QL to Z88 Data Transfer By Tim Swenson As the new owner of a Cambridge Z88 laptop, I needed a way to transfer files to and from the QL. I did not have enough memory to use Z88COM and I wanted to use the built in Import/Export utility. Transfering files from the Z88 to the QL was easy. Enter COPY SER2 TO RAM1_FILE_EXT, connect the Z88 on SER2, and have the Z88 send the file. Once the Z88 was done, I'd just hit CTRL-SPACE to break the COPY. Getting files to the Z88 would be more difficult. A direct copy would not not work. I was able to get a SuperBasic program from Dave Bennett that sort of worked. I found that I had to open the serial port as SER2IR. I did see that the program has a PAUSE between sending characters. Since SuperBasic does not have a byte input command, the program would read in a string at a time (ended with a LF). But files with no LF would cause problems. Time to move to C. The C program is fairly simple. My first version only prompted for a file name, the later version added the ability to set the baud rate and convert all LF's to CR's (the Z88 uses Cr's for EOL's). Once the serial port is opened right, the file is opened and, byte by byte, is sent to the Z88. I tried the program with out a pause between bytes, but it did not work, hence the FOR loop for a pause. In keeping with the Z88 Import/Export protocal, I send an ESC for end of file and ESC for end of batch. If the file came from the Z88 it has the filename in the file. One can then send the file to the Z88 in batch mode without telling the Z88 what the file name is. If it's not needed, the ESC's will go to the bit bucket. The program was written for Small-C but should compile fine with C68 with only a few modifications. /* File: QLtoZ88_c Author: Timothy Swenson Send files to the Z88 from the QL This program will send any file to a Z88. It has an option to translate all Line Feeds (LF) (QL End-Of-Line markers) to Carriage Return (CR) (Z88 End-Of-Line markers). At the end of each file it will send an End Of File escape command. It will the send an End of Batch escape sequence. Since Z88 files store the filename with in the file (when transfered out of Import- Export) the Batch Recieve can be used to send a file without explicitly telling the Z88 the filename. */ #define TRUE 1 #define FALSE 0 /* #define CR 13 defined in STDIO_H */ /* #define LF 10 defined in STDIO_H */ #define ESC 27 #include main() { char c, file[30]; int i, convert, baud_rate, fd1, fd2; printf(" QL To Z88 \n"); printf(" By Tim Swenson\n\n"); printf("Enter Input File Name : \n"); gets(file); fd1 = fopen(file,"r"); if (fd1 == NULL) { printf("Did not open file: %s",file); abort(1); } printf("\nConvert LF to CR? (Y/N)"); getchar(c); convert = FALSE; /* default */ if ( c == 'Y' || c == 'y' ) convert = TRUE; printf("\nSelect Baud Rate: \n"); printf(" 1 - 300\n"); printf(" 2 - 1200\n"); printf(" 3 - 2400\n"); printf(" 4 - 9600\n"); printf("Default of 1200\n"); getchar(c); baud_rate = 1200; /* default */ if ( c == '1' ) baud_rate = 300; if ( c == '2' ) baud_rate = 1200; if ( c == '3' ) baud_rate = 2400; if ( c == '4' ) baud_rate = 9600; fd2 = fopen("ser2ir","w"); if (fd2 == NULL) { printf("Could not open Serial 2\n"); abort(1); } baud(baud_rate); while (( c = getc(fd1)) != EOF) { if ( convert == TRUE && c == LF ) putc(CR,fd2); else putc(c,fd2); /* Pause in sending */ for ( i = 1; i < 500; i++) ; } /* Send ESC E to signal End of File */ /* ( Z88 Protocal ) */ putc(ESC,fd2); putc('E',fd2); /* add another pause */ for ( i = 1; i < 500; i++ ) ; /* Send ESC Z to signal End of Batch */ putc(ESC,fd2); putc('Z',fd2); fclose(fd1); fclose(fd2); } One small problem with Z88 ASCII files on the QL was the fact that the Z88 used CR instead of LF to mark EOL. I wrote a very short program that will read in a file, convert all instances of CR to LF and output the file. It's fairly trivial but I've added here for the beginning C users out there. /* File: CRtoLF_c Author: Timothy Swenson Converts all CR's to LF's This program will take a file that came from the Z88 with CR's for End-Of-Line markers and convert them to LF's (QL End-OF-Line markers). */ /* #define CR 13 defined in STDIO_H */ /* #define LF 10 defined in STDIO_H */ #include main() { char c, file[30]; int fd1, fd2; printf("Enter Input File Name : \n"); gets(file); fd1 = fopen(file,"r"); if (fd1 == NULL) { printf("Did not open input file: %s",file); abort(1); } printf("Enter Output File Name : \n"); gets(file); fd2 = fopen(file,"w"); if (fd2 == NULL) { printf("Could not open output file: %s\n",file); abort(1); } while (( c = getc(fd1)) != EOF) { if ( c == CR ) putc(LF,fd2); else putc(c,fd2); } fclose(fd1); fclose(fd2); } MacPaint File Printing By Don Walterman Don Walterman has sent a program that reads a MacPaint file and prints to an HP Deskjet printer. Don claims that this is his first C program. If so, it's very ambitious. Don did not send an article describing his program, so I'll present it as is. For formatting reasons, comments are below the lines that they apply to. I've inserted ^'s to emphasise the point. /* Print_Mac305_c Author: Don Walterman */ char _PROG_NAME[] = "Print Mac"; #include #include #define ESC 27 #define FF 12 char macfile_name[50],answer,i; unsigned short int bits,repeat_count,single_count,byte; unsigned short int dot_column,single_byte,line_count; long tty_wait = 0; FILE *mac_file, *printer; main() { if((tty_wait = isatty( fileno( stdout ))) && !isnoclose( fileno(stdout ))) { struct QLRECT rect; rect.q_width = 512; rect.q_height =200; rect.q_x = rect.q_y = 0; tty_wait = getchid( fileno(stdout) ); sd_wdef( tty_wait, -1, RED_M4, 1, &rect); sd_clear( tty_wait, -1); } printf("Enter the readmac file to print \n(including the device name). "); scanf("%s" , macfile_name); if ((mac_file = fopen(macfile_name,"r")) == NULL) { puts("\ncan't find file...please check disk and try again\n "); printf("System error returned..... %d %s", _oserr," \n"); if(tty_wait) { printf("Press any key to continue\n"); io_fbyte( tty_wait, -1, &i); } main(); } fseek(mac_file,640,SEEK_SET); /* ^ set file pointer to start of picture data */ printer = fopen("SER1","w"); /* ^ open SER1_ for printing */ fprintf(printer,"%c%s", ESC, "*b0M"); /* ^ select full graphics mode */ fprintf(printer,"%c%s", ESC,"*t75R"); /* ^ select 75 dpi resolution */ fprintf(printer,"%c%s", ESC,"&a0C"); /* ^ set printer's cursor to leftmost position */ fprintf(printer,"%c%s", ESC,"&a+112H"); /* ^ center the image on the page */ fprintf(printer,"%c%s", ESC,"*r1A"); /* ^ start printing at current printer(cursor) position */ dot_column = 0; line_count = 0; fprintf(printer,"%c%s", ESC,"*b72W"); /* ^ print 576 dots per line (standard Mac screen width) */ /* 72 dot_columns x 8 bits per dot_column */ do { byte = fgetc(mac_file); if (byte > 184 && byte < 256) { repeat_count = 257 - byte; byte = fgetc(mac_file); do { fputc(byte , printer); /* ^ this routine prints out the repeating data bytes */ dot_column++; /* ^ the first byte tells how many times to repeat the */ if(dot_column > 71) /* ^ next byte */ { fprintf(printer,"%c%s", ESC,"*b72W"); dot_column = 0; line_count++; update(); } --repeat_count; } while (repeat_count > 0); } else { /* ^ this routine prints out the non-repeating */ if (byte < 128) /* ^ graphics bytes. the first byte tells how many */ { /* non-repeating bytes follow */ single_count = 0; do { single_byte = fgetc(mac_file); fputc(single_byte , printer); dot_column++; if(dot_column > 71) { fprintf(printer,"%c%s", ESC,"*b72W"); dot_column = 0; line_count++; update(); } single_count++; } while(single_count < (byte+1)); } } } while(!feof(mac_file) && (line_count < 720)); /* ^ jump out at end of file */ /* the screen is 720 lines so skip the garbage */ if(dot_column < 72) /* ^ the file may have appended from the file transfer */ { do { /* ^ this routine finishes off whatever graphics */ byte = 0; /* ^ line is started so that the next two commands */ fputc(byte , printer); /* ^ are not mistaken for graphics data */ dot_column++; } while(dot_column < 72); } fprintf(printer,"%c%s", ESC,"*rB"); /* ^ tell DeskJet end of graphics data */ fprintf(printer,"%c", FF); fclose(printer); fclose(mac_file); printf("\nPrint another Readmac file ? "); if(getchar() == 89 | getchar() == 121) /* ^ if 'y' or 'Y' start over */ { main(); } } update() { sd_pixp( tty_wait, -1,10,20); printf("printing line %d %s", line_count, "of 720 lines....\n"); } Maze Solution with CA By Tim Swenson I've been playing with Cellular Automata (CA) since College. (See QHJ #4 for a more indepth discussion of CA) I've seem some articles that talk about how CA can be used in Physics and Chemistry to simulate various chemical reactions and particle simulations. I have not seen any fairly practical applications that can be easy demonstrated to show how useful CA can be. That was before I read an article in the most recent issue of "Dr Dobb's Journal." Basem Nayfeb of Stanford University gives a fresh approach to finding the solution to a maze. Past algorithms for solving mazes were brute force approaches to solve the maze just like a mouse. Be recursivly searching all possible paths the solution will be eventually found. This takes time and lots of memory for stack space. Basem Nayfeb used CA to solve the problem with no extra extra memory needed. Given a maze stored in an array. Cells with a wall have a value of 1, free cells are 0. In the maze possible moves are north, west, east, and south. This translates to a neighborhood of the 4 cells that share a side with a cell. Basem defines a counting rule that states: A free cell will become a wall cell if there are three or more walls in its neighborhood. The only cells that have 3 or more walls nearby are obviously dead-ends. Over time all dead-ends will convert to walls and only the true path(s) will stay free of walls. By defining a simple neighborhood and that one simple rule, Basem has defined a CA that will fairly quickly find the solution to the maze. Below is the a SuperBasic program that implements the algorithm. You can see how short and simple it is. Consider how much code it would take to solve the problem the recursive way. ** Maze_ssb ** Tim Swenson ** ** Based on an algorithm by Basem A. Nayfeb ** Dr Dobb's Journal January 1993 ** wall = 1 free = 0 ** My example maze is 16x16. Change ** to what ever you need. maze_x = 16 maze_y = 16 DIM maze(maze_x,maze_y) read_file display REPeat loop eval dislay IF change = 0 THEN EXIT loop END REPeat loop DEFine PROCedure read_file OPEN_IN #4,flp1_maze_data FOR y = 1 TO maze_y INPUT #4,in$ FOR x = 1 TO maze_x maze(x,y) = in$(x) END FOR x END FOR y CLOSE #4 END DEFine read_file DEFine PROCedure eval LOCal count change = 0 FOR y = 2 TO maze_y-1 FOR x = 2 TO maze_x-1 count = 0 IF maze(x,y+1) = wall THEN count=count+1 IF maze(x+1,y) = wall THEN count=count+1 IF maze(x,y-1) = wall THEN count=count+1 IF maze(x-1,y) = wall THEN count=count+1 IF count >= 3 THEN maze(x,y) = wall change = 1 END IF END FOR x END FOR y END DEFine eval DEFine PROCedure display CLS FOR y = 1 TO maze_y FOR x = 1 TO maze_x IF maze(x,y) = wall THEN PRINT "*"; ELSE PRINT " "; END IF END FOR x PRINT END FOR y PAUSE 4E4 END DEFine display Here is an example data file that I used in my testing of the program: 1111111111111111 1000000010000101 1010111010110101 1010101010110101 1010101010110101 1010101010111101 1110101010110001 0000101000110100 1110101010110101 1010101010110101 1010101010110101 1010101010110101 1010100010110101 1011111110111101 1000000000000001 1111111111111111 QHJ Index Here is a listing of issues and articles for the first two years of the QHJ. Use as a quick reference to find what issue a particular article is in. QHJ #1 - January 1991 Structured SuperBasic Ratcliff/Obershelp Pattern Matching The Quebec Link Pursuit of a PD C Compiler Minix on the QL QHJ #2 - February 1991 Find_c DiskInfo_bas C Beautifier QHJ #3 - April 1991 Herb Schaaf's Small C Programs File Comparison Real Windows for SuperBasic C Compiler Comparison QHJ #4 - July 1991 Rand_c Cellular Automata Iterated Function Systems QHJ #5 - August 1991 News The Dutch Connection QHJ Print Formatter QROFF Postscript Formatter 2D Arrays in Small C QHJ #6 - November 1991 Italian Software Dutch Connection II RPN Calculator Substring Searching in C Levenstein Distance QDOS Rights Compiler Benchmarks QHJ #7 - January 1992 Core Wars QLPatch The German Connection New QL QHJ #8 - March 1992 ASCII Dump Check Bits for ASCII Files ANSI C to K&R C Strip_c QHJ #9 - June 1992 New Public Domain/Freeware QL Software Software Engineering and OOPS on the QL? Random Dot Stereograms Infix to Postfix Fletcher's Checksum QHJ #10 - September 1992 Programmer's Bookshelf Maus.sys.ql PGM & PBM to QL QHJ #11 - November 1992 C68 Version 3.03 Disk Eraser Random ASCII Stereograms LZW Compression Token Reconstruction %%% overflow headers %%% To: 100031.2312@compuserve.com, 70004.75@compuserve.com, 70313.3522@compuserve.com, 71071.462@compuserve.com, 71157.745@compuserve.com, 71650.605@compuserve.com, 72047.2774@compuserve.com, 72267.3572@compuserve.com, 72466.3716@compuserve.com, 73270.1444@compuserve.com, 74405.1244@compuserve.com, 74435.135@compuserve.com, 75206.1565@compuserve.com, 9021973@ul.ie, ac959@cleveland.freenet.edu, adamd@rhi.hi.is, agulbra@siri.unit.no, akayser@dnpap.et.tudelft.nl, andreas_bloetscher@bb.maus.de, beppe@alessia.dei.unipd.it, bj@cs.tu-berlin.de, bolli@matai.vuw.ac.nz, chris@bcl.co.nz, cs89ssg@brunel.ac.uk, dhembrow@eoe.co.uk, Dirk_Kutscher@hb2.maus.de, flight@vogon.mathi.uni-heidelb, gaylord@shannon.ee.wits.ac.za, geisler@namu01.gwdg.de, georg@bluemoon.gun.de, grimbert@aedi.insa-lyon.fr, groot@idca.tds.philips.nl, Hans_Hoelscher@hb.maus.de, hclase@morgan.ucs.mun.ca, henne@eana.f3.gmd.dbp.de, hlschaaf@brahms.udel.edu, j.c.vanderwal@research.ptt.nl, jeroen@cs.few.eur.nl, jfsenior@vax1.tcd.ie, jk@zarniwoop.pc-labor.uni-bremen.de, jmooring@mswe.dnet.ms.philips.nl, johnl@master.qpsx.oz.au, klamer@mi.eltn.utwente.nl, lorenz@alessia.dei.unipd.it, lsg001@cck.cov.ac.uk, martin@chemeng.ed.ac.uk, mauricio@gauss.aero.ufl.edu, mbppxgf@cms.mcc.ac.uk, mcj@moose.cccs.umn.edu, peter@opusc.csd.scarolina.edu, pfoley@cavebbs.welly.gen.nz, qltwirl@matai.vuw.ac.nz, Ralf_Tenbrink@bn.maus.de, rcarter@isis.cs.du.edu, rdw@ukc.ac.uk, rohde@namu01.gwdg.de, s.telford@ed.ac.uk, sander.plomp@cwi.nl, seje890@ucl.ac.uk, srwmpnm@wnv.grace.cri.nz, swh@eatl.co.uk, ts@uwasa.fi, UDAH054@oak.cc.kcl.ac.uk, umisef@mcshh.hanse.de, v882022@si.hhs.nl, wahl@ocf.berkeley.edu, woodman@bnr.ca, ztsindi@ubvmsb.cc.buffalo.edu, cc201jja01@trent-poly.ac.uk, dnash@chaos.demon.do.uk, ipi@cernvm.bitnet, dup@vax.ox.ac.uk, 71071.462@compuserve.com, jockneyj@cs.man.ac.uk %%% end overflow headers %%%