View difference between Paste ID: pbXLsJ1e and GgvWWm7P
SHOW: | | - or go back to the newest paste.
1
2
--# Main
3
-- Flood
4
5
function setup()
6
    if backup then backup("Flood 101") end
7
    parameter.integer("Size",10,30,15) --size of board
8
    parameter.action("Start",Start) --starts a new game
9
    parameter.integer("Moves_so_far",0,100,0)
10
    parameter.action("Undo",UndoMove)
11
    --set up palette of six colors
12
    colrs={color(255,0,0,255),  color(0,255,0,255),  color(0,0,255,255),
13
            color(255,255,0,255),color(255,0,255,255),color(0,255,255,255)}
14
    ss=readProjectData("Size") --read in user's last size selection
15
    if ss~=nil then Size=ss end --set size, if a saved value exists
16
    Start()
17
end
18
19
function Start()
20
    --create random 2D table of colors
21
    board={}--create 1D table
22
    for i=1,Size do --loop through columns
23
        --this is how you create a 2D table
24
        board[i]={} --as we start each new column, create an array of rows
25
        for j=1,Size do --choose random color for each square
26
            board[i][j]=tostring(math.random(1,6))
27
        end
28
    end
29
    state="RUNNING" --to tell draw the game has started
30
    Moves_so_far=0
31
    output.clear()
32
    lastMove=board[1][1]
33
    back=Backup()
34
    saveProjectData("Size",Size) --save user size selection
35
    currSize=Size
36
    print("Press a color at the bottom to change the bottom left hand cell to that color, along with all adjoining cells. Try to flood the whole table with one color in as few moves as possible.")
37
end
38
39
function draw()   
40
    background(200)
41
    --calculate the size of square we can fit on screen 
42
    local w=(HEIGHT-100)/currSize
43
    pushStyle()
44
    --draw table of colors
45
    local finished=true --see use below
46
    for x=1,currSize do
47
        for y=1,currSize do
48
            fill(colrs[tonumber(board[x][y])]) --set colour based on value in table 1-6
49
            rect(50+x*w-w,75+y*w-w,w,w) --draw square
50
            --if any of the squares are a different color, we haven't finished
51
            if board[x][y]~=board[1][1] then finished=false end
52
        end
53
    end
54
    --draw buttons for user to press, store button locations for touch detection
55
    button={}
56
    for i=1,6 do
57
        fill(colrs[i])
58
        --position button at bottom of screen
59
        local x,y,w,h=100*i,10,75,50
60
        rect(x,y,w,h)
61
        --save details of button position so we can trap touches
62
        button[i]={x=x,y=y,w=w,h=h}
63
    end
64
    popStyle()
65
    --if we've just finished, print a message
66
    if state~="FINISHED" then --we weren't finished last move
67
        if finished then --...but we are now
68
            state="FINISHED" 
69
            print("Finished in",Moves_so_far,"moves")
70
        end
71
    end
72
end
73
74
function touched(touch)
75
    --state has three values, BEGAN, MOVING and ENDED
76
    --we only want ENDED, ie when the finger lifts up
77
    if touch.state~=ENDED then return end
78
    --check touch postiion against each button
79
    --that's why we stored all that info about button position
80
    for i=1,6 do
81
        if touch.x>=button[i].x and touch.x<=button[i].x+button[i].w
82
        and touch.y>=button[i].y and touch.y<=button[i].y+button[i].h then
83
            --only react if the user has chosen a different color
84
            if tonumber(board[1][1])~=i then 
85
                back:store(board)
86
                fillBoard(tostring(i))
87
                Moves_so_far = Moves_so_far + 1
88
            end
89
            break
90
        end
91
    end
92
end
93
94
function UndoMove()
95
    board=back:restore() or board
96
    Moves_so_far = math.max(0,Moves_so_far - 1)
97
end
98
99
--this is a recursive function that calls itself
100
function fillBoard(c,r,x,y)
101
    --the first time it's called, from touched, it just passes the new color
102
    --so we'll make a note of the current color of bottom left
103
    --square, and our starting x,y, which is 1,1
104
    if r==nil then 
105
        r=board[1][1] 
106
        x=1 y=1 
107
    end
108
    --check if the square we are in, needs to be changed
109
    --if it is the first one, 1,1, the answer is always yes
110
    if board[x][y]==r then 
111
        board[x][y]=c
112
        --now check the neighbours around, excl diagonals
113
        if x>1 then fillBoard(c,r,x-1,y) end
114
        if x<Size then fillBoard(c,r,x+1,y) end
115
        if y>1 then fillBoard(c,r,x,y-1) end
116
        if y<Size then fillBoard(c,r,x,y+1) end
117
    end
118
end
119
120
--# Backup
121
Backup = class()
122
123
function Backup:init()
124
    self.backups={}
125
end
126
127
--backs up a 1D or 2D table to a delimited string
128
--one parameter is the table to be backed up, stores the string in an array backup
129
--this provides unlimited backups
130
function Backup:store(t)
131
    if t==nil then return end --do nothing if given nothing
132
    if self.backups==nil then self.backups={} end --if first time, create array
133
    local s={} --we use a 1D array for the backup because it's faster than strings, we convert later
134
    if type(t[1])~="table" then --1D table, we can use built in concat command
135
        self.backups[#self.backups+1]="1,"..table.concat(t,",")
136
    else  --2D table, loop through
137
        for i=1,#t do
138
            for j=1,#t[i] do
139
                s[#s+1]=t[i][j]
140
            end
141
        end
142
        self.backups[#self.backups+1]=#t[1]..","..table.concat(s,",")
143
    end   
144
end
145
146
--restore last backup from a string to a table (1 or 2D)
147
--parameter is the number of cols - if missing,table is assumed to be 1D
148
--if cols is provided, it is used to calculate rows (since # total items backed up = cols x rows)
149
--returns the table, deletes restored backup
150
function Backup:restore()
151
    if #self.backups==0 then return end --no backups
152
    local t={} --the table we will return
153
    local b=self:split(self.backups[#self.backups]) --split backup string into a 1D table
154
    local cols=tonumber(b[1])
155
    if cols==1 then 
156
        t=b --if a 1D table is needed, we're done
157
        table.remove(t,1)
158
    else
159
        local ii,jj=cols,(#b-1)/cols --otherwise we need a 2D table, calc number of rows (jj)
160
        local n=1
161
        for i=1,ii do --loop through cols
162
            t[i]={} --create array for this row
163
            for j=1,jj do --loop through row
164
                n = n + 1 --counter to help us find the place in b
165
                t[i][j]=b[n] 
166
            end
167
        end
168
    end
169
    table.remove(self.backups,#self.backups) --remove latest backup
170
    return t
171
end
172
173
function Backup:clear()
174
    self.backups=nil
175
end
176
177
--splits a delimited string into a table, delimiter defaults to comma
178
function Backup:split(str, delim)
179
    if delim==nil then delim="," end
180
    local result = {}
181
    local pat = "(.-)" .. delim .. "()"
182
    local lastPos = 1
183
    for part, pos in string.gfind(str, pat) do
184
        table.insert(result, part)
185
        lastPos = pos
186
    end
187
    -- Handle the last field
188
    table.insert(result, string.sub(str, lastPos))
189
    return result
190
end