This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
JakeDaSnake's profile picture

Advanced "if, else" statement

Started by JakeDaSnake, 28 December 2014 - 03:16 AM
JakeDaSnake #1
Posted 28 December 2014 - 04:16 AM
Hello ComputerCraftees, I am a new member here (as you can see), as well as a new ComputerCrafter. I've been using this mod for a few days now, as I've never gotten around to do so with the extremeness of the FTB: Monster pack. Although, I regret putting it off, because this mod is great, and right down my alley.

Now, for the reason im here. I've been writing this small set code for the last 2 days (my first attempt at a whole "OS" for my "Big Reactors" Reactor), hitting small road bumps here and there, nothing too crazy though. Until now, that is. I'm trying to write this "if, else" statement, but cant get it to work!

Here's the idea:
I want to set up a piece of code at the end of the script that EITHER activates subscript "a", or subscript "b" (depending on: If "a" ran last, run "b". If "b" ran last, run "a"). Script "a" saves the currently stored "RF", compares it to last ticks stored "RF" (saved by script "b" ), and lastly, setting control rods accordingly based on the comparison. Next time around, script "b" does exactly the same, but checks script "a" for its temporary "RF/t" place holder instead.

Basically, I'm trying to implement an "RF/t usage" variable, then use it to set my reactor's control rods for optimal energy generation. I just can't get the "if, else" statement to work properly. Here's the code:


local counter = counter
local adj = adj
local num1 = num1
local num2 = num2
local tmp1 = tmp1
local tmp2 = tmp2
local I = I
local O = O

counter = counter + 1

if counter == 1 then
	  num1 = nrg
	  tmp1 = nrg - num2
	  tmp2 = tmp1/nrg
	  I = math.floor(tmp2*100)
	  adj = I - O

else
	  num2 = nrg
	  tmp1 = nrg - num1
	  tmp2 = tmp1/nrg
	  O = math.floor(tmp2*100)
	  adj = O - I
	  counter = 0

end

After this^ I tell it to get all the control rod insertion %s, divide by # of control rods, then add the "adj" variable to the control rod insertion %. After all is done, it sets the control rods to the new %. But the above code is all I really need help with.

I hope this all makes sense!

As a final note, I'm trying really hard to learn lua, so don't just spit out the correct code or something. I want explanations! I want to know why it works, and the logical steps it takes!

Thanks in advance!

P.S. I don't write on forums much, so I don't know hot to put a spoiler for the code. Sorry about that.
Bomb Bloke #2
Posted 28 December 2014 - 06:04 AM
Your if/then block looks right to me; assuming you've got a properly set up loop wrapped around this code, it should indeed alternate between the two code blocks on each iteration (as "counter" will either be 1 or 2 each time it hits it, depending on what it was before).

I'm not so sure about the rest of your logic, though - personally I don't see the need for an "if" statement here at all. Let's say we replace num1/num2 with just oldnrg, replace I/O with thisPercent /oldPercent, and do away with tmp1/tmp2/counter completely. We could then crunch the code down to a few lines:

thisPercent = math.floor((nrg - oldnrg) / nrg * 100)
adj = thisPercent - oldPercent
oldPercent, oldnrg = thisPercent, nrg

I'm also curious as to what you think that list of local declarations is doing.

Certainly I recommend using more descriptive variable names. I'm still scratching my head over what "nrg" is supposed to stand for.

I'm also not sure I like the idea of figuring out production levels based on the amount of RF in the reactor vs how much was in the reactor. It sounds like you're aiming for a system that tries to keep the same amount of power in the reactor at all times… but what if that amount is 0? That's not such a good figure to "maintain". Why not compare the amount of power in there to the maximum amount the reactor can store?

I reckon it may be worth dumping the complete script on pastebin and providing a link here.
Lyqyd #3
Posted 28 December 2014 - 06:08 AM
Is this all of the code?

Is there something wrong with the reactor's getEnergyProducedLastTick method, or do I misunderstand what you're trying to figure out?

Edit: Also, if you're trying to match reactor energy production to energy consumption, all you have to do is set the control rod percentage to be equal to the energy stored percentage–this will cause production to track usage after a short time.
JakeDaSnake #4
Posted 28 December 2014 - 07:09 AM
First off, thanks for the quick reply guys, you're awesome.

Second, I probably should have posted the whole code, so ill do that now.

http://pastebin.com/8NF1uh9K

The code has been slightly revised and edited (the portion I already posted), but basically is the same.

