General Category > Programming

A little Pascal programming…

(1/2) > >>

the graveborn:
The following is my solution to the second sub-problem of the "Three Homework Problems" problem posed by Programming Praxis; I'm just trying to solve the problems posed by the aforementioned 'site whilst I try to get a job - I was just fired in so passive a way that I'm not completely certain that I've been fired (I had - have..? - a "zero hour" job, and my employer just stopped offering me hours and responding to my emails :/ ) - and, having solved a fair few of the problems posed by the aforementioned 'site using a (kind of..?) retro Mac (an Apple Power Mac G4 (AGP Graphics) (450MHz processor, 1GB memory)), I decided to try to solve the problems posed by the aforementioned 'site using an Amstrad CPC and HiSoft Pascal for CP/M-80 and HiSoft Pascal Amstrad CPC464 to try to broaden my exposure to other platforms - particularly after I skimmed the documentation and realised that machine code could be intermixed with Pascal using arrays and the built-in ADDR function and USER procedure; but, if I'd done more than just skim the documentation, I would have realised that HiSoft Pascal Amstrad CPC464 doesn't provide any built-in functions or procedures for using files, and so I think that my using that platform - or at least that compiler - to try to solve the problems posed by the aforementioned 'site - and to try to program games - has ended almost as quickly as it began :/

