Monday, February 17, 2020

PC/370 Word Search Analyzer


My Obsessive Compulsive Disorder (OCD) kicked in last Thursday after a Technology Townhall conference call. Typically, to make the call more interesting, a puzzle or mind teaser is emailed to the distribution list and the first to return it completed wins a $25 gift card. This month's "challenge" was a Word Search in a 30 x 30 grid. I was busy with other matters so I passed on the mundane task of straining my eyes in the search for character patterns going up, down & diagonal - forwards and backwards. My immediate thought was to automate the banal activity. Feed the grid & search words into a program & let it do all the work for me. That seems like more of a challenge...

That night I woke up at 3am (courtesy of my pups) & thanks to my OCD, couldn't get the grid algorithm out of my head. Horizontal is a no brainer, vertical & diagonals require positional plotting & extraction for dynamic comparison string building. The picture in my head became clear...

The perfect language would be PC/370 due to the necessity of tables, indexes, counts & displacements. I stopped coding in Assembler in 1996 - but my skills are still very sharp & very quick. My most valuable tool is my brain (though at times my wife would dispute my assessment).

I carved out a little time Friday night & early Saturday morning and it was done... Testing on several word search puzzles was successful! Here are the results...





The original Townhall Word Search was a Valentine's theme. For this blog post I created something special - a Mainframe / Assembler theme. 54 search words hidden within a 30 x 30 grid. You can create your own puzzles using the Free Word Search Puzzle Maker. See link below.

Free Word Search Puzzle Maker - CLICK HERE