Now, Bomb Bloke, a few years ago I used to write java. As you may know, you have to declare your variables before you use them. Apparently, in lua, this is not the case, so I'll stop doing that. But, yes, I agree, my variable names are a little crazy lol. I was doing the last bit of my code last night when I was really Fn tired and I didn't put much thought into naming them. Also, as you can see here from my newly pasted code, nrg is equivalent to the .getEnergyStored() statement. I do have to say, I'm not sure I 100% understand the bit of code you posted.. Can you help me understand the difference between your block of code and mine?

And Lyqyd, I posted the whole code, so have a look at that. Also, the original code I posted didn't need to use that Method, because I'm trying to figure out how much energy is actually making it into the reactors storage, not what's being produced. But, I think just setting the control rods to the percentage of energy stored is a better, like you said. I'll give it a whack.

Lastly, I'm sure my coding isn't very.. great. Sorry about that, guys. This is the first script I've ever written in ComputerCraft, and in lua, period. I used to write in c++ way back in the day, but I can't recall any of it, really. Haha so, if you guys have any pro tips for me, please, I'm all ears. I stride for perfection, and my lua knowledge is faaar from it.

Thanks again!


EDIT: Bomb Bloke, I read that code you posted earlier repeatedly, and it finally makes sense. I'll put it in my "Reactor OS" now. Thanks!
Edited on 28 December 2014 - 07:18 AM
theoriginalbit #5
Posted 28 December 2014 - 07:22 AM
a few years ago I used to write java. As you may know, you have to declare your variables before you use them. Apparently, in lua, this is not the case, so I'll stop doing that.
well yes and no. The following examples are no different.
Java

private int counter = 0;
counter = counter + 1;
Lua

local counter = 0
counter = counter + 1

Just an extra side points
  • your lines that are mon.setTextColor(15000) are technically invalid. 15000 (and other numbers you use) are not a valid ComputerCraft colour, however due to some Java logic it is able to resolve it to colors.green, you would be best off to use the Colors API to set text and background colours.
  • lines 152 onwards don't make much sense as to what they're trying to achieve, could you enlighten us on their purpose?
Dragon53535 #6
Posted 28 December 2014 - 07:39 AM
a few years ago I used to write java. As you may know, you have to declare your variables before you use them. Apparently, in lua, this is not the case, so I'll stop doing that.
well yes and no. The following examples are no different.
Java

private int counter = 0;
counter = counter + 1;
Lua

local counter = 0
counter = counter + 1
To expand slightly just on this point.

Java:

private int counter = 0;
counter += 1;
Lua:

local counter = 0
counter = counter + 1 --#You can't use += in lua
This note aside:

Line 46/47

  local e = eTic/1000
  e = math.floor(e)
--#Could just be
  local e = math.floor(eTic/1000)

When you get the control rod level, you're doing it wrong.
You'll probably want a loop.


--#Line 6:
local R = 0
--#Line 17:
local rod = rad.getControlRodLevel(R)
--#This is only ever going to get whatever r is at the time, which is always going to be 0. So you're only going to get the control rod level of the first one.


--#Line 152-189 can be rewritten as such:
local tot = 0 --#Start of the total variable as 0
for i = 1, 18 do --#Loop 18 times
  tot = tot + rad.getControlRodLevel(i) --#Add the control rod level of each rod to the total.
end
JakeDaSnake #7
Posted 28 December 2014 - 07:40 AM
Hello theoriginalbit, when I attempted to use terms like "colors.green" or "colors.red", I was returned an error. No matter what color, or how many times I tried, it failed. I then tried using 1, 2, 3, 4, etc and found 1=white, 2 AND 3=a different color, then 4 5 6 and 7=another, then 8-15 was another, same with 16-31, 32-63, 64-127, and so on. So I ended up just using that. So in this case, I truly should have put 8000 for green, but 8000-15999 will work. I'm not sure why my colors work this way, but it hasn't been a problem yet, so I'll leave it the way it is.

As for lines 152 and on, they're meant to get each of the control rods levels (as there isn't a "getAllControlRodLevels" I don't believe), add them together, and divide them by how many control rods there are. Basically, getting the average. Then, it takes said average and adds it to the current level of rod insertion. The average could have been negative or positive, so it could increase or decrease the amount of insertion.

EDIT: I'm sorry, I meant when I get "adv", it then gets "adj" subtracted from it, therefor possibly making "fin" (the final number to make the control rod adjustment) a negative number.
Edited on 28 December 2014 - 07:01 AM
JakeDaSnake #8
Posted 28 December 2014 - 07:50 AM
Thanks Dragon53535, I'll do a few edits.

