aboutsummaryrefslogtreecommitdiff
path: root/challenge-098/paulo-custodio/forth/ch-2.fs
blob: 7ad46a4d1e4cab25e991670e0c664eef0611642b (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
#! /usr/bin/env gforth

\ Challenge 098
\
\ TASK #2 � Search Insert Position
\ Submitted by: Mohammad S Anwar
\ You are given a sorted array of distinct integers @N and a target $N.
\
\ Write a script to return the index of the given target if found
\ otherwise place the target in the sorted array and return the index.
\
\ Example 1:
\ Input: @N = (1, 2, 3, 4) and $N = 3
\ Output: 2 since the target 3 is in the array at the index 2.
\ Example 2:
\ Input: @N = (1, 3, 5, 7) and $N = 6
\ Output: 3 since the target 6 is missing and should be placed at
\ the index 3.
\ Example 3:
\ Input: @N = (12, 14, 16, 18) and $N = 10
\ Output: 0 since the target 10 is missing and should be placed at
\ the index 0.
\ Example 4:
\ Input: @N = (11, 13, 15, 17) and $N = 19
\ Output: 4 since the target 19 is missing and should be placed at
\ the index 4.

\ output number without space
: .num              ( n -- )
    0 U.R
;

: str>number        ( str len -- n )
    S>NUMBER? 0= THROW DROP
;

: arg>number        ( -- n )
    NEXT-ARG str>number
;

\ list of numbers with max size and current size in first cell
: iarray.new        ( max-size -- ) \ creates a new word
    CREATE
    0 ,                             \ store size
    CELLS ALLOT                     \ allocate space
;

: iarray.size       ( arr -- size )
    @
;

: iarray.front      ( arr -- addr-of-first-elem )
    1 CELLS +
;

: iarray.back       ( arr -- addr-after-last-elem )
    DUP @ 1+ CELLS +
;

: iarray.push       { arr n -- }
    n arr iarray.back !
    1 arr +!
;

: iarray.elem       ( arr index -- addr )
    1+ CELLS +
;

: iarray.insert     { arr i n -- }
    arr i iarray.elem
    DUP
    DUP 1 CELLS +  arr iarray.size i - CELLS CMOVE>
    n SWAP !
    1 arr +!
;

: iarray.delete     { arr i -- }
    arr i iarray.elem
    DUP 1 CELLS + SWAP  arr iarray.size i - CELLS CMOVE
    -1 arr +!
;

: iarray.bsearch    { arr n -- i f-found}
    arr iarray.size 0= IF 0 FALSE EXIT THEN         \ array empty
    n  arr iarray.front @ < IF 0 FALSE EXIT THEN    \ before first
    n  arr iarray.back 1 CELLS - @ > IF             \ after last
        arr iarray.size FALSE EXIT
    THEN

    0                   { b }
    arr iarray.size     { t }
    0                   { m }
    BEGIN
        b t 1- <
    WHILE
        b t + 2 / TO m
        n  arr m iarray.elem @
        2DUP = IF 2DROP m TRUE EXIT ELSE        \ found
        < IF m TO t
        ELSE m TO b
        THEN THEN
    REPEAT
    t FALSE
;

: iarray.print      { arr -- }
    ." ("
    arr iarray.size 0 ?DO
        I 0> IF ." , " THEN
        arr I iarray.elem @ .num
    LOOP
    ." )"
;

100 iarray.new nums     \ array of numbers
0 VALUE n               \ number to find/insert

\ collect args
: collect-args      ( -- )
    arg>number TO n
    BEGIN
        NEXT-ARG DUP 0>
    WHILE
        str>number  nums SWAP iarray.push
    REPEAT 2DROP
;

\ search index and insert if not found
: search_index          ( -- i )
    nums n iarray.bsearch   { i f }
    f 0= IF     \ not found
        nums i n iarray.insert
    THEN
    i
;

collect-args
search_index .num CR
nums iarray.print CR
BYE