I wanted to make a madden mobile sniping bot. So I wanted to use the findImage function to find if a player has sold or not. Here is what I'm thinking.
The first image would be my screen and the second image would be what image I'm trying to find, and if it find it it will tap on it. Here is my script:
local r = findImage ( "/images/auction.bmp" ,1, 1, nil, nil);
if r == nil then alert ( "nil" );
else local n = 0;
for i, v in pairs (r) do n = n + 1;
end if n == 0 then alert ( "false" );
else
alert ( "true" );
end
end
It runs but always returns false. So I was wondering if I'm using the findImage function right and if so why doesn't it return true?
The end statement at line 5 closes the for loop and is directly followed by another if statement before the first one at line 2 has been closed.
Try ending both before issuing another condition.
I'd also recommend lowering the finding tolerance a little. A value of 1 is the most strict which means every single pixel must match precisely in order to be found. A value of 0.8 is just as accurate when finding such a large image yet still allows some fuzziness for improving detection.
Something like this should work.
local r = findImage ( "/images/auction.bmp" ,1, 0.8, nil, nil);
local n = 0;
if r == nil then alert ( "nil" ); else
for i, v in pairs (r) do n = n + 1;
end
end
if n == 0 then alert ( "false" );
else alert ( "true" );
end
Related
How can I make a text box to be able to enter numbers using them to calculate in love2d ?
steps:
(optional) capture mouse / touch location
store input, in a string variable
sanitize input, make sure there aren't unexpected chars
calculate results, use load(str) then execute that ()
print results
Capturing mouse is optional, only required if your app has more than one function. If it's a single-use app that only calculates what you type in, there's no need for that first step. However, if there are other selectable locations on the screen, you'll need a way to determine that the user desires that input area. There are a few GUI libs that help with this, or you can simply test if it's within the expected screen x,y region.
function love.load()
fontsize = 16
fontname = "font.ttf"
font = love.graphics.newFont( fontname, fontsize )
input_x_min = 20
input_x_max = 400
input_y_min = 20
input_y_max = input_y_min +fontsize *2
allowed_chars = "1234567890()+-*/"
love.keyboard.setTextInput( false )
input_text = "result=" -- for storing input
result = nil -- empty placeholder for now
output_x = 20
output_y = 40
output_limit = 400
end
function love.update(dt)
local x, y = love.mouse.getPosition()
-- could also capture mouseclicks here, and/or get touch events
if x >= input_x_min and x <= input_x_max
and y >= input_y_min and y <= input_y_max then
love.keyboard.setTextInput( true )
else
love.keyboard.setTextInput( false )
input_text = "result=" -- no longer selected, reset input
end
end
function love.textinput(t)
for i = 1, #allowed_chars do -- sanitize input
if allowed_chars :sub(i,i) == t then -- if char is allowed
input_text = input_text ..t -- append what was typed
generate_result, err = load( input_text ) -- "result=3+(2*2)"
if err then print( err )
else generate_result() -- function() return result=3+(2*2) end
end
end
end
end
function love.draw()
love.graphics.printf( input_text, output_x, output_y, input_limit )
love.graphics.printf( result, output_x, output_y, output_limit )
end
I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().
I am currently trying to debug a Minecraft-based turtle farming script with functions and API functions.
When I am executing I get an 'io' exception (which is understandable as I am trying to write to a log for each loop), but it doesn't tell me which script it is in or the line number. Are there any solutions apart from printing throughout program execution?
Exception I have been getting:
io:107: index expected, got nil
main turtle-farming script:
--[[main script for farming procedure]]
--load functions responsible for positioning/repositioning/farming
os.loadAPI("APIS/positioners");
os.loadAPI("APIS/farmers");
--action turtle start farming condition
assert(positioners.check_start_pos(), "Could not initialise the turtle for the farming procedure\nCould not identify it's starting location\n(are there birch planks directly above and beneath it?");
--check Netherrack can be found from start block, declare 'dir' also as local
local init_result, dir = positioners.find_next_neth()
assert(init_result, "Could not find the appropriate direction to travel in from\n the turtle starting position, is the farm set up correctly?");
local loop_vars = {["count"] = 0, ["blockId"] = nil, ["dir"] = nil, ["prevManvr"] = nil, ["action"] = ""};
--**input** assertion tests for required fuel level and seed requirements
assert(turtle.getFuelLevel() > 50, "Fuel level is below required level to start farming, - terminating");
--given 'result' == true can start farming
turtle.forward();
--open log file (overwrite) and save to io class handle
log = io.open("logs/proc_log", "w");
--start main farming process loop
while turtle.getFuelLevel() > 0 do
--reset action variable
loop_vars["action"] = "";
--sort log variables
loop_vars["count"] = loop_vars["count"] + 1;
--identify the block above (returns inv slot(1-4) it matches with or false if it doesn't)
loop_vars["blockId"] = positioners.id();
if blockId == 1 then
loop_vars["action"] = "Netherrack above ";
if loop_vars["dir"] == nil then
print("Netherrack found, planting");
farmers.plant();
--shift turtle forward such that it can evaluate a new block. Ensure that moves forward in case of obstruction
assert(turtle.forward(), "The turtle is impeded from moving forwards in farming route");
--log statement
loop_vars["action"] = loop_vars["action"].."plant and move forward";
else
--initiate change in direction procedure
assert(positioners.change_direction(loop_vars["dir"]), "Failed to complete turtle change direction procedure");
--reset dir
loop_vars["dir"] = nil;
loop_vars["action"] = loop_vars["action"].." actioned 'positioners.change_position(dir)'.";
end;
elseif blockId == 3 then
turtle.forward();
--log statement
loop_vars["action"] = "Proceeding past marble block";
elseif blockId == false then
print("Finding next Netherrack block.");
--retrace back to the most recent 'legitimate' block");
turtle.back();
--call function to reposition turtle for next farming line
result, loop_vars["dir"] = positioners.find_next_neth(loop_vars["prevMan"]);
assert(result, "A new netherrack block could not be found in any direction.");
--assign dir result to prevMan (information for next positioners.change_position() call
loop_vars["prevMan"] = loop_vars["dir"];
--log statement
loop_vars["action"] = "No 'legitimate' block above, 'positioners.find_next_neth() successful,\nassigning dir accordingly.";
else
--log statement
log.write("Unhandled exception in farm_proc main loop");
log.close();
error("positioners.find_next_neth() did not find an appropriate block above it.");
end;
print("farm_proc loop");
--write current turn to log file
log.write("Turn no: "..loop_vars["count"].."\n Id()== "..tostring(loop_vars["blockId"]).."\n Action: "..loop_vars["action"].."\n Previous maneuver: "..loop_vars["prevMan"].."\n\n");
end;
--updating log
log.write("Error - turtle ran out of fuel\n");
log.close();
error("Turtle ran out of fuel whilst planting - terminated");
'positioners' api (movement/detection based tasks):
function find_next_neth(prevMan)
--[[Find direction of the next overhead block of Netherrack from turtle's current pos,
Order;
N
E
W
S
Error (no direction found)]]
--define numbers corresponding to directions
local dirs = {"Back", "Left", "Right", "Forward"};
--create a loop counter to ensure does not exceed full checking loop
local counter = 4;
--loop through movement proc. until netherrack (slot 1) is found above it (if at all)
while true do
print("Looping, current loop counter is: ", counter);
local idAhead = id_ahead();
if counter == 4 then
--placeholder, script should never need to find forwards
elseif counter == 3 then
turtle.turnLeft();
elseif counter == 2 then
turtle.turnRight();
turtle.turnRight();
elseif counter == 1 then
turtle.turnRight();
--decremented counter has reached it's minimum
elseif counter < 1 then
return false, nil;
else
error("For find_next_neth iteration counter out of range");
end;
--decrement counter variable
counter = counter - 1;
--boolean condition to determine whether function is complete, incomplete or broken. 'prevMan' as a logical statement will return true if var has value, and false if not
local testPrev = (not prevMan == dir[(math.abs(counter - 4) + 1))] or not prevMan);
local validBlock = (idAhead == 1 or idAhead == 3)
if testPrev and validBlock then
--all tests are valid - break loop to return
break;
end;
--report success and return result
print("Nether found!\n");
return true, dirs[counter];
end;
end;
function change_direction(dir)
--intialise a base error string
local errMsg = "Could not action positioners.change_direction(dir, prevMan) ";
if dir == "East" then
assert(turtle.forward(), errMsg.."Obstruction to route");
--this should finalise a 180deg turn to the left
turtle.turnLeft()
elseif dir == "West" then
assert(turtle.forward(), errMsg.."Obstruction to route");
--180deg turn left
turtle.turnRight()
elseif dir == "North" then
--no action
elseif dir == "South" then
error("Return to start not yet implemented");
else
error("positioners.change_direction() parameter not as expected");
end;
return true;
end;
function id(slot)
--[[Determines if netherrack is currently above turtle.
Return false means the block
above does not match slots 1-4 of the
turtle's inv. Takes optional int
for specific block slot index
in turtle compare]]
--checking argument
if slot ~= nil then
--select slot given as argument
turtle.select(slot);
if turtle.compareUp() then
--don't return int because specific material requested
return true;
else
return false;
end;
end;
counter = 1
while counter < 5 do
turtle.select(counter);
--identify whether the current selected slot item matches the blovk overhead
if turtle.compareUp() then
--return block above's corresponding slot index
return counter
end;
counter = counter + 1;
end;
--return number indicating unidentfied block
return false;
end;
function id_ahead(slot)
if turtle.forward() then
--save value of id call for later return
local rtn = id(slot)
turtle.back();
return rtn
else
error("turtle could not move forwards in id_ahead(slot)");
end;
end;
function check_start_pos()
--set selected slot to birch planks (no currently selected method implemented so cannot revert this change internally)
turtle.select(2);
--save boolean variables for comparison of blocks above and below position
local up = turtle.compareUp();
local down = turtle.compareDown();
--test if above boolean values are true (turtle in designated start position)
if up and down then
return true;
else
print("Not in appropriate farming start position");
return false;
end;
end;
(The 'farmers' api simply checks current seeds and then plants a crop through farmers.plant())
I believe I have found the solution - the debug library, specifically debug.traceback() allows you to introspect the call stack more closely when catching an error
debug library index
How would you check a table for three identical elements (looking for three L's)?
table = {nil, nil, L, nil, L} -> false
table = {L, L, nil, nil, L} -> true
Really would appreciate some help!
EDIT: Ok I've got this, but it only outputs false even when there are three or more L's (and does so five times for every check?). Sorry if it seemed like I was trying to get the code for it, I'm genuinely trying to learn! :)
for k, v in pairs( threeL_table ) do
local count = 0
if k == 'L' then
count = count + 1
end
if count == 3 then
print('true')
else
print('false')
end
end
You were almost there. You need to test the values v against 'L', not the keys k. Also, I suppose you want to print the message only once after the scan is concluded; if so, put the if-statement outside of the for-loop. (In this case, you should define count outside of the for-loop, too, otherwise you would not see it once it has ended).
local count = 0
for k, v in pairs( threeL_table ) do
if v == 'L' then -- you need to check for the values not the keys
count = count + 1
end
end
if count == 3 then -- move this out of the for-loop
print('true')
else
print('false')
end
I will not give you any code as you did not show any own efforts to solve the problem.
How would you check a table for three identical elements? Well you count them.
Loop over the table and for every distinct value you create a new counter. You could use another table for that. Once one of those counters reaches 3 you know that you have three identical values.
Another way to solve this.
function detectDup(t,nDup)
table.sort(t)
local tabCount = {}
for _,e in ipairs(t) do
tabCount[e] = (tabCount[e] or 0) + 1
if tabCount[e] >= 3 then
print("The element '" .. e .. "' has more than 3 repetitions!")
return true
end
end
return false
end
print(detectDup({'L', 'L','A','B'},3))
print(detectDup({'L', 'L','A','B','L',},3))
I want to make sure that kD points which I generate randomly don't happen to be identical. To test this efficiently, I want to use a set (at least that's what I would do in C++).
I know that in Lua tables can be used as sets by inserting the object as value with any non-nil key (typically just true or an integer for multisets).
But the problem is that tables in Lua are by default just compared w.r.t. their address, which is of course different even if all the vector components (in my case) are equal.
So I thought I'd implement a equal and/or less than metamethod for my points. But this didn't work (see code below). Can anybody help?
local k = 3
local mt = {}
mt.__eq = function( a, b )
for dim = 1, k do
if a[dim] ~= b[dim] then return false end
end
return true
end
mt.__lt = function( a, b )
for dim = 1, k do
if a[dim] < b[dim] then
return true
elseif a[dim] > b[dim] then
return false
end
end
return false -- equal
end
local set = {}
local p1 = { 1, 2, 3 }
setmetatable( p1, mt )
set[p1] = true
local p2 = { 1, 2, 3 }
setmetatable( p2, mt )
set[p2] = true -- should just overwrite the old value
print( "p1 == p2 --> "..tostring( p1 == p2 ) )
print( "p1 < p2 --> "..tostring( p1 < p2 ) )
local setSize = 0
for _, _ in pairs( set ) do
setSize = setSize + 1
end
print( "Size of the set: "..setSize )
Lua has no facilities for allowing what you're trying to do. That is, there's no metamethod trickery that can make two different pieces of userdata or two different tables map to the same index to the table indexing system.
You'll have to do this manually. You can effectively write your own set, by keeping a list of vectors sorted. table.sort can do the job, since you already have an appropriate __lt metamethod.
If anyone is interested: I have come up with another work-around that has worked for me.
One can use a set of x-coordinates and instead of associating the set items with just "true" or "1", the respective values are sets themselves (of y-coordinates); and so on.
This leads to a tree-like structure where the path to each leaf represents a point (sequence of coordinates) and points with the same first coordinates have common parent nodes. Also all points are unique.