this program, in C and Pascal, has a 4 level nested search-repeat parse through a list.
This program was written back in the days of cassette tapes!: Screen I/O pgm in C & Pascal.
This program will go through a list of songs, throwing out one song or another until it finds a total time that most nearly matches the target time. It will display and write to a (text) file the new (sub) list and, separately, the song(s) that it threw out. What was surprising was that with only 1 or 2 extra songs, the program could almost always come within 5 sec. of the exact time!
back in 1985:
GIVEN: that many people enjoy recording their favorite records onto cassette tapes and playing them in their car tape players (as well as home tape decks) and do NOT enjoy the tape coming to the end in the middle of a song.
THEREFORE …
WRITE: A program that prompts for a target time (30:00 min 45:00 min., or even 33:28 min & sec etc.) and then prompts for
1. a number of seconds to be added between songs. (4 is common)
2. a string of about 30 to 35 characters. (a song title)
3. a number between 0 and 9 (minutes) and
4. a number between 0 and 59 (seconds) until only
1 or 2 more than enough to pass the total target time or end-of-data is encountered; whichever comes first.
If EOD is first, terminate the program with a message (not enough data).
The program has been written in Pascal (Borland’s Turbo Pascal) and
in C (compiled by both Borland’s Turbo C and MicroSoft’s C
C
#include /*-----------------------------------------------------------------*/ /* THIS 3RD VERSION DISPLAYS THE 1ST 20 */ /* SOLUTIONS BY DIRECTLY ADDRESSING THE SCREEN */ /*-----------------------------------------------------------------*/ /**------ E X T E R N A L D E C L A R A T I O N S ------**/ #define minimum_minutes 16 #define maximum_minutes 64 #define songsLimit 31 /* array from 0 to 30 */ #define titleLength 36 /* array from 0 to 35 */ #define displayLimit 31 /* array from 0 to 30 */ #define total_error_limit 40 /* seconds from target */ FILE *tapelog ; int TargetMinutes, songs ; int TargetSeconds, this_one ; int ttl_trgt_secs, this_song ; int subttl_Minutes, last_song = 0 ; int subttl_Seconds = 0, xtraSongs = 0 ; int subttl_in_secs = 0, xtraSeconds = 0 ; int out1, out3, limit = 0 ; int out2, out4, diff = 0 ; static char d_title [songsLimit] [titleLength+1] ; /* strings */ char *atitle [songsLimit] ; /* pointers to strings */ char astring [titleLength] ; /* an extra string */ char ch ; char test [11] ; int minutes [songsLimit] ; int seconds [songsLimit] ; int ttlsecs [songsLimit] ; int outtime [songsLimit] ; /* ---------------+----------------------------------+-------------- */ /* ---------------+ B E G I N P R O G R A M: +-------------- */ /* ---------------+----------------------------------+-------------- */ main () { union REGS r ; printf ("\n\n"); printf ("\t +------------------------------------------------------+ \n"); printf ("\t | M A K I N G A C A S S E T T E T A P E | \n"); printf ("\t +------------------------------------------------------+ \n"); printf ("\t Given that we enjoy recording our records onto tapes but \n"); printf ("\t we do NOT enjoy the tape coming to the end in the middle \n"); printf ("\t of a song, this program enables a person to . . . \n\n"); printf ("\t Enter a list of songs and their durations (min's & sec's) \n"); printf ("\t that total just over a required minimum, ex: 30 minutes, \n"); printf ("\t plus 1 more song. This program will then go through the \n"); printf ("\t list throwing out one song or another, until it finds a \n"); printf ("\t total time that most nearly matches the target time. It \n"); printf ("\t will then display the results. \n"); printf ("\t ( p.s. a 30 min. tape seems to last 31 min. & 30 sec.) \n"); printf ("\t ( a 45 min. tape seems to last 46 min. & 30 sec.) \n"); printf ("\t ( and add about 3 to 6 seconds between songs.) \n\n"); printf ("\t Please enter the total target time for one side : \n"); printf ("\t (between %d & %d min.) ( otherwise quit ) \n", minimum_minutes, maximum_minutes ); printf ("\t ( %d to %d ) MINUTES: ", minimum_minutes, maximum_minutes ); gets (astring); /* - - - - - - - - - - - - - - - - - - - - - - - - - */ /* a person normally verifies the data as valid */ /* before Ascii TO Integer conversion (atoi): */ /* - - - - - - - - - - - - - - - - - - - - - - - - - */ TargetMinutes = atoi (astring); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* the program terminates here unless the entry time is valid: */ /* (to be valid, the target minutes must be */ /* between minimum_minutes and maximum_minutes) */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if ( TargetMinutes >= minimum_minutes && TargetMinutes 60 ) printf ("\t Seconds must be between 0 and 60. \n"); } while ( TargetSeconds 60 ); ttl_trgt_secs = TargetMinutes * 60 + TargetSeconds ; printf ("\t Confirmed: %2d:%02d \n", TargetMinutes, TargetSeconds); printf ("\t Enter the number of seconds to be added \t\t default=4\n"); printf ("\t to the subtotal, between songs: (0-7): "); ch = getch(); switch ( ch ) { case '0' : xtraSeconds = 0 ; break ; case '1' : xtraSeconds = 1 ; break ; case '2' : xtraSeconds = 2 ; break ; case '3' : xtraSeconds = 3 ; break ; case '4' : xtraSeconds = 4 ; break ; case '5' : xtraSeconds = 5 ; break ; case '6' : xtraSeconds = 6 ; break ; case '7' : xtraSeconds = 7 ; break ; default : xtraSeconds = 4 ; } printf ("%1d \n\n", xtraSeconds ) ; /* ----------------------------------------------------------- */ /* E N T E R T H E D A T A */ /* ----------------------------------------------------------- */ last_song = 0 ; /* get the 1st title and set it */ /* = to last_song if it verifies */ getTitle() ; /* - - - - - - - - main loop - - - - - - - - - */ /* While the title is not null, the array */ /* limit has not been over-extended, and we */ /* have not entered more than 2 extra songs, */ /* - - - - - - Enter another song - - - - - - - */ while ( strlen(d_title[last_song + 1]) != 3 && xtraSongs %2d:%02d \n" , subttl_Minutes, subttl_Seconds , TargetMinutes, TargetSeconds ); if ( ttl_trgt_secs 1 ) { display_song_list(); /* display on screen */ /* ------------------------------------------------------------- */ /* WRITE LIST TO FILE (TAPE-LOG) */ /* ------------------------------------------------------------- */ if ( ( tapelog = fopen ( "tape-log", "a") ) != NULL ) { fprintf (tapelog, "\n\n\n ================================ \n" ); fprintf (tapelog, " -- -- A FULL LISTING -- -- \n" ); fprintf (tapelog, " ================================ \n" ); for ( this_song=1; this_song ttl_trgt_secs ) diff = outtime[out1] - ttl_trgt_secs ; else diff = ttl_trgt_secs - outtime[out1] ; /* diff = abs ( outtime[out1] - ttl_trgt_secs ); */ if ( diff == limit ) display_songs() ; /* - - - - - - - - - - - - - - - - - - - - - - - - */ /**** see if throwing out 2 songs will do ****/ /* - - - - - - - - - - - - - - - - - - - - - - - - */ for ( out2 = out1+1 ; out2 1 ) */ } /* if ( TargetMinutes > minimum_minutes && ... */ } /* main */ /* ------------------------------------------------------------------ */ /* ------------------- ( E N D P R O G R A M ) ---------------- */ /* ------------------------------------------------------------------ */ /* */ /* ------------------------------------------------------------------ */ /* -------------- ( B E G I N S U B R O U T I N E S ) ----------- */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ r.h.ah = 15 ; /* gets video mode */ vmode = int86(0x10, &r, &r) & 255 ; getTitle() /* - - - - - - - G E T T I T L E - - - - - - - - */ { int length ; printf ("\t Enter a song title (not 3 char's.) ", titleLength ); printf (" (or Enter xxx to quit) \n |"); for ( length = 1; length 6 ) printf (" 1 to 6 \b\b\b\b\b\b\b\b\b\b\b\b"); } while ( Minutes 6 ); /* end do...while */ printf ("%1d: \b\b\b\b\b\b\b\b\b\b", Minutes ) ; return (Minutes); } /* ------------------------------------------------------------------ */ getSeconds() /* - - - - - - G E T S E C O N D S - - - - - - - */ { int Seconds; char string[4]; do { gets (string); Seconds = atoi (string); if ( Seconds 60 ) printf ("\t Seconds must be between 0 and 60 : "); } while ( Seconds 60 ); return (Seconds); } /* ------------------------------------------------------------------ */ display_songs() /* - - - - - D I S P L A Y S O N G S - - - - - */ { subttl_in_secs = 0 ; for ( this_one = 1; this_one %2d. %2d.Turbo PASCAL
{==================================} PROGRAM MUSIC ; {==================================} {--------------------- CONSTANTS ---------------------} const songs_limit = 40; { number of songs that can be entered } title_length = 35; { title string length limit; char's. } type a_song_rec = record title : string[title_length]; time : integer; minutes : integer; seconds : integer; cut_tim1 : integer; { time without this song } end; all_the_songs = array[1..songs_limit] of a_song_rec; {---------------- VARIABLES ----------------} var atitle : string[title_length]; asong : all_the_songs; ch : char; songs : integer; LastSong : integer; this_song : integer; xtraSongs : integer; xtraSeconds : integer; target_min : integer; target_sec : integer; subttlMin : integer; subttlSec : integer; subttlTim : integer; xx, yy, zz : integer; limit, diff : integer; ttl_target_sec : integer; out1, out2, out3, out4 : integer; {---------------------------- PROCEDURE -------------------------------} PROCEDURE Read_a_Title ; begin atitle[0] := chr(title_length); for xx := 1 to title_length do aTitle[xx] := ' ' ; repeat Write (' || Enter A Blank Title To End'); Write (' ',LastSong+1:2,' '); Readln ( aTitle ); if ( (atitle[0] = chr(1)) or (atitle[0] = chr(2)) ) then Writeln ('A title must be more than 2 characters. '); until ( (atitle[0] chr(1)) and (atitle[0] chr(2)) ) end; { Read_a_Title }{ } {-------------------------------------------------------------------} PROCEDURE get_the_minutes (ThisOne : integer) ; begin repeat Write (' 1 to 6 Minutes: '); Readln (aSong[ThisOne].minutes); until (aSong[ThisOne].minutes >= 1 ) and (aSong[ThisOne].minutes = 0) and (aSong[ThisOne].seconds out1) and (this_one out2) and (this_one out3) and (this_one out4) ) then begin Write (this_one:2, '. '); Write (aSong[this_one].minutes:2 , ':'); Write (aSong[this_one].seconds:2 , ' '); Write (aSong[this_one].title); Writeln; subttlTim := subttlTim + aSong[this_one].time ; end; end ; {for} subttlSec := subttlTim mod 60; subttlMin := subttlTim div 60; Write ( subttlMin:8, ':', subttlSec:2, ' = total time '); Writeln; Writeln; Writeln; Write (' Off target by ', subttlTim - ttl_target_sec, ' sec''s. '); Writeln (' target time = ', target_min:2, ':', target_sec:2); { -------- now print the cast-out(s) -------- } Writeln (' --- these were not used: --- '); for this_one := 1 to LastSong do begin if ( (this_one = out1) or (this_one = out2) or (this_one = out3) or (this_one = out4) ) then begin Write (this_one:12, '. '); Write (aSong[this_one].minutes:2 , ':'); Write (aSong[this_one].seconds:2 , ' '); Write (aSong[this_one].title); Writeln; end; end ; {for} Writeln (' ............................................... '); Writeln (' --- hit Enter to continue --- or ^C to quit '); Write (' or prt-scrn if you wish; ... then {Enter} '); READln (ch); Writeln ; end; { display_Songs } {-------------------------------------------------------------------} { M A I N P R O G R A M } {-------------------------------------------------------------------} begin for xx := 1 to songs_limit do for yy := 1 to title_length do asong[xx].title[yy] := ' ' ; Writeln (' M A K I N G A C A S S E T T E T A P E '); Writeln (' ---------------------------------------------- '); Writeln (' Given that we enjoy recording our records onto tapes but '); Writeln (' we do NOT enjoy the tape coming to the end in the middle '); Writeln (' of a song, this program enables a person to . . . '); Writeln (' Enter a list of songs and their durations (min''s & sec''s)'); Writeln (' that total just over a required minimum, ex: 30 minutes, '); Writeln (' plus 1 more song. This program will then go through the '); Writeln (' list throwing out one song or another, until it finds a '); Writeln (' total time that most nearly matches the target time. It '); Writeln (' will then display the results. '); Writeln (' ( p.s. a 30 min. tape seems to last 31 min. & 30 sec.) '); Writeln (' ( a 45 min. tape seems to last 46 min. & 30 sec.) '); Writeln (' ( and add about 3 to 6 seconds between songs?) '); Writeln; Writeln (' Please enter the total target time for one side : '); Writeln (' (between 16 & 64 min.) ( otherwise quit ) '); Write (' ( 16 to 64 ) Minutes: '); readln (target_min); if ( target_min >= 16 ) and ( target_min = 0) and (target_sec 7 ) or ( xtraSeconds = 0 ) ; { ------------------------------------------------------ } { enter the data } { ------------------------------------------------------ } subttlTim := 0 ; subttlMin := 0 ; subttlSec := 0 ; xtraSongs := 0 ; LastSong := 0 ; Read_a_title; While ( aTitle[0] chr(0) ) and ( xtraSongs ' ); Write ( target_min :2); Writeln (':', target_sec :2); if ttl_target_sec 0 then { ------------------------ } begin { Make the Trades } for xx := 1 to lastSong do { ------------------------ } begin { cut_tim1 is the subtotal without that song } asong[xx].cut_tim1 := subttlTim - asong[xx].time; end; limit := -1 ; repeat out1 := 0; out2 := 0; out3 := 0; out4 := 0; limit := limit + 1 ; for out1 := 1 to lastSong do begin { see if throwing out 1 song will work: } diff := ABS(asong[out1].cut_tim1 - ttl_target_sec); if (diff = limit) then display_songs; { see if throwing out 2 songs will work. } { out1+1 you can't throw "out1" out twice } for out2 := out1+1 to lastSong do begin diff := ABS(asong[out1].cut_tim1 - asong[out2].time - ttl_target_sec) ; if (diff = limit) then display_songs; { --- see if throwing out 3 songs will work: --- } for out3 := out2+1 to lastSong do begin diff := ABS(asong[out1].cut_tim1 - asong[out2].time - asong[out3].time - ttl_target_sec); if (diff = limit) then display_songs; { see if throwing out 4 songs will work: } for out4 := out3+1 to lastSong do begin diff := ABS(asong[out1].cut_tim1 - asong[out2].time - asong[out3].time - asong[out4].time - ttl_target_sec); if (diff = limit) then display_songs; end; { for out4 } out4 := 0 ; end; { for out3 } out3 := 0 ; end; { for out2 } out2 := 0 ; end; { for out1 } until limit > 40 ; Writeln (' THIS PROGRAM STOPS at +/- 40 '); Writeln (' seconds of the target time. '); end; { make the trades ... IF extra songs > 0 } end { if target is between 16 & 64 } else begin Writeln (' Program terminated normally. '); end; End. { PROGRAM MUSIC }