aboutsummaryrefslogtreecommitdiff
path: root/challenge-094/paulo-custodio/forth/ch-2.fs
blob: 271615bf0524d32a2e9a1f619e28b92b98606cd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#! /usr/bin/env gforth

\ Challenge 094
\
\ TASK #2 � Binary Tree to Linked List
\ Submitted by: Mohammad S Anwar
\ You are given a binary tree.
\
\ Write a script to represent the given binary tree as an object and flatten
\ it to a linked list object. Finally print the linked list object.
\
\ Example:
\   Input:
\
\       1
\      / \
\     2   3
\    / \
\   4   5
\      / \
\     6   7
\
\   Output:
\
\       1 -> 2 -> 4 -> 5 -> 6 -> 7 -> 3

80 CONSTANT MAXLINE
10 CONSTANT '\n'

\ -----------------------------------------------------------------------------
\ read lines from stdin and store them in dictionary
0 VALUE num_lines

: ,line                     { src len -- }
    HERE                    ( dest )
    len ALLOT               \ reserve space
    src SWAP len CMOVE      \ copy to space
    '\n' C,                 \ append line terminator
;

: ,lines
    BEGIN
        PAD DUP MAXLINE STDIN READ-LINE THROW
    WHILE
        ,line
        num_lines 1+ TO num_lines
    REPEAT
    2DROP
;

CREATE lines ,lines

\ get start of row
: row[]                     ( row -- row-addr )
    lines SWAP              ( lines row )
    0 ?DO                   \ loop for rows
        BEGIN DUP C@ '\n' <> WHILE  \ find end of each row
            1+
        REPEAT
        1+
    LOOP
;

\ advance from start of row to column
: col[]                     ( row-addr col -- char-addr )
    0 ?DO
        DUP C@ '\n' <> IF
            1+              \ increment unless end of line
        THEN
    LOOP
;

\ get address of character at row, col
: lines[][]                 ( row col -- addr )
    SWAP row[]
    SWAP col[]
;

\ get character at row, col
: char[][]                  ( row col -- char )
    lines[][] C@
;

: char[][]isdigit           ( row col -- f )
    char[][]
    DUP '0' >= SWAP '9' <= AND
;

: char[][]isnewline         ( row col -- f )
    char[][]
    '\n' =
;

\ -----------------------------------------------------------------------------
\ Representation of a tree

: new_node                  ( -- node )
    HERE 0 , 0 , 0 ,
;

: node.value                ( node-addr -- value-addr )
;

: node.left                 ( node-addr -- left-addr )
    1 CELLS +
;

: node.right                ( node-addr -- right-addr )
    2 CELLS +
;

: parse_subtree             { row col -- node }
    new_node                ( node )
    row col char[][] '0' -  ( node value )
    OVER node.value !       \ store value
    row 2 + num_lines < IF  \ have children
        row 1+ col 1- char[][] '/' = IF \ have left child
            row 2 + col 2 - RECURSE     ( node child-node )
            OVER node.left !            \ store left subtree
        THEN
        row 1+ col 1+ char[][] '\' = IF \ have right child
            row 2 + col 2 + RECURSE     ( node child-node )
            OVER node.right !           \ store right subtree
        THEN
    THEN
;

: parse_tree                ( -- root )
    0                       ( col )
    BEGIN
        0 OVER              ( col row col )
        char[][]isdigit IF
            0 SWAP          ( row col )
            parse_subtree
            EXIT            ( node )
        THEN
        0 OVER
        char[][]isnewline IF
            1 THROW         \ root not found
        THEN
        1+                  ( col++ )
    AGAIN
;

\ -----------------------------------------------------------------------------
\ Flatten the tree
: flatten_tree          { root -- }
    root IF                     \ root not null
        root node.left @        ( left )
        DUP RECURSE             \ flatten left sub-tree

        root node.right @       ( left right )
        DUP RECURSE             \ flatten right sub-tree

        0 root node.left !      \ left = 0
        SWAP root node.right !  \ right = left; ( right )

        root                    ( right node )
        BEGIN DUP node.right @ WHILE
            node.right @
        REPEAT                  ( right rightmost-node )
        node.right !
    THEN
;

: print_tree    ( root )
    BEGIN ?DUP WHILE
        DUP node.value @ .
        DUP node.right @ IF ." -> " THEN
        node.right @
    REPEAT
    CR
;

parse_tree VALUE tree           \ parse tree, save root
tree flatten_tree               \ flatten the tree
tree print_tree
BYE