The reason why line 6 and line 17 were the way that they were was because I repeatedly was receiving errors when implementing this "active reactor adjustment" piece, so I attempted to fix it with this, but with no success (obviously).

That last replacement code piece you have is way better then mine. Lol I didn't know how to shorten it like that. I figured you could though.
theoriginalbit #9
Posted 28 December 2014 - 07:55 AM
Hello theoriginalbit, when I attempted to use terms like "colors.green" or "colors.red", I was returned an error. No matter what color, or how many times I tried, it failed. I then tried using 1, 2, 3, 4, etc and found 1=white, 2 AND 3=a different color, then 4 5 6 and 7=another, then 8-15 was another, same with 16-31, 32-63, 64-127, and so on. So I ended up just using that. So in this case, I truly should have put 8000 for green, but 8000-15999 will work. I'm not sure why my colors work this way, but it hasn't been a problem yet, so I'll leave it the way it is.
it would be good to know exactly what the error is, we can help with that. As for why the numbers work… the colours are on a binary scale, therefore white is 20, orange is 21, magenta is 22 etc, as evident by the Colors API page on the wiki.

The choice of using a binary scale is because, unlike the terminals, bundled cables can support multiple colours on or off, meaning having the colours on the binary scale makes for easier tests for on/off. The reason your 15000 works by setting the text/background colour to green is due to the logic which dan200 uses where it can be represented by the following pseudo-equation color = floor(log2(input)). As we know from maths, log2(x) is the inverse of 2x, thus changing the colour input you give it to a number between 0 and 15.99, This number is then rounded down, meaning it is a whole number between 0 and 15, which map directly to the 16 colours within ComputerCraft. So really, the accurate representation of colors.green would be 213 or 8192.

The reason we use the colors API is simply for readability sake, it is much easier to read and understand that colors.black will output as black, it is a little more difficult to understand that 32768 will also be black.

As for lines 152 and on, they're meant to get each of the control rods levels (as there isn't a "getAllControlRodLevels" I don't believe), add them together, and divide them by how many control rods there are. Basically, getting the average. Then, it takes said average and adds it to the current level of rod insertion. The average could have been negative or positive, so it could increase or decrease the amount of insertion.
your problem there is that while the R value does change, the rod value does not, it remains as the return result from invoking that function with a value of R = 0. You will need to continue to query the reactor for each rod as Dragon53535 has shown you.
JakeDaSnake #10
Posted 28 December 2014 - 08:12 AM
The choice of using a binary scale is because, unlike the terminals, bundled cables can support multiple colours on or off, meaning having the colours on the binary scale makes for easier tests for on/off. The reason your 15000 works by setting the text/background colour to green is due to the logic which dan200 uses where it can be represented by the following pseudo-equation color = floor(log2(input)). As we know from maths, log2(x) is the inverse of 2x, thus changing the colour input you give it to a number between 0 and 15.99, This number is then rounded down, meaning it is a whole number between 0 and 15, which map directly to the 16 colours within ComputerCraft. So really, the accurate representation of colors.green would be 213 or 8192.

The reason we use the colors API is simply for readability sake, it is much easier to read and understand that colors.black will output as black, it is a little more difficult to understand that 32768 will also be black.

Ahhh this makes so much sense. Lol I didn't know colors were so complicated.

your problem there is that while the R value does change, the rod value does not, it remains as the return result from invoking that function with a value of R = 0. You will need to continue to query the reactor for each rod as Dragon53535 has shown you.

Yeah, I got that. The way I was doing it was ridiculous! Like I said, I figured there was a better way to do it, I just didn't know how.

I'm doing allot of clipping, deleting, and revising, so I'll be back with my new code soon. Haha let's hope by that time I have it all fixed.

By the way, thanks for the help, theoriginalbit.
JakeDaSnake #11
Posted 28 December 2014 - 08:50 AM
Okay, I'll re-post my code, but the part it's giving me an error at hasn't changed.

New code:
http://pastebin.com/9THs6dd8
Error:


EDIT: This is why I put the "R" and the "local R = 0" that you told me was bad, @Dragon53535. I don't understand why this error comes up. Should I make it "i", to match this piece of code at the end:

  local tot = 0
  for i = 1, 18 do
    tot = tot + rad.getControlRodLevel(i)
  end
?
Edited on 28 December 2014 - 07:59 AM
Lyqyd #12
Posted 28 December 2014 - 08:53 AM
You didn't specify which control rod you wanted to get the level for.
JakeDaSnake #13
Posted 28 December 2014 - 09:30 AM
Okay, I fixed everything, except this:
Spoiler

