how do you make a string dictionary function in lua? - lua

Is there a way if a string is close to a string in a table it will replace it with the one in the table?
Like a spellcheck function, that searches through a table and if the input is close to one in the table it will fix it , so the one in the table and the string is the same?

You can use this code :) Reference code is from here : https://github.com/badarsh2/Algorithm-Implementations/blob/master/Levenshtein_distance/Lua/Yonaba/levenshtein.lua
local function min(a, b, c)
return math.min(math.min(a, b), c)
end
local function matrix(row,col)
local m = {}
for i = 1,row do m[i] = {}
for j = 1,col do m[i][j] = 0 end
end
return m
end
local function lev(strA,strB)
local M = matrix(#strA+1,#strB+1)
local i, j, cost
local row, col = #M, #M[1]
for i = 1, row do M[i][1] = i - 1 end
for j = 1, col do M[1][j] = j - 1 end
for i = 2, row do
for j = 2, col do
if (strA:sub(i - 1, i - 1) == strB:sub(j - 1, j - 1)) then cost = 0
else cost = 1
end
M[i][j] = min(M[i-1][j] + 1,M[i][j - 1] + 1,M[i - 1][j - 1] + cost)
end
end
return M[row][col]
end
local refTable = {"hell", "screen"}
local function getClosestWord(pInput, pTable, threesold)
cDist = -1
cWord = ""
for key, val in pairs(pTable) do
local levRes = lev(pInput, val)
if levRes < cDist or cDist == -1 then
cDist = levRes
cWord = val
end
end
print(cDist)
if cDist <= threesold then
return cWord
else
return pInput
end
end
a = getClosestWord("hello", refTable, 3)
b = getClosestWord("screw", refTable, 3)
print(a, b)
Third parameter is threesold, if min distance is higher than threesold, word is not replaced.

Related

How to fix "attempt to index ? (a number value)" ? LUA

SOLVED
What I learned: When using a table within a function, make sure you don't have a variable defined under the same string/letter. Local variables overshadow global variables. Hope this helps!
The error occurs on line 112 when trying to use the goto() function.
I'm completely new to coding as of 4 days ago and am attempting to write a code that references a table for an argument to select a parameter for a function.
I want to enter changeD(a[4]) and have checkD() run until it returns a[4]. Instead i get the error code listed in the title.
My table is as follows
a = {}
a[1] = "north"
a[2] = "east"
a[3] = "south"
a[4] = "west"
I reference a table value as an argument in this function:
function changeD(arg)
local dir = 0
repeat
if checkD() == arg then
print("Done")
dir = 1
else
turn(1,1)
end
until dir == 1
end
the checkD() function returns one of the table values. Therefore the changeD() function runs until the value returned by checkD() is the same as the table value specified in the argument.
I apologize if i'm using the wrong words to refer to the table stuff as I am still wet behind the ears when it comes to coding.
My full program is as follows. Sorry if its messy.
c = 0
a = {}
a[1] = "north"
a[2] = "east"
a[3] = "south"
a[4] = "west"
function fd(x)
for i = 1 ,x do
print("forward")
turtle.dig()
turtle.forward()
end
end
function turn(y,x)
if x == 1 then
for i = 1 ,y do
turtle.turnLeft()
print("left")
end
elseif x == 2 then
for i = 1 ,y do
turtle.turnRight()
print("right")
end
end
end
function checkD()
local X, Y, Z = gps.locate()
print(X)
print(Y)
print(Z)
turtle.forward()
local x , y, z = gps.locate()
print(x)
print(y)
print(z)
c = 0
result = false
D = 0
repeat
if c == 0 then
A = X
B = x
print(A.." "..B)
else
A = Z
B = z
print(A.." "..B)
end
sleep(2)
if A < B then
g = 1
elseif A > B then
g = 2
elseif A == B then
c = 1
end
print("compared values; g="..g)
if c == 0 then
if g == 1 then
D = a[2]
result = true
elseif g == 2 then
D = a[4]
result = true
end
print("checked x")
print(D)
elseif not c == 0 then
if g == 1 then
D = a[3]
result = true
elseif g == 2 then
D = a[1]
result = true
end
print("checked z")
end
print("Direction facing "..D)
until result == true
turtle.back()
return D
end
function changeD(arg)
local dir = 0
repeat
if checkD() == arg then
print("Done")
dir = 1
else
turn(1,1)
end
until dir == 1
end
local x = 0
function goto(x,y,z)
local t = 0
local a = 0
local X, Y, Z = gps.locate()
print(X)
print(Y)
print(Z)
if X > x then
t = X - x
changeD(a[4])
fd(t)
elseif X < x then
t = x - X
changeD(a[2])
fd(t)
else
print("cord is same")
end
if Z > z then
t = Z - z
change(a[1])
fd(t)
elseif Z < z then
t = z - Z
change(a[3])
fd(t)
else
print("cord is same")
end
if Y > y then
t = Y - y
for i = 1,t do
turtle.down()
end
elseif Y < y then
t = y - Y
for i = 1,t do
turtle.up()
end
end
end
In goto, you declare local a = 0. This local a variable shadows the global a = {} variable. The local a variable is a number, so can't be indexed.

math library is missing in the latest update of Logitech G-Hub

local delay = math.random(25, 50)
[string "LuaVM"]:5: attempt to index a nil value (global 'math')
I can't use math.random anymore is there any way to fix this ?
If math library is missed you can insert the following code block at the beginning of your script.
It will not fix the whole math library, but only some of the most frequently used functions (including math.random).
It will also fix the following errors:
bad argument #1 to 'Sleep' (number has no integer representation)
attempt to call a nil value (field 'getn')
do
local state_8, state_45, cached_bits, cached_bits_qty = 2, 0, 0, 0
local prev_width, prev_bits_in_factor, prev_k = 0
for c in GetDate():gmatch"." do
state_45 = state_45 % 65537 * 23456 + c:byte()
end
local function get_53_random_bits()
local value53 = 0
for shift = 26, 27 do
local p = 2^shift
state_45 = (state_45 * 233 + 7161722017421) % 35184372088832
repeat state_8 = state_8 * 76 % 257 until state_8 ~= 1
local r = state_8 % 32
local n = state_45 / 2^(13 - (state_8 - r) / 32)
n = (n - n%1) % 2^32 / 2^r
value53 = value53 * p + ((n%1 * 2^32) + (n - n%1)) % p
end
return value53
end
for j = 1, 10 do get_53_random_bits() end
local function get_random_bits(number_of_bits)
local pwr_number_of_bits = 2^number_of_bits
local result
if number_of_bits <= cached_bits_qty then
result = cached_bits % pwr_number_of_bits
cached_bits = (cached_bits - result) / pwr_number_of_bits
else
local new_bits = get_53_random_bits()
result = new_bits % pwr_number_of_bits
cached_bits = (new_bits - result) / pwr_number_of_bits * 2^cached_bits_qty + cached_bits
cached_bits_qty = 53 + cached_bits_qty
end
cached_bits_qty = cached_bits_qty - number_of_bits
return result
end
table = table or {}
table.getn = table.getn or function(x) return #x end
math = math or {}
math.huge = math.huge or 1/0
math.abs = math.abs or function(x) return x < 0 and -x or x end
math.floor = math.floor or function(x) return x - x%1 end
math.ceil = math.ceil or function(x) return x + (-x)%1 end
math.min = math.min or function(x, y) return x < y and x or y end
math.max = math.max or function(x, y) return x > y and x or y end
math.sqrt = math.sqrt or function(x) return x^0.5 end
math.pow = math.pow or function(x, y) return x^y end
math.frexp = math.frexp or
function(x)
local e = 0
if x == 0 then
return x, e
end
local sign = x < 0 and -1 or 1
x = x * sign
while x >= 1 do
x = x / 2
e = e + 1
end
while x < 0.5 do
x = x * 2
e = e - 1
end
return x * sign, e
end
math.exp = math.exp or
function(x)
local e, t, k, p = 0, 1, 1
repeat e, t, k, p = e + t, t * x / k, k + 1, e
until e == p
return e
end
math.log = math.log or
function(x)
assert(x > 0)
local a, b, c, d, e, f = x < 1 and x or 1/x, 0, 0, 1, 1
repeat
repeat
c, d, e, f = c + d, b * d / e, e + 1, c
until c == f
b, c, d, e, f = b + 1 - a * c, 0, 1, 1, b
until b <= f
return a == x and -f or f
end
math.log10 = math.log10 or
function(x)
return math.log(x) / 2.3025850929940459
end
math.random = math.random or
function(m, n)
if m then
if not n then
m, n = 1, m
end
local k = n - m + 1
if k < 1 or k > 2^53 then
error("Invalid arguments for function 'random()'", 2)
end
local width, bits_in_factor, modk
if k == prev_k then
width, bits_in_factor = prev_width, prev_bits_in_factor
else
local pwr_prev_width = 2^prev_width
if k > pwr_prev_width / 2 and k <= pwr_prev_width then
width = prev_width
else
width = 53
local width_low = -1
repeat
local w = (width_low + width) / 2
w = w - w%1
if k <= 2^w then
width = w
else
width_low = w
end
until width - width_low == 1
prev_width = width
end
bits_in_factor = 0
local bits_in_factor_high = width + 1
while bits_in_factor_high - bits_in_factor > 1 do
local bits_in_new_factor = (bits_in_factor + bits_in_factor_high) / 2
bits_in_new_factor = bits_in_new_factor - bits_in_new_factor%1
if k % 2^bits_in_new_factor == 0 then
bits_in_factor = bits_in_new_factor
else
bits_in_factor_high = bits_in_new_factor
end
end
prev_k, prev_bits_in_factor = k, bits_in_factor
end
local factor, saved_bits, saved_bits_qty, pwr_saved_bits_qty = 2^bits_in_factor, 0, 0, 2^0
k = k / factor
width = width - bits_in_factor
local pwr_width = 2^width
local gap = pwr_width - k
repeat
modk = get_random_bits(width - saved_bits_qty) * pwr_saved_bits_qty + saved_bits
local modk_in_range = modk < k
if not modk_in_range then
local interval = gap
saved_bits = modk - k
saved_bits_qty = width - 1
pwr_saved_bits_qty = pwr_width / 2
repeat
saved_bits_qty = saved_bits_qty - 1
pwr_saved_bits_qty = pwr_saved_bits_qty / 2
if pwr_saved_bits_qty <= interval then
if saved_bits < pwr_saved_bits_qty then
interval = nil
else
interval = interval - pwr_saved_bits_qty
saved_bits = saved_bits - pwr_saved_bits_qty
end
end
until not interval
end
until modk_in_range
return m + modk * factor + get_random_bits(bits_in_factor)
else
return get_53_random_bits() / 2^53
end
end
local orig_Sleep = Sleep
function Sleep(x)
return orig_Sleep(x - x%1)
end
end

Check Collision Between Ball And Array Of Bricks

Since I have a collision check function in Lua:
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
And I did make some panels as bricks using array table on my form, with this function, I did collision check between ball with each form sides without problems.
function createBricks()
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
local x = (col - 1) * (width + gap) -- x offset
local y = (row - 1) * (height + gap) -- y offset
local newBrick = createPanel(gamePanel)
newBrick.width = brickWidth
newBrick.height = brickHeight
newBrick.top = y + 15
newBrick.left = x + 15
newBrick.BorderStyle = 'bsNone'
if level == 1 then newBrick.color = '65407' -- green
elseif level == 2 then newBrick.color = '858083' -- red
elseif level == 3 then newBrick.color = '9125192' -- brown
elseif level == 4 then newBrick.color = math.random(8,65255) end
bricks[row][col] = newBrick
end
end
end
Next how to detect if the ball collided with the bricks?. So far I did:
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
dBrick = bricks[row][col]
if onCollision(gameBall,dBrick) then
dBrick.destroy() -- destroy the collided brick
end
end
end
I want to learn how to implement this collision logic in VB Net script which VB script easier for me, I did the whole game project using VB Net, now I try to re-write the project using CE Lua.
Private brickArray(brickRows, brickColumns) As Rectangle
Private isBrickEnabled(brickRows, brickColumns) As Boolean
For rows As Integer = 0 To brickRows
For columns As Integer = 0 To brickColumns
If Not isBrickEnabled(rows, columns) Then Continue For
If gameBall.IntersectsWith(brickArray(rows, columns)) Then
isBrickEnabled(rows, columns) = False
If gameBall.X + 10 < brickArray(rows, columns).X Or _
gameBall.X > brickArray(rows, columns).X + brickArray(rows, columns).Width _
Then
xVel = -xVel
Else
yVel = -yVel
End If
End If
Next
Next
And also this private sub, how to write it CE Lua?
Sub loadBricks()
Dim xOffset As Integer = 75, yOffset As Integer = 100
For row As Integer = 0 To brickRows
For column As Integer = 0 To brickColumns
brickArray(row, column) = New Rectangle(xOffset, yOffset, brickWidth, brickHeight)
xOffset += brickWidth + 10
isBrickEnabled(row, column) = True
Next
yOffset += brickHeight + 10
xOffset = 75
Next
End Sub
Function getBrickCount() As Integer
Dim Count As Integer = 0
For Each brick As Boolean In isBrickEnabled
If brick = True Then Count += 1
Next
Return Count
End Function
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
Then to detect collision the collision and remove from the table:
-- Drawback table
local function tcount( t )
local c = 0
for k,v in pairs(t) do
c = c + 1
end
return c
end
local count = #brickArray
for x = 1, count do
if onCollision(gameBall, brickArray[x]) then
if gameBall.Left + 10 < brickArray[x].Left or gameBall.Left > brickArray[x].Left + brickArray[x].Width then
xVel = -xVel else yVel = -yVel
end
playSound(findTableFile('strikeball.wav'))
brickArray[x] = brickArray[count]
brickArray[x] = x
brickArray[count] = nil
brickArray[x].Visible = false
tcount(brickArray)
end
end
The code above detected the collision and remove the object from the table, but that is not removed from display. How to remove the bricks from the table and display, using Cheat Engine Lua script?.

Memory is not released after a dofile in lua

I am new to lua and was working on NodeMCU. I was trying to extract data from an xml file.
Here is my xml file:
<?xml version="1.0" encoding="UTF-8"?>
<netconfig>
<mode>0</mode>
<stamac>18-FE-34-A4-4B-05</stamac>
<staip>XXX.XXX.XXX.XXX</staip>
<stanetmask>XXX.XXX.XXX.XXX</stanetmask>
<stagateway>XXX.XXX.XXX.XXX</stagateway>
<apmac>1A-FE-34-A4-4B-05</apmac>
<apip>192.168.4.1</apip>
<apnetmask>255.255.255.0</apnetmask>
<apgateway>192.168.4.1</apgateway>
<port>80</port>
<dns>XXX.XXX.XXX.XXX</dns>
<dhcp>1</dhcp>
<stacustomconfig></stacustomconfig>
<timezone>10</timezone>
<serial>0x00000001</serial>
<connssid>ESP-10767109</connssid>
<ssid></ssid>
<passwd></passwd>
<hostname>ESP-10767109</hostname>
<reboot></reboot>
<message></message>
</netconfig>
Here is my xmlparser:
return function (xmlfile, xmlword)
file.open(xmlfile,"r")
local eofflag = 0
local i, j, k, l, xmloutput
while(eofflag < 1) do
local m = file.readline()
if(m == nil) then
eofflag = eofflag + 1
elseif (string.find(m, xmlword) ~= nil) then
i, j = string.find(m, xmlword, 1)
i = i - 1
j = j + 2
k, l = string.find(m, xmlword, j)
k = k - 3
l = l + 1
xmloutput = string.sub(m, j, k)
eoffile = 1
end
end
file.close()
return xmloutput
end
I call this file by using:
local port = dofile("xmlparser.lc")("netconfig.xml", "port")
But I always endup with memory less than I started with even though I call the garbagecollector. Moreover The heap seems to decrease further if the word I am searching for is near the end of file. I also observed that if the word I am looking for is not present, the heap has the less difference I started with.
Am I missing something?
and thanks for taking a look.
Alternatively, is the XML strictly for settings/only used by your lua code? If so I found it much easier and less memory and compute intensive to create the settings file in lua syntax, and then simply execute it. Declare a global table and exec the file:
cfg = {}
dofile("settings.lua")
and in the settings.lua file assign members:
cfg.port = "80"
cfg.dhcp = "1"
cfg.mode = "0"
You can write the table to file easily:
local buf = ""
for mykey,myval in pairs(cfg) do
buf = "cfg." .. mykey .. " = \"" .. myval .. "\""
file.writeline(buf)
end
For what it's worth...
Slight changes to your module:
local module =...
return function (xmlfile, xmlword)
file.open(xmlfile,"r")
local eofflag = 0
local i, j, k, l, xmloutput
while(eofflag < 1) do
local m = file.readline()
if(m == nil) then
eofflag = eofflag + 1
elseif (string.find(m, xmlword) ~= nil) then
i, j = string.find(m, xmlword, 1)
i = i - 1
j = j + 2
k, l = string.find(m, xmlword, j)
k = k - 3
l = l + 1
xmloutput = string.sub(m, j, k)
eoffile = 1
end
end
file.close()
package.loaded[module] = nil
module = nil
return xmloutput
end
That makes the whole thing local and dereferences the module in the packages.loaded table, allowing it to be garbage collected.
And call it using...
xmplarser = require("xmplarser")
v = xmplarser("netconfig.xml", "port")
Hope it helps.

problems with Lua match to find a pattern

I'm struggling with this problem:
Given 2 strings:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
I would like to produce the following information:
If they match (these two above should match, s2 follows a pattern described in s1).
A table holding the values of s2 in with the corresponding name in s1. In this case we would have: { bar = "lua", rab = "rocks" }
I think this algorithm solves it, but I can't figure how to implement it (probably with gmatch):
store the placeholders : indexes as KEYS of a table, and the respective VALUES being the name of these placeholders.
Example with s1:
local aux1 = { "6" = "bar", "15" = "rab" }
With the keys of aux1 fetched as indexes, extract the values of s2
into another table:
local aux2 = {"6" = "lua", "15" = "rocks"}
Finally merge them two into one table (this one is easy :P)
{ bar = "lua", rab = "rocks" }
Something like this maybe:
function comp(a,b)
local t = {}
local i, len_a = 0
for w in (a..'/'):gmatch('(.-)/') do
i = i + 1
if w:sub(1,1) == ':' then
t[ -i ] = w:sub(2)
else
t[ i ] = w
end
end
len_a = i
i = 0
local ans = {}
for w in (b..'/'):gmatch('(.-)/') do
i = i + 1
if t[ i ] and t[ i ] ~= w then
return {}
elseif t[ -i ] then
ans[ t[ -i ] ] = w
end
end
if len_a ~= i then return {} end
return ans
end
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
for k,v in pairs(comp(s1,s2)) do print(k,v) end
Another solution could be:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
pattern = "/([^/]+)"
function getStrngTable(_strng,_pattern)
local t = {}
for val in string.gmatch(_strng,_pattern) do
table.insert(t,val)
end
return t
end
local r = {}
t1 = getStrngTable(s1,pattern)
t2 = getStrngTable(s2,pattern)
for k = 1,#t1 do
if (t1[k] == t2[k]) then
r[t1[k + 1]:match(":(.+)")] = t2[k + 1]
end
end
The Table r will have the required result
The solution below, which is some what cleaner, will also give the same result:
s1 = '/foo/:bar/oof/:rab'
s2 = '/foo/lua/oof/rocks'
pattern = "/:?([^/]+)"
function getStrng(_strng,_pattern)
local t = {}
for val in string.gmatch(_strng,_pattern) do
table.insert(t,val)
end
return t
end
local r = {}
t1 = getStrng(s1,pattern)
t2 = getStrng(s2,pattern)
for k = 1,#t1 do
if (t1[k] == t2[k]) then
r[t1[k + 1]] = t2[k + 1]
end
end

Resources