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
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...