(And I'm well-aware that my solutions to the problems posed by the aforementioned 'site are far from the best - but, in my defence, I don't have any traditional qualifications in computer science :/ )

PP150918.pas:


--- Code: ---(* Programming Praxis *)
(* "Three Homework Problems" (18th of September, 2015) *)
(* [Sub-problem #2] *)

PROGRAM PP150918;

VAR
 i : 1..27;
 count (* (s) of letter(s) *) : ARRAY [ 1..26 ] OF 0..MAXINT;
 c : CHAR;
 first : BOOLEAN;
 number (* of letters *) : 0..26;
 were : BOOLEAN;
 k : 0..26;

FUNCTION fToLowercase( p : CHAR ) : CHAR;
BEGIN
 IF p IN [ 'A'..'Z' ] THEN
  fToLowercase := CHR( ORD( p ) - ORD( 'A' ) + ORD( 'a' ))
 ELSE
  fToLowercase := p
END;

BEGIN
 FOR i := 1 TO 26 DO
  count[ i ] := 0;
 WRITELN;
 WRITE( 'Please enter a string; ' );
 WRITE( 'this program will then count the number of occurences of each ' );
 WRITELN( 'letter in that string.' );
 WRITELN;
 WRITE( 'Your input: ' );
 REPEAT
  READ( c );
  c := fToLowercase( c );
  IF c IN [ 'a'..'z' ] THEN BEGIN
   i := ORD( c ) - ORD( 'a' ) + 1;
   count[ i ] := count[ i ] + 1
  END
 UNTIL EOLN;

 first := TRUE;
 number := 0;
 FOR i := 1 TO 26 DO
  IF count[ i ] > 0 THEN BEGIN
   IF first THEN BEGIN
    first := FALSE;
    were := count[ i ] > 1
   END;
   number := number + 1
  END;

 WRITELN;
 WRITE( 'There w' );
 IF ( number = 0 ) OR were THEN
  WRITE( 'ere' )
 ELSE
  WRITE( 'as' );
 WRITE( ' ' );
 IF number = 0 THEN
  WRITE( 'no letters' )
 ELSE BEGIN
  k := 0;
  FOR i := 1 TO 26 DO
   IF count[ i ] > 0 THEN BEGIN

    k := k + 1;
    IF k > 1 THEN
     IF number <> 2 THEN BEGIN
      WRITE( ', ' );
      IF k = number THEN
       WRITE( 'and ' )
     END ELSE
      WRITE( ' and ' );

    WRITE( count[ i ]:0, ' ''', CHR( i - 1 + ORD( 'a' )), '''' );
    IF count[ i ] > 1 THEN
     WRITE( 's' )
   END
 END;
 WRITELN( ' in the string that you entered.' )
END.
--- End code ---

AMSDOS:
Hisoft Pascal 4t (or as you're calling it HiSoft Pascal Amstrad CPC464), has been designed to utilise much of the Amstrads Firmware, so for Games for example, it would be looking at simple games. Not that Simple Games can't be enjoyable, I coded 'Get the Cash' with it and towards the end of that project I felt like it was very close to pushing the limits on Hisoft Pascal 4t. I probably had some things in there I could have done better, for instance I was loading Sprite Driver/Graphics & Music. The Sprite Driver probably could have been some procedures which may have freed up some memory, I also used very descriptive names for the procedures, in Hisoft Pascal 4t only the Keywords are Tokenised, which leaves the names of procedures, variables and even variable types fully ASCII. The Hisoft Pascal 80 version would probably give more space to play with to compile programmes, it's only restriction being it only Compiles COM files for CP/M, while Hisoft Pascal 4t is pushing it's boundaries around 20k or so. It does allow like Turbo Pascal 3 to insert source code files at compile time and this does help free up space, though that was what I had to do to get my Game going.
You're correct in Hisoft Pascal for CPC464 doesn't have any standard File handling facilities. Within the Compiler is two non-standard commands called TIN(); and TOUT(); which Load and Save Files in a Character Format. They can be used to load Data into an Array or Saved from an Array, apart from that other the alternative is to write you own which involves using the Firmware.
The Firmware handling is one of Hisoft Pascal 4t strengths and can easily be accessed without any Machine Code necessary by allowing access to the Register Set through R variable. 'R' then follows on with any of the available registers the Amstrad has, so 'A','HL','DE','BC' for example. It can also use 'H','L' as single registers for example, so when single registers are used Hisoft Pascal needs to convert into Byte format which it does with the CHR(varname), this way when writing a PROCEDURE which carries out a operation a Numeric value can be passed through the PROCEDURE and then be converted where necessary. I hope that makes sense.

SRS:
Nice :)
Just made me quickhack it in good ol' loco:

--- Code: ---10 DIM a%(26)
20 PRINT"Please enter a string this program will then count the number of occurences of each letter in that string."
30 INPUT a$:a$=UPPER$(a$)
40 FOR i%=1 TO LEN(a$):m$=MID$(a$,i%,1)
50 PRINT m$
60 a%(ASC(m$)-64)=a%(ASC(m$)-64)+1
70 NEXT
80 PRINT"string was made of "
90 FOR i%=1 TO 26
100 IF a%(i%)>0 THEN PRINT a%(i%);" times ";CHR$(i%+64)
110 NEXT
--- End code ---

the graveborn:
@AMSDOS Thank you for your reply! I think I already knew about everything that you wrote about - eg., I already knew about the built-in Rx variables, although those aren't how I've been intermixing machine code and Pascal - I've posted below a proof-of-concept of my (likely bad...) idea for intermixing machine code and Pascal using arrays and the built-in ADDR function and POKE and USER procedures; my (better, but still likely bad...) idea was for the executable to read machine code from file at run-time, thus - amongst other things - reducing the size of the source code and the size of the executable, as it isn't necessary to have line after line after... of calls to the POKE procedure; I've now put together quick-and-(very...)dirty functions for file handling (again intermixing machine code and Pascal), and I'll try to post them "soon"...

On that topic, do you know if the Z80 in the Amstrad CPC supports the IX (#DDxx) instructions? (If you don't know, I'll perform an experiment to determine if it does or doesn't.) I ask as I discovered that the Z80 in the Amstrad CPC seems not to support the bit (#CBxx) instructions. (I'm using the tables here for reference.)

PoC.pas:


--- Code: ---(*$C-*)

(* This program is a proof-of-concept that demonstrates using `HiSoft Pascal *)
(* Amstrad CPC464` to intermix machine code and Pascal using arrays and the  *)
(* built-in `ADDR` function and `POKE` and `USER` procedures.                *)

(* This program interrogates the state of joystick #0.                       *)

PROGRAM PoC (* "Proof-of-Concept" *) ;

CONST
 kMCLength = 31;

TYPE
 tJoystick = ARRAY [ 0..5 ] OF BOOLEAN;
 (* Bit/index: Meaning:      *)
 (* 0          d-pad up      *)
 (* 1          d-pad down    *)
 (* 2          d-pad left    *)
 (* 3          d-pad right   *)
 (* 4          fire button 2 *)
 (* 5          fire button 1 *)
 tPositiveInteger = 1..MAXINT;
 tJoystickAxisDirection = -1..1;
 tJoystickButton = 1..2;

VAR
 MCOffset, MCAddress : INTEGER;
 MC : ARRAY [ 1..kMCLength ] OF CHAR;
 joystick0 : tJoystick;
 jumpAddress, callAddress : INTEGER;
 first : BOOLEAN;
 oldJoystick0 : tJoystick;
 i : 0..6;

PROCEDURE pPokeMC( value : INTEGER; sizeOfValue (* in bytes *) :
                   tPositiveInteger );
BEGIN
 IF MCOffset + sizeOfValue > kMCLength THEN BEGIN
  WRITE( 'Sorry, an error occurred: too much machine code has already been ' );
  WRITELN( '`POKE`''d (`MCOffset` + `sizeOfValue` > `kMCLength`).' );
  HALT
 END;
 POKE( MCAddress + MCOffset, value );
 MCOffset := MCOffset + sizeOfValue
END;

FUNCTION fJoystickStateChanged( a, b : tJoystick ) : BOOLEAN;
VAR
 returnValue : BOOLEAN;
 i : 0..6;
BEGIN
 returnValue := FALSE;
 i := 0;
 WHILE NOT returnValue AND ( i <= 5 ) DO BEGIN
  returnValue := a[ i ] <> b[ i ];
  i := i + 1
 END;
 fJoystickStateChanged := returnValue
END;

FUNCTION fJoystickAxisDirection( joystick : tJoystick; axis : CHAR ) :
         tJoystickAxisDirection;
VAR
 p, n : 0..3;
 returnValue : tJoystickAxisDirection;
BEGIN
 IF axis IN [ 'x', 'X' ] THEN BEGIN
  p := 3;
  n := 2
 END ELSE BEGIN
  p := 0;
  n := 1
 END;
 IF NOT joystick[ p ] AND NOT joystick[ n ] THEN
  returnValue := 0
 ELSE
  IF joystick[ p ] AND joystick[ n ] THEN
   returnValue := 0
  ELSE
   IF joystick[ p ] THEN
    returnValue := 1
   ELSE
    returnValue := -1;
 fJoystickAxisDirection := returnValue
END;

PROCEDURE pWriteJoystickButtonState( joystick : tJoystick; button :
          tJoystickButton );
VAR
 i : 4..5;
BEGIN
 IF button = 1 THEN
  i := 5
 ELSE
  i := 4;
 WRITE( ' Fire button #', button:0, ': ' );
 IF NOT joystick[ i ] THEN
  WRITE( 'up' )
 ELSE
  WRITE( 'down' );
 WRITELN
END;

BEGIN
 MCAddress := ADDR( MC );
 MCOffset := 0;

 pPokeMC( #CD, 1 );   (* call ** *)
 pPokeMC( #BB24, 2 ); (* address #BB24 *)
 pPokeMC( #57, 1 );   (* ld d, a *)
 pPokeMC( #06, 1 );   (* ld b, * *)
 pPokeMC( #01, 1 );   (* value #01 *)
 pPokeMC( #0E, 1 );   (* ld c, * *)
 pPokeMC( #06, 1 );   (* value #06 *)
 pPokeMC( #21, 1 );   (* ld hl, ** *)
 pPokeMC( ADDR( joystick0 ), 2 );

 jumpAddress := MCAddress + MCOffset;

 pPokeMC( #36, 1 );   (* ld (hl), * *)
 pPokeMC( #00, 1 );   (* value #00 *)
 pPokeMC( #7A, 1 );   (* ld a, d *)
 pPokeMC( #A0, 1 );   (* and b *)

 pPokeMC( #C4, 1 );   (* call nz, ** *)
 callAddress := MCAddress + MCOffset;
 pPokeMC( #DEAD, 2 ); (* placeholder address *)

 pPokeMC( #78, 1 );   (* ld a, b *)
 pPokeMC( #87, 1 );   (* add a, a *)
 pPokeMC( #47, 1 );   (* ld b, a *)
 pPokeMC( #0D, 1 );   (* dec c *)
 pPokeMC( #23, 1 );   (* inc hl *)
 pPokeMC( #C2, 1 );   (* jp nz, ** *)
 pPokeMC( jumpAddress, 2 );

 pPokeMC( #C9, 1 );   (* ret *)

 POKE( callAddress, MCAddress + MCOffset );
 pPokeMC( #36, 1 );   (* ld (hl), * *)
 pPokeMC( #01, 1 );   (* value #01 *)
 pPokeMC( #C9, 1 );   (* ret *)

 first := TRUE;
 WHILE TRUE DO BEGIN
  USER( MCAddress );
  IF first OR fJoystickStateChanged( joystick0, oldJoystick0 ) THEN BEGIN
   first := FALSE;
   oldJoystick0 := joystick0;
   PAGE;
   WRITELN( 'Joystick #0:' );
   FOR i := 0 TO 5 DO
    WRITELN( ' Bit #', i:0, ': ', joystick0[ i ] );
   WRITELN;
   WRITE( ' y-axis: ' );
   CASE fJoystickAxisDirection( joystick0, 'y' ) OF
    -1:WRITE( 'down' );
    0:WRITE( 'neutral' );
    1:WRITE( 'up' )
   END;
   WRITELN;
   WRITE( ' x-axis: ' );
   CASE fJoystickAxisDirection( joystick0, 'x' ) OF
    -1:WRITE( 'left' );
    0:WRITE( 'neutral' );
    1:WRITE( 'right' )
   END;
   WRITELN;
   pWriteJoystickButtonState( joystick0, 1 );
   pWriteJoystickButtonState( joystick0, 2 )
  END
 END
END.
--- End code ---

zhulien:

--- Quote from: SRS on 23:17, 03 July 19 ---Nice :)
Just made me quickhack it in good ol' loco:

--- Code: ---10 DIM a%(26)
20 PRINT"Please enter a string this program will then count the number of occurences of each letter in that string."
30 INPUT a$:a$=UPPER$(a$)
40 FOR i%=1 TO LEN(a$):m$=MID$(a$,i%,1)
50 PRINT m$
60 a%(ASC(m$)-64)=a%(ASC(m$)-64)+1
70 NEXT
80 PRINT"string was made of "
90 FOR i%=1 TO 26
100 IF a%(i%)>0 THEN PRINT a%(i%);" times ";CHR$(i%+64)
110 NEXT
--- End code ---

--- End quote ---


I remember a guy trying to tutor this in YouTube and saying how such logic is really bad and instead was coming up with a faster logic that uses more memory but less iterations.  I told him, he shouldn't be teaching his students that one method was bad without reason because if the goal is to conserve memory or eg: run on a CPC in BASIC, then such a solution like yours is very good.  Sad when lecturers assume a single target platform when teaching algorithms.

Navigation

[0] Message Index

[#] Next page

Go to full version
Powered by SMFPacks Media Embedder
Powered by SMFPacks Alerts Pro Mod
Powered by SMFPacks Mentions Pro Mod