Is there anyway to make this function better for my module? - module

I've been recently messing around with modules and I wanted to know if there's anyway to make this calculate function any better?
function Library.calc(arg1,arg2,option)
local options = {
[1] = "add",
[2] = "sub",
[3] = "mul",
[4] = "div"
}
if option == options[1] then
print(arg1+arg2)
end
if option == options[2] then
print(arg1-arg2)
end
if option == options[3] then
print(arg1*arg2)
end
if option == options[4] then
print(arg1/arg2)
end
end

This question should be migrated to Code Review SE, as Nifim pointed out.
local options = {
add = function (x,y) return x+y end,
sub = function (x,y) return x-y end,
mul = function (x,y) return x*y end,
div = function (x,y) return x/y end,
}
function Library.calc(arg1,arg2,option)
print(assert(options[option], "Unknown option")(arg1, arg2))
end

Related

Lua implementation of BestSum function using memoization

I am trying to translate the below javascript "bestSum" memoization function into lua:
const bestSum = (targetSum,numbers,memo ={}) => {
if(targetSum in memo) return memo[targetSum];
if(targetSum === 0 ) return [];
if(targetSum <0)return null;
let shortestCombination = null;
for (let num of numbers) {
const remainder = targetSum - num;
const remainderCombination = bestSum(remainder,numbers,memo);
if (remainderCombination !==null) {
const combination = [...remainderCombination, num];
if (shortestCombination === null || combination.length < shortestCombination.length)
{
shortestCombination = combination;
}
}
}
memo [targetSum] = shortestCombination;
return shortestCombination;
}
sample test cases with correct results:
console.log(bestSum(7,[5,3,4,7])); //[7]
console.log(bestSum(8,[2,3,5])); //[3,5]
console.log(bestSum(8,[1,4,5])); //[4,4]
console.log(bestSum(100,[1,2,5,25])); //[25,25,25,25]
I translated the above javascript into lua as the following:
local function BestSum(target_sum,numbers,memo)
if memo[target_sum] ~= nil then return memo[target_sum] end
if target_sum == 0 then return {} end
if target_sum < 0 then return nil end
local shortest_combination = nil
for i, num in ipairs (numbers) do
local remainder = target_sum - num
local remainder_combination = BestSum(remainder,numbers, memo)
if remainder_combination ~= nil then
local combination = remainder_combination
table.insert(combination,num )
if (shortest_combination == nil) or (#combination < #shortest_combination )then
shortest_combination = combination
end
end
end
memo[target_sum] = shortest_combination;
return shortest_combination;
end
but don't get the desired results for the two last cases...... instead get incorrect results:
BestSum(8,{1,4,5},{})==>{"4","1","4"}
BestSum(150,{5,25},{})==>
{"25","5","5","5","5","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25"}
The results are not even correct let alone being "best" case??
Can anyone spot where I'm going wrong?
Much appreciated
The problem is with this part of the translation:
local combination = remainder_combination
table.insert(combination, num)
Tables are pass by reference, so this isn't creating a new table, it's just assigning the variable combination to the same table. Modifying combination is just adding more data to remainder_combination.
The JavaScript version is taking care to create a new array, and fills it with the contents of the remainderCombination array (using '...', the spread operator):
const combination = [...remainderCombination, num];
This is the most accurate Lua translation:
local combination = {unpack(remainder_combination)}
table.insert(combination, num)
(Edit: For Lua 5.2+ it's table.unpack)

Entities inheriting Entity.lua variables, but not its methods

I am building a game with enemies and players, all of which are set up to have various states for animation and behavior. The parent class for both is Entity.lua, from which they inherit variables and methods. However, while both enemies and players are inheriting the variables, for some reason the enemies do not inherit the methods. So, if I try to call snakey:changeState('search'), for example, it gives me an error message "Attempt to call method 'changeState' (a nil value)".
I have used the same sequence for creating entities in several games in the past and never had this problem. In fact, if I create the Player in the same way, file and location as the enemies, I receive no error messages.
Here is the code where I create the entities.
local snakey
snakey = Snakey {
platform = platform,
player1 = self.player1,
player2 = self.player2,
stateMachine = StateMachine {
['search'] = function() return SnakeySearchState(snakey) end,
['chasing'] = function() return SnakeyChasingState(snakey) end,
['idle'] = function() return SnakeyIdleState(snakey) end
}
}
-- snakey:changeState('search')
-- snakey.stateMachine:change('search', params)
table.insert(self.entities, snakey)
The two coded out lines are where I noticed the problem. The first line gives and error and the second does work, but is not satisfactory because it is a work-around.
Here is the code for Entity.lua: I don't include details of the functions for brevity, but all are working properly for when player calls them.
Entity = Class{}
function Entity:init(def)
-- position
self.x = def.x
self.y = def.y
self.gravity = 6
-- many more variables
end
function Entity:changeState(state, params)
self.stateMachine:change(state)
end
function Entity:update(dt)
self.stateMachine:update(dt)
end
function Entity:collides(entity)
-- do something
end
function Entity:onDamage()
-- do something
end
function Entity:render()
- renders sprite
end
Player code (in brief)
Player = Class{__includes = Entity}
function Player:init(def)
Entity.init(self, def)
-- more variables
end
function Player:update(dt)
Entity.update(self, dt)
end
function Player:render()
Entity.render(self)
end
And perhaps the trouble spot, one one enemy's script
Snakey = Class{__includes = Entity}
function Snakey:init(def)
Entity.init(self, def)
-- yet more variables
end
function Snakey:update(dt)
Entity.update(self, dt)
-- entity behavior (works fine, so omitted)
end
function Snakey:render()
Entity.render(self)
end
Thank you very much for your help. I'm feeling quite frustrated because this sequence has worked in the past and I would really like to know why it's not calling those Entity methods.
Adding the class library
--Copyright (c) 2010-2013 Matthias Richter
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})
It turns out that sequence matters. In trying to create the minimum reproducible code I could not reproduce the error. After some searching (and a little frustration), I noticed that in Dependencies.lua I was requiring the enemies BEFORE Entity.lua, but Player.lua was required after. I would have thought this wouldn't matter, since everything was imported into the program on frame 1 and I was creating entities on something like frame 1000, but alas. Anyway, problem solved! Always require parent classes before child classes... Lesson learned. :)

