summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/dat/clua/iter.lua
blob: 9972a1208cf6701ffb4c673f8e324a9baede29bd (plain) (blame)
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
------------------------------------------------------------------------------
-- iter.lua:
-- Iterationeering functions.
------------------------------------------------------------------------------
--
-- Example usage of adjacent_iterator:
--
-- function iter.rats()
--   local i
--   for i in iter.adjacent_iterator() do
--     dgn.create_monster(i.x, i.y, "rat")
--   end
-- end
--
-- The above function will surround the player with rats.
--
------------------------------------------------------------------------------
-- dgn.point iterators.
-- All functions expect dgn.point parameters, and return dgn.points.
------------------------------------------------------------------------------
iter = {}

------------------------------------------------------------------------------
-- rectangle_iterator
------------------------------------------------------------------------------
iter.rectangle_iterator = {}

function iter.rectangle_iterator:_new ()
  local m = {}
  setmetatable(m, self)
  self.__index = self
  return m
end

function iter.rectangle_iterator:new (corner1, corner2, filter)
  if corner1 == nil or corner2 == nil then
    error("need two corners to a rectangle")
  end

  if corner2.x < corner1.x then
    error("corner2's x less than corner1's; did you swap them?")
  elseif corner2.y < corner1.y then
    error("corner2's y less than corner1's; did you swap them?")
  end

  local mt = iter.rectangle_iterator:_new()
  mt.min_x = corner1.x
  mt.min_y = corner1.y
  mt.max_x = corner2.x
  mt.max_y = corner2.y
  mt.cur_x = corner1.x - 1
  mt.cur_y = corner1.y
  mt.filter = filter or nil

  return mt:iter()
end

function iter.rectangle_iterator:next()
  local point = nil
  repeat
    if self.cur_x >= self.max_x then
      self.cur_y = self.cur_y + 1
      self.cur_x = self.min_x
      if self.cur_y > self.max_y then
        point = -1
      else
        point = dgn.point(self.cur_x, self.cur_y)
        if not self:check_filter(point) then
          point = -2
        end
      end
    else
      self.cur_x = self.cur_x + 1
      point = dgn.point(self.cur_x, self.cur_y)
      if not self:check_filter(point) then
        point = -2
      end
    end
    if point == -1 then
      return nil
    elseif point == -2 then
      point = nil
    end
  until point

  return point
end

function iter.rectangle_iterator:check_filter(point)
  if self.filter ~= nil then
    if self.filter(point) then
      return true
    else
      return false
    end
  else
    return true
  end
end

function iter.rectangle_iterator:iter ()
  return function() return self:next() end, nil, nil
end

function iter.rect_iterator(top_corner, bottom_corner, filter)
  return iter.rectangle_iterator:new(top_corner, bottom_corner, filter)
end

-------------------------------------------------------------------------------
-- los_iterator
-------------------------------------------------------------------------------

function iter.los_iterator (include_center, filter, center)
  local y_x, y_y
  if center == nil then
    y_x, y_y = you.pos()
  else
    y_x, y_y = center:xy()
  end
  local top_corner = dgn.point(y_x - 8, y_y - 8)
  local bottom_corner = dgn.point(y_x + 8, y_y + 8)
  local function check_los (point)
    local _x, _y = point:xy()

    if filter ~= nil then
      if not filter(point) then
        return false
      end
    end

    if include_center == true and y_x == _x and y_y == y then
      return true
    else
      return false
    end

    if you.see_cell(_x, _y) then
      return true
    else
      return false
    end

  end
  return iter.rect_iterator(top_corner, bottom_corner, check_los)
end

-------------------------------------------------------------------------------
-- adjacent_iterator
-------------------------------------------------------------------------------

function iter.adjacent_iterator (include_center, filter, center)
  local y_x, y_y
  if center == nil then
    y_x, y_y = you.pos()
  else
    y_x, y_y = center:xy()
  end
  local top_corner = dgn.point(y_x - 1, y_y - 1)
  local bottom_corner = dgn.point(y_x + 1, y_y + 1)
  local function check_adj (point)
    local _x, _y = point:xy()

    if filter ~= nil then
      if not filter(point) then
        return false
      end
    end

    if include_center ~= true and y_x == _x and y_y == y then
      return false
    end

    return true
  end
  return iter.rect_iterator(top_corner, bottom_corner, check_adj)
end