summaryrefslogtreecommitdiff
path: root/common/coords.lua
diff options
context:
space:
mode:
Diffstat (limited to 'common/coords.lua')
-rw-r--r--common/coords.lua90
1 files changed, 90 insertions, 0 deletions
diff --git a/common/coords.lua b/common/coords.lua
new file mode 100644
index 0000000..1bb9154
--- /dev/null
+++ b/common/coords.lua
@@ -0,0 +1,90 @@
+-- Hex: q,r,s. invariant that q+r+s=0
+-- add, subtract
+-- constructor takes 3 positions and rounds to closest hex centre.
+
+-- round to nearest int, rounding .5 away from 0.
+local function round(x)
+ if x<0 then
+ return math.ceil(x-0.5)
+ else
+ return math.floor(x+0.5)
+ end
+end
+
+local Pos, Hex
+
+local SR3 = math.sqrt(3)
+
+Hex={}
+Hex.__index = Hex
+function Hex.make(q,r,s)
+ s=s or -q-r
+ assert(q+r+s==0,"hex coord doesn't meet invariant")
+ return setmetatable({q=q,r=r,s=s},Hex)
+end
+function Hex.round(self)
+ -- return a new Hex rounded to integer coordinates
+ local fq,fr,fs = self.q,self.r,self.s
+ -- round all to nearest integer
+ -- find which was changed the most, reset that one to be coherent with the other two.
+ local abs = math.abs
+
+ local rq,rr,rs = round(fq),round(fr),round(fs)
+ local dq,dr,ds = abs(fq-rq), abs(fr-rr), abs(fs-rs)
+
+ if dq>dr and dq>ds then
+ rq = -rr-rs
+ elseif dr>ds then
+ rr = -rq-rs
+ else
+ rs = -rq-rr
+ end
+
+ return Hex.make(rq,rr,rs)
+end
+
+function Hex.to_pos(self)
+ local x = self.q*SR3 + self.r*(SR3/2)
+ local y = self.r*(3/2)
+ return Pos.make(x,y)
+end
+
+function Hex.__add(self,other) return Hex.make(self.q+other.q, self.r+other.r, self.s+other.s) end
+function Hex.__sub(self,other) return Hex.make(self.q-other.q, self.r-other.r, self.s-other.s) end
+function Hex.__tostring(self) return string.format("H(%.2f,%.2f)",self.q,self.r) end
+
+
+Pos = {}
+Pos.__index=Pos
+function Pos.make(x,y)
+ return setmetatable({x=x,y=y},Pos)
+end
+function Pos.__add(self,other) return Pos.make(self.x+other.x,self.y+other.y) end
+function Pos.__sub(self,other) return Pos.make(self.x-other.x,self.y-other.y) end
+function Pos.__mul(a,b)
+ if type(a) == "number" then
+ return Pos.make(a*b.x,a*b.y)
+ elseif type(b) == "number" then
+ return Pos.make(a.x*b,a.y*b)
+ else
+ error("can only multiply Pos by scalar")
+ end
+end
+function Pos.__div(a,b)
+ assert(type(b) == "number","can only divide Pos by scalar, and can't divide scalar by Pos")
+ return a*(1/b)
+end
+function Pos.lensq(self) return self.x^2 + self.y^2 end
+function Pos.len(self) return math.sqrt(self:lensq()) end
+function Pos.to_hex(self)
+ local q = self.x*(SR3/3) - self.y*(1/3)
+ local r = (2/3)*self.y
+ return Hex.make(q,r,-q-r)
+end
+function Pos.__tostring(self) return string.format("(%.2f,%.2f)",self.x,self.y) end
+
+
+
+return {Hex=Hex,Pos=Pos}
+
+