Code:
Spoilerhttp://pastebin.com/kp5jpSKf
Lyqyd #14
Posted 28 December 2014 - 10:09 AM
BigReactors seems to use 0 - (count - 1) for its control rod indices. Try using 0 - 17 instead of 1 - 18 for the for loop.
JakeDaSnake #15
Posted 28 December 2014 - 10:48 AM
BigReactors seems to use 0 - (count - 1) for its control rod indices. Try using 0 - 17 instead of 1 - 18 for the for loop.
Ahhh, that makes sense. I was using 1-18, thinking it got the actual names of each rod (whatever you type in the gui). Thanks! I'll give it a try!
JakeDaSnake #16
Posted 28 December 2014 - 11:26 AM
Aha! I've done it! Working v1.0 of "Active Reactor OS" is finished! Thanks for all the help guys! I'll be posting it in the programs area of these forums!

Also, I'd like to add, I still don't know as much I'd like to about lua. If you guys could point me in the right direction as far as a guide, or tutorial, or even a video series so I can sharpen my skills, I'd greatly appreciate it!
theoriginalbit #17
Posted 28 December 2014 - 12:08 PM
Also, I'd like to add, I still don't know as much I'd like to about lua. If you guys could point me in the right direction as far as a guide, or tutorial, or even a video series so I can sharpen my skills, I'd greatly appreciate it!
The tutorials within these forums is home to many a good tutorial specifically for ComputerCraft; especially those which are for the 'Ask a Pro' series. The ComputerCraft wiki is home to lots of good resources about the various API's available to us in ComputerCraft. Lastly as an overall Lua resource the Lua 5.1 reference manual is without a doubt the best resource you can get for learning Lua, combined with the tutorials over at Lua-users.org and the occasional Stack Overflow answers coming in handy from time-to-time.
Bomb Bloke #18
Posted 28 December 2014 - 12:23 PM
This tutorial directory (from the aforementioned Lua-users.org) is an excellent resource. I recommend any beginner read from the top down to at least the scope tutorial (though I don't expect them to all sink in at once). The rest aren't really relevant for day-to-day ComputerCraft use, with the possible exception of the co-routines tutorial (as the mod relies on those in order to make all the computers in your MineCraft world run while using just one single Lua VM instance to handle them all, and you'll rely on them too if you ever start trying to handle certain events at the same time).

Getting back to the "variable declarations" thing, it's somewhat interesting to consider what this line actually does:

local counter = counter

It generates a new variable that's localised to the current scope, and assigns it the value of an already existing upvalue.

Now here's the thing - what if you never declared the upvalue prior to reaching this line? Well, the Lua VM will decide that's what you want to do now, and set it up as a new global (set to nil). Thus the one line declares two different variables at once, and since they have the same name, only the local variable will subsequently be accessible within the current scope!

Assuming that makes any sense to you, you can probably see why you generally wouldn't want to do that. However, there is a time when you would consider setting up a local variable to mirror an upvalue - when the upvalue is already defined, and you're going to use its value often within the current scope. You see, accessing variables that're local to the current scope executes faster than accessing upvalues!

Personally I suspect that in most cases, the time spent creating the new local variable would cancel out the time gained by only accessing the upvalue once. It would depend on how often the value is going to be used. But I've noticed that Dan (the current ComputerCraft dev) seems to make a rule of doing it in his Lua code - for quite some time now I've been wanting to sit down and experiment to see if his functions actually benefit from the technique.

Edit:

Oy, what's this?

adj = 0
oldnrg = 0
thisPercent = 0
oldPercent = 0

thisPercent = math.floor((nrg - oldnrg) / nrg * 100)
adj = thisPercent - oldPercent
oldPercent, oldnrg = thisPercent, nrg

That'll result in adj being set to 100 on every single iteration, no matter what nrg is or was. That's no good!

Scrap this lot:

adj = 0  
oldnrg = 0
thisPercent = 0
oldPercent = 0

oldnrg and oldPercent do indeed need to be pre-assigned values before the actual mathy bit runs, but their initial values should be assigned before the loop starts. After that they can just be whatever they were when the last iteration completed. Eg:

local oldPercent, oldnrg = 0, rad.getEnergyStored()

while true do

  act = rad.getActive()
  nrg = rad.getEnergyStored()

  -- etc

  mon.write(f)
  mon.write("%")

  thisPercent = math.floor((nrg - oldnrg) / nrg * 100)
  adj = thisPercent - oldPercent
  oldPercent, oldnrg = thisPercent, nrg

  -- etc

Then you can start wrestling with any issues in the math itself. :)/>
Edited on 28 December 2014 - 11:40 AM