After creating the puzzle on the Free Puzzle Maker page I formatted the output below. (This is not the input to the program - it's just a nice visual of  the Word Search puzzle). It has the grid on the left with the search words on the right. In honor of Donald Higgins I added his name to the list. He's the creator of the PC/370 Assembler Emulator I'm running on my PC.

First I'll post the Sample Puzzle, the Calculated Results followed by the general Algorithm Methodology, the program INPUT file & finally the full TDPUZZLE.ALC Source Code.

SAMPLE PUZZLE - Mainframe/Assembler Theme

You can print it & try to solve yourself. Have fun...



Spoiler Alert - Solved puzzle output below.

Output - Solved Puzzle

This is an actual snapshot of the TDPUZZLE output. The Result Grid is displayed next to the original version. Horizontal, vertical, diagonal (up/down) - forward & backwards. All detected & displayed.


In addition the Word Search List is displayed with various statistics. B/F designates if the word was discovered backward or forward. The mode represents the virtual axis - H=Horizontal, V=Vertical, D=Diagonal Down or U=Diagonal Up. The word length along with the absolute position (001 thru 900). The Row & Column positions are also included. If a word is not found only the name & length are shown.

Note the display below has been altered to save space. It shows two sets of words side by side - the actual output is displayed in a single long list.


Algorithm Methodology

This exercise is somewhat abstract - there can be no direct character comparisons for vertical & diagonal evaluations. The horizontal planes can be accessed & compared directly since it's a string of sequential values. The constraint of rows & columns determine if there's enough room to make a comparison. For example, a 5 character search word cannot be tested past column 26. This is standard string comparison.

The other critical point is that there is no meaningful "Backward" search - that would be completely unnecessary. As the search words are read from the input file they are loaded into a table. This table holds the values mentioned above (string, length, statistics) as well as a reversed copy of the string. Every time a compare is performed an additional compare using the reversed version is also performed (if needed). For example, the word GENIUS is stored along with the reverse SUINEG. This makes life so much simpler than adding pointless convoluted code.

Of course, there's other approaches to solve this puzzle. This is strictly my solution. It was developed quickly, accurately & takes seconds to complete on my PC.

Below is a simulated grid in Excel - 30 rows & 30 columns - positions 1 thru 900. This represents the natural state of the grid as well as the Horizontal search. A contiguous search may be performed on a row by row basis starting with column 1 thru column 30 (the positions increment by 30 with each row). You can see the vertical & diagonal positions line up much differently. *Prior to coding I created 4 tables in Excel for each mode (H/V/D/U) - adding the function to populate the cells helped me to quickly understand the positional relationships. Horizontal is shown below - I'll use the actual values generated from the program to display the other positions.


The vertical & diagonal grids aren't as simple. The positions are not sequential so the data cannot be compared directly. I use a table to normalize the rows & calculate the precise positions of each character to compare. The VERTICAL output below is printed from the actual table used in the program. The vertical search structure traverses 30 rows & 30 columns of positional values.



The Diagonal Up & Down positonal values are displayed below. Again, these were directly printed from the TDPUZZLE tables (all of which matched the Excel preliminary mappings). Each position represents the location of a character in the grid. These positions are used to extract characters & build a dynamic string equal to the length of the search word. If the comparison (forward or backward) is equal then we have a match - otherwise the pointer is bumped to start fresh.The diagonal search structure traverses 59 rows of data with the columns varying from 1 to 30 then back down to 1 again. Depending on the direction the positional values beyond the first column either increase by 31 or decrease by 29 until the "arrow point" is formed on the right.


PROGRAM INPUT - TDPUZZLE.TXT

Below is the formatted input to the program. The grid has no spaces - it's raw data. Then the search words appear with the prefix "WORD:". That's all that is needed. Grids can be less than 30 x 30.

REMMARGORPIRCNOPBBIWADDRESSICI
ORZFWAHITQRVIPRNAELOOBEPRCPONQ
CZCTNATSNOCICNKGTCNHJMANVCBNZW
TRCSKILLTKYZSVDRJSVFGRWAQOTLJX
ATQKVIYLTUKFNRHOLCVCTTMLLFBGDD
BHDCZFNMCDPHOKSSLBQICCVMABVEEO
LMSRETSIGERWBHSEGSTPCEWTMGVBRN
ENKQNMIQEREBITIEVIXRZSHVIPUECA
OEDSFAHFVLJFKTGDODDZJCMUCGEJWL
OMAKECLKBUTSXABNCLDLHGHQEAAAID
IOOEZRZUFYAUUYMISRFHEMYFDJWSVH
INLPHOORFMRGHEMKOEBNBXMAAPMSTI
RIXAWDBSTVNXTALWCTIKYMOTXURESG
XCYTTSYIIALONYFUHUXNFEDEEDWMMG
GEMCRYBJLEQYELGOSPHUMMUNHXWBHI
PRJIAZFQOODTALDRWMMNGOLRCYHLEN
ZBATNNUJJGGHNHAONOLUUREAIATEUS
GQJESXLCTKOINWBPXCOUYYWWFRZRLR
SVENLXLLZXBECMAWZQCUVUODDVEAVP
TRHGAOWHVBDYBRNDISPLACEMENTSDR
CVTATROAJMKMABTPRZLGOUXKCQAONE
MLYMEVRVFDGMVLEBCDICLDQXNMLAOC
HGGZRWDBIWEEMNKKVMQKPYRBEDUATI
VYLINKAGETBOUNDARYEKKZFAIXCAQS
ARKYRNLTEUWKJYRAFPIUFREUCYLSPI
JARZIKJRAIEVIRTUALGLAHJRSHAZUO
ZNNAMSSEZFENNXIOLNFBXBRGYQCWKN
XIRWGEXPERTEMARFNIAMRGEBNXPNOI
TBKHEGAROTSBFUDADGWYRWSNKSRUUC
ASCIITAERAEVASMCQUSTHKJXDDVXNP
WORD:ABEND
WORD:ADDRESS
WORD:ASCII
WORD:ASSEMBLER
WORD:BINARY
WORD:BITMASK
WORD:BOOLEAN
WORD:BOUNDARY
WORD:BRAIN
WORD:CALCULATE
WORD:CICS
WORD:CNOP
WORD:COBOL
WORD:COMPUTER
WORD:CONSTANT
WORD:CSECT
WORD:DEBUG
WORD:DISPLACEMENT
WORD:DONALDHIGGINS
WORD:DOUBLEWORD
WORD:DYNAMIC
WORD:EBCDIC
WORD:EXPERT
WORD:FULLWORD
WORD:GENIUS
WORD:HALFWORD
WORD:HEXADECIMAL
WORD:JCL
WORD:LANGUAGE
WORD:LINKAGE
WORD:LOAD
WORD:LOGIC
WORD:MACRO
WORD:MAGNETICTAPE
WORD:MAINFRAME
WORD:MEMORY
WORD:MNEMONIC
WORD:MODULE
WORD:PARAMETERS
WORD:PARTITION
WORD:PRECISION
WORD:PROGRAMMER
WORD:PUNCHCARD
WORD:REGISTERS
WORD:SAVEAREA
WORD:SCIENCE
WORD:SHIFT
WORD:SKILL
WORD:STCM
WORD:STORAGE
WORD:TABLE
WORD:TRANSLATE
WORD:VIRTUAL
WORD:VSAM


MAIN PROCESSING LOGIC

A view of the main logic. Read the Input file & perform the PARSE routine for each record. The data will either populate the GRID or the SEARCH WORD list. At End-Of-File we begin the Search Process. First, the Horizontal Search (HSRCH) is performed. Next, the Vertical Positions are calculated (VPCALC) then the Vertical Search (VSRCH) is performed. Then the Diagonal Down Positions (DPCALC) are calculated then searched (DSRCH) followed by the Diagonal Up Positions (UPCALC) calculation then searched (DSRCH again). Then the results (RESULTS) are produced.

***********************************************************************
*        MAINLINE PROCEDURE                                           *
***********************************************************************
         PRINT NOGEN
*
         XFILI STDWKI                        OPEN INPUT  FILE
         XFILO STDWKO                        OPEN OUTPUT FILE
*
         LA    9,MAIN                        LOAD MAIN ADDRESS
         LA    8,LIST                        LOAD LIST ADDRESS
GETI     EQU   *
         XREAD IREC,80                       READ INPUT RECORD
         BNZ   EOFI                          EOF - EXIT ROUTINE
*
         BAL   6,PARSE                       PARSE INPUT RECORD
*
         B     GETI                          READ NEXT RECORD
EOFI     EQU   *
         MVI   0(8),X'FF'                    MARK END OF LIST
*
         BAL   6,HSRCH                       SEARCH HORIZONTAL
*
         BAL   6,VPCALC                      VERTICAL CALCULATION
         BAL   6,VSRCH                       SEARCH VERTICAL
*
         BAL   6,DPCALC                      DIAGONAL DOWN CALC
         MVI   XDIAG,C'D'                    DIAGONAL DOWN MODE
         BAL   6,DSRCH                       SEARCH DIAGONAL DOWN
*
         BAL   6,UPCALC                      DIAGONAL UP CALC
         MVI   XDIAG,C'U'                    DIAGONAL UP MODE
         BAL   6,DSRCH                       SEARCH DIAGONAL UP
*
         BAL   6,RESULTS                     PRINT RESULTS
*
         B     RETURN                        EXIT PROGRAM PLEASE
***********************************************************************


The positional calculations & comparing the search words to a dynamic string is the key. Greater details can be observed within the code. It's well formed, concise & well documented - despite being produced at a rapid pace. Enjoy!


TDPUZZLE.ALC - Full Source Code

         TITLE 'TDPUZZLE - PC/370 4.2 // DELIA'
***********************************************************************
*                                                                     *
*        MODULE:  TDPUZZLE.                                           *
*        AUTHOR:  TONY DELIA.                                         *
*          DATE:  02/14/2020.                                         *
*          DESC:  PC/370 WORD SEARCH PUZZLE ANALYZER.                 *
*          NOTE:  PC/370 RELEASE 4.2                                  *
*                                                                     *
***********************************************************************
         EJECT
***********************************************************************
*        T  D  P  U  Z  Z  L  E     P  R  O  G  R  A  M               *
***********************************************************************
TDPUZZLE START 0                             START PROGRAM
         STM   14,12,12(13)                  SAVE REGISTERS
         LR    12,15                         LOAD PROGRAM ENTRY POINT
         USING TDPUZZLE+0*4096,12            BASE REGISTER 1
         L     11,BASE2                      LOAD BASE REGISTER 2
         USING TDPUZZLE+1*4096,11            TELL ASSEMBLER ABOUT BASE2
         L     10,BASE3                      LOAD BASE REGISTER 3
         USING TDPUZZLE+2*4096,10            TELL ASSEMBLER ABOUT BASE3
         ST    13,SAVE+4                     SAVE EXTERNAL SAVE ADDRESS
         LR    14,13                         XFER ADDRESS TO TEMP R14
         LA    13,SAVE                       LOAD INTERNAL SAVE ADDRESS
         ST    13,8(14)                      SAVE IN EXTERNAL SAVE AREA
         B     GO                            BRANCH TO PROCESSING RTN
***********************************************************************
RETURN   EQU   *                             TIME TO RETURN
         L     13,SAVE+4                     RESTORE REGISTER 13
         LM    14,12,12(13)                  RESTORE REMAINING REGS
         SR    15,15                         CLEAR RETURN CODE
         BR    14                            BRANCH TO CALLING PROGRAM
***********************************************************************
SAVE     DC    18F'0'                        S A V E   A R E A
***********************************************************************
BASE2    DC    A(TDPUZZLE+1*4096)            BASE2 DISPLACEMENT
BASE3    DC    A(TDPUZZLE+2*4096)            BASE3 DISPLACEMENT
***********************************************************************
GO       EQU   *                             BEGIN PROCESSING ...
***********************************************************************
         EJECT
***********************************************************************
*        MAINLINE PROCEDURE                                           *
***********************************************************************
         PRINT NOGEN
*
         XFILI STDWKI                        OPEN INPUT  FILE
         XFILO STDWKO                        OPEN OUTPUT FILE
*
         LA    9,MAIN                        LOAD MAIN ADDRESS
         LA    8,LIST                        LOAD LIST ADDRESS
GETI     EQU   *
         XREAD IREC,80                       READ INPUT RECORD
         BNZ   EOFI                          EOF - EXIT ROUTINE
*
         BAL   6,PARSE                       PARSE INPUT RECORD
*
         B     GETI                          READ NEXT RECORD
EOFI     EQU   *
         MVI   0(8),X'FF'                    MARK END OF LIST
*
         BAL   6,HSRCH                       SEARCH HORIZONTAL
*
         BAL   6,VPCALC                      VERTICAL CALCULATION
         BAL   6,VSRCH                       SEARCH VERTICAL
*
         BAL   6,DPCALC                      DIAGONAL DOWN CALC
         MVI   XDIAG,C'D'                    DIAGONAL DOWN MODE
         BAL   6,DSRCH                       SEARCH DIAGONAL DOWN
*
         BAL   6,UPCALC                      DIAGONAL UP CALC
         MVI   XDIAG,C'U'                    DIAGONAL UP MODE
         BAL   6,DSRCH                       SEARCH DIAGONAL UP
*
         BAL   6,RESULTS                     PRINT RESULTS
*
         B     RETURN                        EXIT PROGRAM PLEASE
***********************************************************************
         EJECT
***********************************************************************
*        PARSE RECORD                        R9=MAIN R8=LIST          *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
PARSE    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         CLC   IREC(5),=CL5'WORD:'           SEARCH WORD ENTRY?
         BE    PARSEW                        YES - STORE ENTRY
*
PARSEBC  BC    0,PARSEX                      EXIT IF GRID FULL
*
         MVC   0(30,9),IREC                  STORE MAIN CHARACTERS
         LA    9,30(,9)                      BUMP TO NEXT ENTRY
         B     PARSEX                        EXIT PARSE ROUTINE
PARSEW   EQU   *
         OI    PARSEBC+1,X'F0'               TURN OFF GRID LOAD
*
         CLI   0(8),X'FF'                    END OF TABLE???
         BE    PARSEX                        YES - EXIT ROUTINE
*
         MVC   6(30,8),IREC+5                MOVE WORD ENTRY
         MVC   0(4,8),=XL4'00000000'         CLEAR POS/LEN
*
         LA    7,IREC+5                      LOAD WORD ADDRESS
PARSEL1  EQU   *
         CLI   0(7),C' '                     BLANK CHARACTER?
         BE    PARSEL1X                      YES - EXIT LOOP
         LA    7,1(,7)                       BUMP POSITION
         B     PARSEL1                       TEST NEXT CHARACTER
PARSEL1X EQU   *
         LR    6,7                           XFER END ADDRESS
         S     6,=A(IREC+5)                  CALCULATE WORD LENGTH
         STH   6,2(8)                        STORE WORD LENGTH
*
         LA    5,36(,8)                      LOAD REVERSE ADDRESS
PARSEL2  EQU   *
         BCTR  7,0                           DECREMENT POINTER
         MVC   0(1,5),0(7)                   MOVE WORD CHARACTER
         LA    5,1(,5)                       BUMP REVERSE POINTER
         BCT   6,PARSEL2                     LOOP UNTIL COMPLETE
*
         LA    8,66(,8)                      BUMP TO NEXT ENTRY
PARSEX   EQU   *
         L     6,PARSE-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        SEARCH - HORIZONTAL                                          *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
HSRCH    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    8,LIST                        LOAD LIST ADDRESS
HSRCH1   EQU   *
         CLI   0(8),X'FF'                    END OF TABLE???
         BE    HSRCHX                        YES - EXIT ROUTINE
*
         MVI   5(8),C'H'                     SET HORIZONTAL
         MVC   XFWD,6(8)                     LOAD STRING FORWARD
         MVC   XBWD,36(8)                    LOAD STRING BACKWARD
         LH    7,2(8)                        LOAD STRING LENGTH
         BCTR  7,0                           ADJUST STRING LENGTH
*
         LA    9,MAIN                        LOAD MAIN ADDRESS
         LA    3,30                          SET ROW COUNTER
HLOOP1   EQU   *
         LA    4,0(9)                        LOAD ROW ADDRESS
         LH    6,=Y(30)                      LOAD ROW LENGTH
         SH    6,2(8)                        SUBTRACT FIELD LENGTH
HLOOP2   EQU   *
         MVI   4(8),C'F'                     SET FLAG FORWARD
         EX    7,HSRCHEXF                    MATCH FORWARD?
         BE    HSRCHZZ                       MARK FOUND ENTRY
         MVI   4(8),C'B'                     SET FLAG BACKWARD
         EX    7,HSRCHEXB                    MATCH BACKWARD?
         BE    HSRCHZZ                       MARK FOUND ENTRY
         LA    4,1(,4)                       BUMP COLUMN ADDRESS
         BCT   6,HLOOP2                      TEST NEXT COLUMN
*
         LA    9,30(,9)                      BUMP MAIN ADDRESS
         BCT   3,HLOOP1                      SEARCH NEXT ROW
*
         MVI   4(8),C' '                     CLEAR DIRECTION
         MVI   5(8),C' '                     CLEAR ORIENTATION
         B     HSRCHB                        BUMP NEXT LIST ENTRY
HSRCHZZ  EQU   *
         LR    6,4                           LOAD MATCH ADDRESS
         S     6,=A(MAIN-1)                  SUBSTRACT MAIN ADDRESS
         STH   6,0(8)                        STORE POSITION VALUE
*
         LA    3,MAIN-1                      LOAD MAIN ADDRESS
         LA    4,RESULT-1                    LOAD RESULT ADDRESS
         AH    3,0(8)                        BUMP MAIN POINTER
         AH    4,0(8)                        BUMP RESULT POINTER
         EX    7,HSRCHMVC                    MOVE WORD TO RESULT
HSRCHB   EQU   *
         LA    8,66(,8)                      BUMP LIST POINTER
         B     HSRCH1                        TEST NEXT ENTRY
HSRCHX   EQU   *
         L     6,HSRCH-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
*
HSRCHEXF CLC   XFWD(0),0(4)                  COMPARE STRING FORWARD
HSRCHEXB CLC   XBWD(0),0(4)                  COMPARE STRING BACKWARD
HSRCHMVC MVC   0(0,4),0(3)                   MOVE WORD TO RESULT
***********************************************************************
         EJECT
***********************************************************************
*        SEARCH - VERTICAL                                            *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
VSRCH    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    8,LIST                        LOAD LIST ADDRESS
VSRCH1   EQU   *
         CLI   0(8),X'FF'                    END OF TABLE???
         BE    VSRCHX                        YES - EXIT ROUTINE
         CLI   4(8),C' '                     ALREADY FOUND???
         BNE   VSRCHB                        YES - BUMP TO NEXT
*
         MVI   5(8),C'V'                     SET VERTICAL CODE
         MVC   XFWD,6(8)                     LOAD STRING FORWARD
         MVC   XBWD,36(8)                    LOAD STRING BACKWARD
         LH    7,2(8)                        LOAD STRING LENGTH
         BCTR  7,0                           ADJUST STRING LENGTH
         STH   7,STRLEN                      STORE ADJUSTED LENGTH
*
         LA    4,30                          LOAD COLUMN COUNT
         SR    4,7                           ADJUST COLUMN COUNT
         STH   4,HALF                        SAVE ADJUSTMENT
*
         LA    3,30                          SET ROW COUNT       
         LA    5,TABX                        LOAD POINTER ADDRESS
VSLOOP1  EQU   *
         LH    4,HALF                        LOAD COLUMN ADJUSTMENT
         LR    6,5                           LOAD POINTER ADDRESS
VSLOOP2  EQU   *
         MVI   STRING,C' '                   MOVE BLANK TO STRING
         MVC   STRING+1(29),STRING           PROPAGATE THRU STRING
         LA    7,STRING                      POINT TO STRING
         LR    9,6                           SET LATEST POINTER
         LH    2,2(8)                        LOAD STRING LENGTH
         ST    9,FULL                        STORE TABLE POINTER
         MVC   0(2,8),0(9)                   STORE CURRENT POSITION
VSLOOP3  EQU   *
         LH    1,0(9)                        LOAD POSITION
         A     1,=A(MAIN-1)                  ADJUST REAL POSITION
         MVC   0(1,7),0(1)                   MOVE CHARACTER
         LA    7,1(,7)                       BUMP STRING ADDRESS
         LA    9,2(,9)                       BUMP POINTER ADDRESS
         BCT   2,VSLOOP3                     SHIFT NEXT COLUMN
*
         LH    7,STRLEN                      LOAD ADJUSTED LENGTH
         MVI   4(8),C'F'                     SET FLAG FORWARD
         EX    7,VSRCHEXF                    MATCH FORWARD?
         BE    VSRCHZZ                       MARK FOUND ENTRY
         MVI   4(8),C'B'                     SET FLAG BACKWARD
         EX    7,VSRCHEXB                    MATCH BACKWARD?
         BE    VSRCHZZ                       MARK FOUND ENTRY
*
         LA    6,2(,6)                       BUMP POINTER ADDRESS
         BCT   4,VSLOOP2                     BUMP TO NEXT COLUMN
*
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   3,VSLOOP1                     SEARCH NEXT ROW
*
         MVC   0(2,8),=Y(0)                  CLEAR POSITION
         MVI   4(8),C' '                     CLEAR DIRECTION
         MVI   5(8),C' '                     CLEAR ORIENTATION
         B     VSRCHB                        BUMP NEXT LIST ENTRY
VSRCHZZ  EQU   *
         LH    2,2(8)                        LOAD STRING LENGTH
         L     9,FULL                        RESTORE POINTER
VSLOOPF  EQU   *
         LH    1,0(9)                        LOAD POSITION
         A     1,=A(MAIN-1)                  ADJUST SOURCE POSITION
         LH    3,0(9)                        LOAD POSITION
         A     3,=A(RESULT-1)                ADJUST TARGET POSITION
         MVC   0(1,3),0(1)                   UPDATE RESULT TABLE
         LA    9,2(,9)                       BUMP POINTER ADDRESS
         BCT   2,VSLOOPF                     SHIFT NEXT COLUMN
VSRCHB   EQU   *
         LA    8,66(,8)                      BUMP LIST POINTER
         B     VSRCH1                        TEST NEXT ENTRY
VSRCHX   EQU   *
         L     6,VSRCH-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
*
VSRCHEXF CLC   XFWD(0),STRING                COMPARE STRING FORWARD
VSRCHEXB CLC   XBWD(0),STRING                COMPARE STRING BACKWARD
***********************************************************************
         EJECT
***********************************************************************
*        SEARCH - DIAGONAL UP/DOWN                                    *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
DSRCH    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    8,LIST                        LOAD LIST ADDRESS
DSRCH1   EQU   *
         CLI   0(8),X'FF'                    END OF TABLE???
         BE    DSRCHX                        YES - EXIT ROUTINE
         CLI   4(8),C' '                     ALREADY FOUND???
         BNE   DSRCHB                        YES - BUMP TO NEXT
*
         MVC   5(1,8),XDIAG                  SET DIAGONAL UP/DOWN
         MVC   XFWD,6(8)                     LOAD STRING FORWARD
         MVC   XBWD,36(8)                    LOAD STRING BACKWARD
         LH    7,2(8)                        LOAD STRING LENGTH
         BCTR  7,0                           ADJUST STRING LENGTH
         STH   7,STRLEN                      STORE ADJUSTED LENGTH
*
         LA    3,59                          SET ROW COUNT       
         LA    5,TABX                        LOAD POINTER ADDRESS
DSLOOP1  EQU   *
         LR    4,3                           XFER COLUMN COUNT
         CH    3,=Y(30)                      TOP HALF OF TABLE?
         BNH   DSLOOP1A                      NO  - CONTINUE PLEASE
         LH    4,=Y(60)                      SET ADJUSTMENT BASE
         SR    4,3                           ADJUST COLUMN COUNT
DSLOOP1A EQU   *
         CH    4,STRLEN                      COLUMN CAPACITY?
         BNH   DSLOOP2X                      LO  - SKIP THIS ROW
*
         SH    4,STRLEN                      ADJUST COLUMN COUNT
         STH   4,HALF                        SAVE ADJUSTMENT
         LR    6,5                           LOAD POINTER ADDRESS
DSLOOP2  EQU   *
         MVI   STRING,C' '                   MOVE BLANK TO STRING
         MVC   STRING+1(29),STRING           PROPAGATE THRU STRING
         LA    7,STRING                      POINT TO STRING
         LR    9,6                           SET LATEST POINTER
         LH    2,2(8)                        LOAD STRING LENGTH
         ST    9,FULL                        STORE TABLE POINTER
         MVC   0(2,8),0(9)                   STORE CURRENT POSITION
DSLOOP3  EQU   *
         LH    1,0(9)                        LOAD POSITION
         A     1,=A(MAIN-1)                  ADJUST REAL POSITION
         MVC   0(1,7),0(1)                   MOVE CHARACTER
         LA    7,1(,7)                       BUMP STRING ADDRESS
         LA    9,2(,9)                       BUMP POINTER ADDRESS
         BCT   2,DSLOOP3                     SHIFT NEXT COLUMN
*
         LH    7,STRLEN                      LOAD ADJUSTED LENGTH
         MVI   4(8),C'F'                     SET FLAG FORWARD
         EX    7,DSRCHEXF                    MATCH FORWARD?
         BE    DSRCHZZ                       MARK FOUND ENTRY
         MVI   4(8),C'B'                     SET FLAG BACKWARD
         EX    7,DSRCHEXB                    MATCH BACKWARD?
         BE    DSRCHZZ                       MARK FOUND ENTRY
*
         LA    6,2(,6)                       BUMP POINTER ADDRESS
         BCT   4,DSLOOP2                     BUMP TO NEXT COLUMN
DSLOOP2X EQU   *
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   3,DSLOOP1                     SEARCH NEXT ROW
*
         MVC   0(2,8),=Y(0)                  CLEAR POSITION
         MVI   4(8),C' '                     CLEAR DIRECTION
         MVI   5(8),C' '                     CLEAR ORIENTATION
         B     DSRCHB                        BUMP NEXT LIST ENTRY
DSRCHZZ  EQU   *
         LH    2,2(8)                        LOAD STRING LENGTH
         L     9,FULL                        RESTORE POINTER
DSLOOPF  EQU   *
         LH    1,0(9)                        LOAD POSITION
         A     1,=A(MAIN-1)                  ADJUST SOURCE POSITION
         LH    3,0(9)                        LOAD POSITION
         A     3,=A(RESULT-1)                ADJUST TARGET POSITION
         MVC   0(1,3),0(1)                   UPDATE RESULT TABLE
         LA    9,2(,9)                       BUMP POINTER ADDRESS
         BCT   2,DSLOOPF                     SHIFT NEXT COLUMN
DSRCHB   EQU   *
         LA    8,66(,8)                      BUMP LIST POINTER
         B     DSRCH1                        TEST NEXT ENTRY
DSRCHX   EQU   *
         L     6,DSRCH-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
*
DSRCHEXF CLC   XFWD(0),STRING                COMPARE STRING FORWARD
DSRCHEXB CLC   XBWD(0),STRING                COMPARE STRING BACKWARD
***********************************************************************
         EJECT
***********************************************************************
*        CALCULATE - VERTICAL POSITIONS                               *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
VPCALC   EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    2,HEX00                       LOAD SOURCE ADDRESS
         LA    3,1                           LOAD SOURCE LENGTH
         LA    4,TABX                        LOAD TARGET ADDRESS
         LA    5,1800*2                      LOAD TARGET LENGTH
         ICM   3,B'1000',HEX00               LOAD PAD CHARACTER
         MVCL  4,2                           INIT RECORD AREA
*
         LA    4,30                          LOAD ROW COUNT
         LA    5,TABX+(29*30*2)              LOAD LAST ROW
VPLOOP1  EQU   *
         STH   4,0(5)                        STORE ROW VALUE
         LA    3,29                          LOAD COLUMN OFFSET
         LR    6,5                           LOAD COLUMN POINTER
VPLOOP2  EQU   *
         LH    7,0(6)                        EXTRACT CELL VALUE
         AH    7,=Y(30)                      INCREMENT VALUE BY 30
         STH   7,2(6)                        STORE ADJACENT CELL
         LA    6,2(,6)                       BUMP TO NEXT COLUMN
         BCT   3,VPLOOP2                     CALCULATE NEXT COLUMN
*
         SH    5,=Y(30*2)                    DECREMENT ROW POINTER
         BCT   4,VPLOOP1                     CALCULATE NEXT ROW
VPCALCX  EQU   *
         L     6,VPCALC-4                    RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        CALCULATE - DIAGONAL DOWN POSITIONS                          *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
DPCALC   EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    2,HEX00                       LOAD SOURCE ADDRESS
         LA    3,1                           LOAD SOURCE LENGTH
         LA    4,TABX                        LOAD TARGET ADDRESS
         LA    5,1800*2                      LOAD TARGET LENGTH
         ICM   3,B'1000',HEX00               LOAD PAD CHARACTER
         MVCL  4,2                           INIT RECORD AREA
*
         LA    2,1                           INIT INCREMENT
         LA    4,30                          ASCENDING ROW COUNT
         LA    5,TABX                        LOAD FIRST ROW
DPLOOP1  EQU   *
         STH   4,0(5)                        STORE ROW VALUE
         LR    3,2                           LOAD COLUMN OFFSET
         LR    6,5                           LOAD COLUMN POINTER
DPLOOP2  EQU   *
         CH    3,=Y(1)                       COLUMN LIMIT REACHED??
         BNH   DPLOOP2X                      YES - EXIT LOOP NOW
*                      
         LH    7,0(6)                        EXTRACT CELL VALUE
         AH    7,=Y(31)                      INCREMENT VALUE BY 31
         STH   7,2(6)                        STORE ADJACENT CELL
         LA    6,2(,6)                       BUMP TO NEXT COLUMN
         BCT   3,DPLOOP2                     CALCULATE NEXT COLUMN
DPLOOP2X EQU   *
         AH    2,=Y(1)                       INCREMENT COLUMN INDEX
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   4,DPLOOP1                     CALCULATE NEXT ROW
*
         LA    4,29                          DESCENDING ROW COUNT
DPLOOP3  EQU   *
         LR    3,4                           LOAD COLUMN OFFSET
         LR    6,5                           LOAD COLUMN POINTER
         SH    6,=Y(30*2)                    DECREMENT ROW POINTER
         LH    7,0(6)                        EXTRACT CELL VALUE
         AH    7,=Y(30)                      INCREMENT VALUE BY 30
         STH   7,0(5)                        PUSH TO CURRENT ROW
         LR    6,5                           LOAD COLUMN POINTER
DPLOOP4  EQU   *
         CH    3,=Y(1)                       COLUMN LIMIT REACHED??
         BNH   DPLOOP4X                      YES - EXIT LOOP NOW
         LH    7,0(6)                        EXTRACT CELL VALUE
         AH    7,=Y(31)                      INCREMENT VALUE BY 31
         STH   7,2(6)                        STORE ADJACENT CELL
         LA    6,2(,6)                       BUMP TO NEXT COLUMN
         BCT   3,DPLOOP4                     CALCULATE NEXT COLUMN
DPLOOP4X EQU   *
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   4,DPLOOP3                     CALCULATE NEXT ROW
DPCALCX  EQU   *
         L     6,DPCALC-4                    RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        CALCULATE - DIAGONAL UP POSITIONS                            *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
UPCALC   EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    2,HEX00                       LOAD SOURCE ADDRESS
         LA    3,1                           LOAD SOURCE LENGTH
         LA    4,TABX                        LOAD TARGET ADDRESS
         LA    5,1800*2                      LOAD TARGET LENGTH
         ICM   3,B'1000',HEX00               LOAD PAD CHARACTER
         MVCL  4,2                           INIT RECORD AREA
*
         MVC   HALF,=Y(1)                    INIT HALF WORD
         LA    2,1                           INIT INCREMENT
         LA    4,30                          ASCENDING ROW COUNT
         LA    5,TABX                        LOAD FIRST ROW
UPLOOP1  EQU   *
         MVC   0(2,5),HALF                   STORE ROW VALUE
         LR    3,2                           LOAD COLUMN OFFSET
         LR    6,5                           LOAD COLUMN POINTER
UPLOOP2  EQU   *
         CH    3,=Y(1)                       COLUMN LIMIT REACHED??
         BNH   UPLOOP2X                      YES - EXIT LOOP NOW
*                      
         LH    7,0(6)                        EXTRACT CELL VALUE
         SH    7,=Y(29)                      DECREMENT VALUE BY 29
         STH   7,2(6)                        STORE ADJACENT CELL
         LA    6,2(,6)                       BUMP TO NEXT COLUMN
         BCT   3,UPLOOP2                     CALCULATE NEXT COLUMN
UPLOOP2X EQU   *
         LH    7,0(5)                        LOAD FIRST CELL VALUE
         AH    7,=Y(30)                      INCREMENT VALUE BY 30
         STH   7,HALF                        SAVE FOR NEXT ROW
         AH    2,=Y(1)                       INCREMENT COLUMN INDEX
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   4,UPLOOP1                     CALCULATE NEXT ROW
*
         LA    4,29                          DESCENDING ROW COUNT
UPLOOP3  EQU   *
         LR    3,4                           LOAD COLUMN OFFSET
         LR    6,5                           LOAD COLUMN POINTER
         SH    6,=Y(30*2)                    DECREMENT ROW POINTER
         LH    7,0(6)                        EXTRACT CELL VALUE
         AH    7,=Y(1)                       INCREMENT VALUE BY 1
         STH   7,0(5)                        PUSH TO CURRENT ROW
         LR    6,5                           LOAD COLUMN POINTER
UPLOOP4  EQU   *
         CH    3,=Y(1)                       COLUMN LIMIT REACHED??
         BNH   UPLOOP4X                      YES - EXIT LOOP NOW
         LH    7,0(6)                        EXTRACT CELL VALUE
         SH    7,=Y(29)                      DECREMENT VALUE BY 29
         STH   7,2(6)                        STORE ADJACENT CELL
         LA    6,2(,6)                       BUMP TO NEXT COLUMN
         BCT   3,UPLOOP4                     CALCULATE NEXT COLUMN
UPLOOP4X EQU   *
         AH    5,=Y(30*2)                    INCREMENT ROW POINTER
         BCT   4,UPLOOP3                     CALCULATE NEXT ROW
UPCALCX  EQU   *
         L     6,UPCALC-4                    RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        PRINT RESULTS                                                *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
RESULTS  EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVC   OPRT+6(7),=C'RESULTS'         MOVE HEADING 1
         MVC   OPRT+70(8),=C'ORIGINAL'       MOVE HEADING 2
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVI   OPRT+6,C'='                   MOVE CHARACTER
         MVC   OPRT+7(58),OPRT+6             PROPOGATE ON LINE
         MVI   OPRT+70,C'='                  MOVE CHARACTER
         MVC   OPRT+71(58),OPRT+70           PROPOGATE ON LINE
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVC   OPRT+5(60),SCALE              MOVE SCALE 1
         MVC   OPRT+69(60),SCALE             MOVE SCALE 1
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVI   OPRT+6,C'='                   MOVE CHARACTER
         MVC   OPRT+7(58),OPRT+6             PROPOGATE ON LINE
         MVI   OPRT+70,C'='                  MOVE CHARACTER
         MVC   OPRT+71(58),OPRT+70           PROPOGATE ON LINE
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         LA    4,RESULT                      LOAD RESULT ADDRESS
         LA    5,MAIN                        LOAD MAIN ADDRESS
         LA    3,30                          LOAD ROW COUNT
         ZAP   PACK,=P'0'                    INIT ROW COUNTER
RESULT1  EQU   *
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         AP    PACK,=P'1'                    INCREMENT ROW COUNTER
         UNPK  OPRT(3),PACK                  UNPACK ROW COUNTER
         OI    OPRT+2,X'F0'                  TURN ON ZONE BITS
*
         LA    6,30                          LOAD COLUMN COUNT
         LA    7,OPRT+6                      LOAD PRINT ADDRESS
RESULT2  EQU   *
         MVC   0(1,7),0(4)                   MOVE RESULT CHARACTER
         MVC   64(1,7),0(5)                  MOVE MAIN CHARACTER
         CLI   64(7),C' '                    BLANK CHARACTER?
         BNE   *+8                           NO  - CONTINUE PLEASE
         MVI   64(7),C'.'                    YES - SET TO DOT
         LA    4,1(,4)                       BUMP RESULT POINTER
         LA    5,1(,5)                       BUMP MAIN   POINTER
         LA    7,2(,7)                       BUMP PRINT  POINTER
         BCT   6,RESULT2                     BUMP TABLE POSITION
*
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         BCT   3,RESULT1                     PRINT NEXT ROW
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT RECORD
         MVC   OPRT(4),=C'WORD'              MOVE HEADING 1
         MVC   OPRT+30(3),=C'B/F'            MOVE HEADING 2
         MVC   OPRT+35(4),=C'MODE'           MOVE HEADING 3
         MVC   OPRT+41(3),=C'LEN'            MOVE HEADING 4
         MVC   OPRT+46(3),=C'POS'            MOVE HEADING 5
         MVC   OPRT+51(3),=C'ROW'            MOVE HEADING 6
         MVC   OPRT+56(3),=C'COL'            MOVE HEADING 7
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVC   OPRT(L'DASHES),DASHES         MOVE DASH LINE
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         LA    8,LIST                        LOAD ENTRY LIST
RESULT3  EQU   *
         CLI   0(8),X'FF'                    END OF TABLE???
         BE    RESULT3X                      YES - EXIT ROUTINE
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVC   OPRT(30),6(8)                 MOVE ORIGINAL STRING
         MVC   OPRT+30(1),4(8)               MOVE DIRECTION
         MVC   OPRT+35(1),5(8)               MOVE ORIENTATION
         LH    7,2(8)                        LOAD STRING LENGTH
         CVD   7,DUBB                        CONVERT TO DECIMAL
         UNPK  OREC+42(3),DUBB+6(2)          UNPACK STRING LENGTH
         OI    OREC+44,X'F0'                 TURN ON ZONE BITS
         MVI   OREC+42,C' '                  CLEAR LEADING ZERO
*
         CLI   4(8),C' '                     WORD NOT FOUND?
         BE    RESULTP                       YES - BYPASS STATS
*
         LH    7,0(8)                        LOAD STRING POSITION
         CVD   7,DUBB                        CONVERT TO DECIMAL
         UNPK  OREC+47(3),DUBB+6(2)          UNPACK STRING POSITION
         OI    OREC+49,X'F0'                 TURN ON ZONE BITS
*
         DP    DUBB,=P'30'                   DIVIDE POSITION BY 30
         CP    DUBB+6(2),=P'0'               REMAINDER = ZERO?
         BNE   *+14                          NO  - CONTINUE PLEASE             
         ZAP   DUBB+6(2),=P'30'              YES - SET COLUMN = 30
         B     *+10                          FORMAT PRINT LINE
         AP    DUBB(6),=P'1'                 INCREMENT ROW COUNT
*
         UNPK  OPRT+51(3),DUBB+4(2)          UNPACK ROW NUMBER
         OI    OPRT+53,X'F0'                 TURN ON ZONE BITS
         MVI   OPRT+51,C' '                  CLEAR LEADING ZERO
         UNPK  OPRT+56(3),DUBB+6(2)          UNPACK COL NUMBER
         OI    OPRT+58,X'F0'                 TURN ON ZONE BITS
         MVI   OPRT+56,C' '                  CLEAR LEADING ZERO
RESULTP  EQU   *
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         LA    8,66(,8)                      BUMP LIST POINTER
         B     RESULT3                       PRINT NEXT ENTRY
RESULT3X EQU   *
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         MVC   OPRT(L'DASHES),DASHES         MOVE DASH LINE
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT AREA
         XPRNT OREC,132                      WRITE OUTPUT RECORD
RESULTSX EQU   *
         L     6,RESULTS-4                   RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        WORKING STORAGE                                              *
***********************************************************************
DUBB     DC    D'0'                          DOUBLEWORD
FULL     DC    F'0'                          FULLWORD
HALF     DC    H'0'                          HALFWORD
STRLEN   DC    H'0'                          ADJUSTED LENGTH
PACK     DC    PL2'0'                        PACKED DATA FIELD
HEX00    DC    XL1'00'                       HEXIDECIMAL ZEROES
XDIAG    DC    CL1' '                        DIAGONAL UP/DOWN
STRING   DC    CL30' '                       DYNAMIC STRING FIELD
XFWD     DC    CL30' '                       STRING - FORWARD
XBWD     DC    CL30' '                       STRING - BACKWARD
SCALE    DS    0CL60                         SCALE - HEADINGS
         DC    CL20' 1 . . . 5 . . . .10'    SCALE -  1 THRU 10
         DC    CL20' . . . .15 . . . .20'    SCALE - 11 THRU 20
         DC    CL20' . . . .25 . . . .30'    SCALE - 21 THRU 30
DASHES   DS    0CL60
         DC    CL30'============================= '
         DC    CL30'===  ====  ===  ===  ===  === '
***********************************************************************
*        DATA CONTROL BLOCK SET UP                                    *
***********************************************************************
STDWKI   DC    CL64'C:\PC370\TDPUZZLE.TXT'
STDWKO   DC    CL64'C:\PC370\TDPUZZLE.OUT'
***********************************************************************
*        INPUT/OUTPUT AREAS                                           *
***********************************************************************
IREC     DC    CL80' '                       INPUT RECORD
OREC     DS    0CL133                        OUTPUT RECORD
OBLANK   DC    CL1' '                        OUTPUT BLANK
OPRT     DC    CL132' '                      OUTPUT PRINT AREA
***********************************************************************
         LTORG                               LITERAL POOL
***********************************************************************
*        COPYBOOKS                                                    *
***********************************************************************
         COPY  CPY/TDSVC.CPY                 COPYBOOK - SUPERVISOR
***********************************************************************
*        WORD SEARCH LIST                                             *
***********************************************************************
         CNOP  0,4                           FULLWORD ALIGNMENT
LIST     DC    70CL66' '                     WORD SEARCH LIST
         DC    XL1'FF'                       END OF WORD SEARCH LIST
***********************************************************************
*        MAIN TABLE                                                   *
***********************************************************************
         CNOP  0,4                           FULLWORD ALIGNMENT
MAIN     DC    900CL1'.'                     MAIN WORD SEARCH GRID
RESULT   DC    900CL1'.'                     SEARCH RESULT TABLE
         CNOP  0,4                           FULLWORD ALIGNMENT
TABX     DC    1800Y(0)                      VERTICAL/DIAGONAL MATRIX
***********************************************************************
WORD     DSECT
WPOS     DS    H                             WORD LOCATION
WLEN     DS    H                             WORD LENGTH
WDIR     DS    CL1                           WORD DIRECTION   F,B
WORI     DS    CL1                           WORD ORIENTATION H,V,D,U
WFWD     DS    CL30                          WORD TEXT FORWARD
WBWD     DS    CL30                          WORD TEXT BACKWARD
***********************************************************************
         END   TDPUZZLE


*NOTE - The TDSVC.CPY copybook call can be commented out. It's not referenced in the process. I always code this in case a @WTO Write To Operator command is required for testing.

This was much simpler than I thought it would be but still fun. Now I need another challenge...