Check if index in table exist

I have problem; I must check in my program one field in table.
if(launchArgs.androidIntent.extras.notification.custom.test_field ~= nil)then...
and when this index exist everything is ok, but when it isn't exist, I get an error :
Attempt to index field 'notification' (a nil value).
And it is understandable. How check if that index exist?
Try this
if (launchArgs and launchArgs.androidIntent and launchArgs.androidIntent.extras
and launchArgs.androidIntent.extras.notification and launchArgs.androidIntent.extras.notification.custom
and launchArgs.androidIntent.extras.notification.custom.test_field) then
-- do you stuff
end
This code will check if each table is set.
If you're sure launch args.androidIntent.extras is always set you can just do this
if(launchArgs.androidIntent.extras.notification and launchArgs.androidIntent.extras.notification.custom and launchArgs.androidIntent.extras.notification.custom.test_field)then
-- do your stuff
end
OR Just use this function, that I posted in some other answer (helps here too )
function IndexScan(input,value,case,_type)
if (input and type(input) == 'table') then
if (_type) then
if (type(value) == _type and value == input) then
return true;
end
else
if (type(value) == 'table' and value == input) then
return true;
end
end
for key,object in pairs(input) do
if (case and type(input)=='string' and type(key)=='string') then
if (_type) then
if (value:lower() == key:lower() and type(object)==_type) then
return true;
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
else
if (value:lower() == key:lower()) then
return true;
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
end
else
if (_type) then
if (key == value and type(object)==_type) then
return true
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
else
if (key == value) then
return true
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
end
end
end
end
return false;
end
-- IndexScan(#param table(table), #param index(string), #param case-sensitive(true/false), #param type (index type, string/boolean/number/table ...))
-- checks if these two indexes were set any where in the launchArgs table and checks their type
if (IndexScan(launchArgs,"notification",false,"table") and IndexScan(launchArgs,"test_field",false,"string")) then
-- do your stuff
end
EDIT:
Fixed some mistake in the function.
EDIT:
Updated the script after the author fixed the Notification typo.
Try also this:
function setglobal(name,value)
local t=_ENV
local f="_G"
for x in name:gmatch("[^.]+") do
if t[f]==nil then t[f]={} end
t=t[f]
f=x
end
t[f]=value
end
function getglobal(name)
local t=_ENV
for x in name:gmatch("[^.]+") do
t=t[x]
if t==nil then return nil,x end
end
return t
end
setglobal("launchArgs.androidIntent.extras.notification.custom.test_field",2014)
print(getglobal("launchArgs.androidIntent.extras.notification.custom.test_field"))
print(getglobal("launchArgs.androidIntent.extras.notifiaction.custom.test_field"))
This assumes that the top-level variable is a global variable. Adapt as needed.
You can use this:
local function try(root, query)
local ids, len = {}, 0
for id in query:gmatch("%w+") do
len = len + 1
ids[len]= id
end
local node = root
for i=1,len do
if type(node) ~= 'table' then return nil end
node = node[ids[i]]
end
return node
end
Usage:
local tbl = { a = { b = { c = { d = 1 } } } }
print(try(tbl, 'a.b.c.d')) -- prints 1
print(try(tbl, 'a.b.c.x')) -- prints nil
print(try(tbl, 'a.x.c.d')) -- prints nil

Lua OOP grid class with event

I'm learning lua and i'm trying the OOP approach.
To start, I'm trying to make a grid class, but I think i'm still lacking some knowledge to make it do what I want it to do.
This is my code so far:
local screen = require( 'data.screen')
Grid = {}
Grid_mt = { __index = Grid }
--- Constructs a new Grid object.
function Grid:new( params )
local self = {}
local function try( self, event )
print(self.empty)
end
for i = 1, screen.tilesAcross do
if not self[i] then
self[i] = {};
end
for j = 1, screen.tilesDown do
self[i][j] = display.newImageRect( params.group, "images/playable.png", screen.tileWidth, screen.tileHeight )
self[i][j].x = (j - 1) * (screen.tileWidth + screen.tileSpacing) + screen.leftSpacing
self[i][j].y = (i - 1) * (screen.tileHeight + screen.tileSpacing) + screen.topSpacing
self[i][j]._x = i
self[i][j]._y = j
self[i][j].enable = false
self[i][j].empty = true
self[i][j].tap = try
self[i][j]:addEventListener( "tap", self[i][j] )
end
end
setmetatable( self, Grid_mt )
return self
end
function Grid:setEnable(value, x, y)
if value ~= true and value ~= false then
error("Boolean expected")
end
self[x][y].enable = value
end
function Grid:getEnable(x, y)
return self[x][y].enable
end
function Grid:setEmpty(value, x, y)
if value ~= true and value ~= false then
error("Boolean expected")
end
self[x][y].empty = value
end
function Grid:getEmpty(x, y)
return self[x][y].empty
end
function Grid:SetmColor()
self[1][4]:setFillColor( 255,255 )
end
I have 2 questions:
My event works but I would like to do something like: print(self:getEmpty() )
but whenever I try to use a method in my event, it doesn't work "attempt to call method 'getEmpty' (a nil value)"
and also the setfillcolor wwon't work, I want to be able to change the color of a case with it.
Thanks for your time!
and if i'm going to the wrong road, let me know, and by the way, I have a working code without make a class, this is just for training purpose :)
Thnaks!
The issue is that self[i][j] is not a Grid, only self is a Grid. So when the event handler is called, self in the handler is the display object, not the Grid object. If the handler needs to know the grid object, you could assign the grid to each display object:
self[i][j].grid = self
then in try you could do
grid = self.grid
But in this case you may get a cleaner design if you have the tap handler not be specific to each display object. In this case you would use an upvalue, you can just use self:
function Grid:new( params )
local self = {}
local function try( event ) -- omit the first param, self is an upvalue
print(self.empty)
end
for i = 1, screen.tilesAcross do
...
for j = 1, screen.tilesDown do
self[i][j] = display.newImageRect( ... )
...
self[i][j]:addEventListener( "tap", try )
end
end
Since listener given is a function rather than a table, it gets only one parameter, the event, and self is an upvalue so it will be the Grid instance created just above the try function.
For the first question, more information would be needed. See my comment above.
As for the setFillColor not working, the following is taken from the Corona docs:
object:setFillColor( gray )
object:setFillColor( gray, alpha )
object:setFillColor( red, green, blue )
object:setFillColor( red, green, blue, alpha )
object:setFillColor( gradient )
gray, red, green, blue, alpha (optional)
Numbers between 0 and 1 that represent the corresponding
value for that channel. alpha represents the opacity of the object.
Now, when you are trying to execute:
self[1][4]:setFillColor( 255,255 )
you are passing the values for gray and alpha channels. The values NEED TO BE less than, or equal to 1. Probably you want to pass 1 (as 255 is generally the max. value)

How can I work with class in lua love2d (OOP)

I don't know how make classes in lua so I used code which was recommended on forum.
But always only one object works. First one have coordinates x,y and the other object share his coordinates. Can you explain what I´m doing wrong in this code.
Thank you for your advice.
My code:
require("class")
asteroid = class:new()
function asteroid:init(x,y)
asteroid.b = love.physics.newBody(world, x ,y , "dynamic")
asteroid.s = love.physics.newCircleShape(35)
asteroid.f = love.physics.newFixture(asteroid.b, asteroid.s)
end
function love.load()
world = love.physics.newWorld(0, 50, true)
asteroid1= asteroid:new(100,100)
asteroid2= asteroid:new(700,100)
end
function love.update(dt)
world:update(dt)
end
function love.draw()
love.graphics.circle("line", asteroid1.b:getX(),asteroid1.b:getY(), asteroid1.s:getRadius(), 35)
love.graphics.circle("line", asteroid2.b:getX(),asteroid2.b:getY(), asteroid2.s:getRadius(), 35)
end
Recommended code:
__HAS_SECS_COMPATIBLE_CLASSES__ = true
local class_mt = {}
function class_mt:__index(key)
return self.__baseclass[key]
end
class = setmetatable({ __baseclass = {} }, class_mt)
function class:new(...)
local c = {}
c.__baseclass = self
setmetatable(c, getmetatable(self))
if c.init then
c:init(...)
end
return c
end
Here is a demo code for you
local MyClass = {}
MyClass.__index = MyClass
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
-- the : syntax here causes a "self" arg to be implicitly added before any other args
function MyClass:set_value(newval)
self.value = newval
end
function MyClass:get_value()
return self.value
end
local instance = MyClass(5)
-- do stuff with instance...
I would suggest you to follow these tutorials
http://lua-users.org/wiki/ObjectOrientationTutorial
http://lua-users.org/wiki/TutorialDirectory
The : syntax causes an implicit self to be available as a local, referring to the object instance. But you are assigning to b at class level. Use self.b = instead of asteroid.b = so that the assignment is specific to the instance.