bulletsPlayer1 = {
Pistol = {},
Shotgun = {}
}
bulletsPlayer2 = {
Pistol = {},
Shotgun = {}
}
I have these tables, and I have this function to create bullets:
function createBullet(x, y, angle, speed, weapon, player)
local directionx = speed * math.cos(angle)
local directiony = speed * math.sin(angle)
table.insert(
"bulletsPlayer"..player.."."..weapon,
{
positionx = x,
positiony = y,
directionx = directionx,
directiony= directiony,
speed = speed
}
)
end
For example if I call this function like this
createBullet(100,100,0,300,'Shotgun',1)
I am receiving this error:
shooting.lua:77: bad argument #1 to 'insert' (table expected, got string)
How can I make my code recognize the first argument of the table.insert() as my tables and not strings?
How can I make my code recognize the first argument of the table.insert() as my tables and not strings?
That's... not how Lua works. A string is a string, a table is a table. If you want to index your players by number, store them in a table:
local bulletsPlayer = {
{
Pistol = {},
Shotgun = {}
};
{
Pistol = {},
Shotgun = {}
};
}
Then you can index it with a number like this
bulletsPlayer[1]["shotgun"]
"bulletsPlayer"..player.."." ..weapon is a string. So the error message is exactly what you should expect.
You cannot just build variable names from strings and hope Lua will know what to do.
As bulletsPlayer1 is a global table value you can access it through the global environment.
_ENV["bulletsPlayer"..player][weapon]
Refer to https://www.lua.org/manual/5.3/manual.html#2.2
But usually you just use table keys to get what you need. You don't build global names from strings.
Then you should have something like:
local players{[1] = {bullets = {shotgun = 20, pistol = 9}}}
But if you're going that way you might want to read something about OOP in Lua. If bullets are a property of your player, why not store that information in a player object. Also metatables can make your life much easier.
Related
I want to make coding about the final score display. If someone has done 10 multiple choice questions and he clicks on the final score button, then his final score will appear along with the description. The score will be made in a range according to the category, namely 1-59 = Under Average, 60-79 = Average, and 80-100 = Above Average.
I've tried coding it but I found error 1176 on line 7 and 11.
Can you help me fix it?
finalscorebutton.addEventListener(MouseEvent.CLICK, finalscore);
function finalscore(event:MouseEvent):void
{
multiplechoicefinalscore.text = sumofscores;
var finalscore:String = finalscore.toString;
finalscore = multiplechoicefinalscore..text;
if(finalscore.toString < 60){
description.text =
"UNDER AVERAGE.";
}
else if(finalscore.toString >= 60 && finalscore.toString <=79){
description.text =
"AVERAGE.";
}
else{
description.text =
"ABOVE AVERAGE.";
}
}
There are multiple syntax and logic errors.
Something.toString is a reference to a method, you probably mean Something.toString() which calls the said method and returns a text representation of whatever Something is.
You don't need a text representation because you want to compare numbers, you need a numeric representation (which is either int, uint or Number).
There are 2 dots in multiplechoicefinalscore..text, what does it even mean?
There is function finalscore and then you define var finalscore, defining things with the same names is a bad idea in general.
You should keep your script formatted properly, otherwise reading it and understanding would be a pain.
So, I assume you have the user's result is in sumofscores. I'm not sure if the script below will actually work as is, but at least it is logically and syntactically correct:
finalscorebutton.addEventListener(MouseEvent.CLICK, onFinal);
function onFinal(e:MouseEvent):void
{
// Ok, let's keep this one, I think you are putting
// the score result into some kind of TextField.
multiplechoicefinalscore.text = sumofscores;
// Get a definitely numeric representation of the score.
var aScore:int = int(sumofscores);
// In terms of logic, putting the complicated condition case
// under the "else" statement will simplify the program.
if (aScore < 60)
{
description.text = "UNDER AVERAGE.";
}
else if (aScore > 79)
{
description.text = "ABOVE AVERAGE.";
}
else
{
description.text = "AVERAGE.";
}
}
I am looking to solve a problem for different iteration and I need to read for each iteration data from a sheet in the same Excel file, like I want to solve my model for let's say for 4 times/iteration with at each time different data read from Excel on 4 different sheets / iteration. Is there any tricky code that I can implement on my main blog, to add this data first and solve the problem?
Suppose you have an Excel spreadsheet with 3 tabs for 3 options for number of kids:
Then in order to do a loop for those 3 options:
You first write
zooexcelmultisheet.mod
string paramsread=...;
tuple param
{
int nbKids;
}
{param} params=...;
assert card(params)==1;
int nbKids=first(params).nbKids;
// a tuple is like a struct in C, a class in C++ or a record in Pascal
tuple bus
{
key int nbSeats;
float cost;
}
// This is a tuple set
{bus} buses=...;
// asserts help make sure data is fine
assert forall(b in buses) b.nbSeats>0;
assert forall(b in buses) b.cost>0;
// decision variable array
dvar int+ nbBus[buses];
// objective
minimize
sum(b in buses) b.cost*nbBus[b];
// constraints
subject to
{
sum(b in buses) b.nbSeats*nbBus[b]>=nbKids;
}
tuple result
{
key int nbSeats;
int nbBuses;
}
{result} results={<b.nbSeats,nbBus[b]> | b in buses};
execute
{
writeln(results);
writeln("cost = ",cplex.getObjValue());
}
and then zooexcelmultisheet.dat
SheetConnection s("zoomultisheet.xlsx");
//paramsread="params1!A2";
params from SheetRead(s,paramsread);
buses from SheetRead(s,"buses!A2:B3");*
and then what you will run do do the loop for all 3 options:
{string} sheets={"params1","params2","params3"};
main {
var source = new IloOplModelSource("zooexcelmultisheet.mod");
var cplex = new IloCplex();
var def = new IloOplModelDefinition(source);
var data = new IloOplDataSource("zooexcelmultisheet.dat");
for(var sheet in thisOplModel.sheets)
{
var data0=new IloOplDataElements();
data0.paramsread=sheet+"!A2";
var opl = new IloOplModel(def,cplex);
opl.addDataSource(data0);
opl.addDataSource(data);
opl.generate();
if (cplex.solve()) {
opl.postProcess();
} else {
writeln("No solution");
}
opl.end();
}
data.end();
def.end();
cplex.end();
source.end();
}
and you will get
{<40 6> <30 2>}
cost = 3800
{<40 7> <30 1>}
cost = 3900
{<40 8> <30 0>}
cost = 4000
I'm trying to query a database and store the results in a Groovy map data structure with some nested data elements and can't seem to figure it out.
Here's my latest attempt -
#!/usr/bin/env groovy
import groovy.sql.Sql;
// code to connect to database omitted
TreeMap tsMap = [:];
def tabcount = 0, inxcount = 0;
dbconn.eachRow("SELECT table_name,tablespace_name FROM user_tables") {
tabcount += 1;
if (tsMap.containsKey(it.tablespace_name)) {
tsMap[it.tablespace_name].tabs++;
} else {
type = [tabs:1];
tsMap[it.tablespace_name] = type;
}
}
dbconn.eachRow("SELECT index_name,tablespace_name FROM user_indexes") {
inxcount += 1;
if (tsMap.containsKey(it.tablespace_name) {
tsMap[it.tablespace_name].inxs++;
} else {
type = [inxs:1];
tsMap[it.tablespace_name] = type;
}
}
tsMap.eachWithIndex { entry, i ->
printf("%3d - Tablespace: %-30s contains %4d tables and %4d indexes\n",
i, entry.key, entry.value.tabs, entry.value.inxs);
}
printf("Total table count = %d\n", tabcount);
printf("Total index count = %d\n", inxcount);
And here's what I want tsMap to end up with -
tsMap = [TS1:[tabs:10], TS2:[tabs:35, inxs:12]]
The TS1 entry (where there are only "table" entries and no "index" entries) works but as soon as there are also index entries I end up with -
tsMap = [TS1:[tabs:10], TS2:[inxs:12]]
even though TS2 also has 35 tables in addition to the 12 indexes.
My goal is to get tsMap to look like -
tsMap = [TS1:[tabs:10], TS2:[tabs:35, inxs:12]]
I use associative arrays in other languages and run into similar challenges anytime attempting to store arrays (of any kind) in them to create complex data structures. With Groovy's Java underpinning I expected it to be easy and straightforward but if so then I'm missing something.
I'm already not happy with the complexity of this code as is and would appreciate pointers on how to simplify it. I expected this to be very simple and straightforward, even trivial, and I took a wrong turn somewhere and it's anything but simple at this point.
Obviously I could just have two maps and end up with -
tabMap = [TS1:10, TS2:35]
inxMap = [TS2:12]
but of course this is also an exercise in understanding how to go beyond simple associative arrays (maps) so any help would be appreciated as I'm working on my Groovy skills.
So based on #cfrick's feedback I've tried this, much more streamlined code -
TreeMap tsMap = [:].withDefault{ [tabs:0, inxs:0] };
def tabcount = 0, inxcount = 0;
workconn.eachRow("SELECT table_name,tablespace_name FROM user_tables") {
tsMap[it.tablespace_name].tabs++;
}
workconn.eachRow("SELECT index_name,tablespace_name FROM user_indexes") {
tsMap[it.tablespace_name].inxs++;
}
which really seemed to make sense and I thought it was going to do it but I end up with -
Caught: java.lang.NullPointerException: Cannot get property 'tabs' on null object
java.lang.NullPointerException: Cannot get property 'tabs' on null object
which previously I've learned is because Groovy can't find that nested map with the "tabs" key to be able to increment it.
I thought the .withDefault was going to add my nested map to any "key" that I added to the tsMap.
Any advice on where I've gone wrong is appreciated.
SOLUTION
OK, with #cfrick's help the objective is now working and here's the final code:
#!/usr/bin/env groovy
import groovy.sql.Sql;
// code to connect to database omitted
// avoid types other than def as they cast away the .withDefault
def tsMap = [:].withDefault{ [tabs:0, inxs:0] };
workconn.eachRow("SELECT table_name,NVL(tablespace_name, '(null)') tsName FROM user_tables") {
tsMap[it.tsName].tabs++;
}
workconn.eachRow("SELECT index_name,NVL(tablespace_name, '(null)') tsName FROM user_indexes") {
tsMap[it.tsName].inxs++;
}
def fmt = (opt.geninput) ? "%d,%s,%d,%d,%s\n" : "%3d - Tablespace: %-25s contains %4d tables and %4d indexes %s\n";
tsMap = tsMap.sort(); // sort the keys
tsMap.eachWithIndex { entry, i ->
printf(fmt, i, entry.key, entry.value.tabs, entry.value.inxs, (entry.value.tabs * entry.value.inxs != 0) ? "**" : "");
}
printf("Total table count = %d\n", tsMap.values()*.tabs.sum());
printf("Total index count = %d\n", tsMap.values()*.inxs.sum());
Thanks!
I am having a problem figuring out how to reference elements of a sub structure.
See: http://play.golang.org/p/pamS_ZY01s
Given something like following.... How do you reference data in the room struct? I have tried fmt.Println(*n.Homes[0].Rooms[0].Size), but that does not work.
Begin Code example
package main
import (
"fmt"
)
type Neighborhood struct {
Name string
Homes *[]Home
}
type Home struct {
Color string
Rooms *[]Room
}
type Room struct {
Size string
}
func main() {
var n Neighborhood
var h1 Home
var r1 Room
n.Name = "Mountain Village"
h1.Color = "Blue"
r1.Size = "200 sq feet"
// Initiaize Array of Homes
homeslice := make([]Home, 0)
n.Homes = &homeslice
roomslice := make([]Room, 0)
h1.Rooms = &roomslice
*h1.Rooms = append(*h1.Rooms, r1)
*n.Homes = append(*n.Homes, h1)
fmt.Println(n)
fmt.Println(*n.Homes)
}
First, *[]Home is really wasteful. A slice is a three worded struct under the hood, one of them being itself a pointer to an array. You are introducing a double indirection there. This article on data structures in Go is very useful.
Now, because of this indirection, you need to put the dereference operator * in every pointer-to-slice expression. Like this:
fmt.Println((*(*n.Homes)[0].Rooms)[0].Size)
But, really, just take out the pointers.
I need a thread safe data structure with three operations: remove, getRandom, reset.
I have only two ideas by now.
First: Seq in syncronized var.
val all: Array[String] = ... //all possible.
var current: Array[String] = Array.empty[String]
def getRandom(): = {
val currentAvailable = current
currentAvailable(Random.nextInt(currentAvailable.length))
}
def remove(s: String) = {
this.syncronized {
current = current diff Seq(s)
}
}
def reset(s: String) = {
this.syncronized {
current = all
}
}
Second:
Maintain some Map[String,Boolean], there bool is true when element currently is present. The main problem is to make a fast getRandom method (not something like O(n) in worst case).
Is there a better way(s) to implement this?
Scala's Trie is a lock free data structure that supports snapshots (aka your currentAvailable) and fast removals
Since I'm not a Scala expert so this answer is general as an example I used Java coding.
in short the answer is YES.
if you use a map such as :
Map<Integer,String> map=new HashMap<Integer,String>(); //is used to get random in constant time
Map<String,Integer> map1=new HashMap<String,Integer>(); //is used to remove in constant time
to store date,
the main idea is to keep the key( in this case the integer) synchronized to be {1 ... size of map}
for example to fill this structure, you need something like this:
int counter=0; //this is a global variable
for(/* all your string (s) in all */ ){
map.put(counter++, s);
}
//then , if you want the removal to be in constant time you need to fill the second map
for(Entry e : map.EntrySet(){
map1.put(e.getValue(),e.getKey());
}
The above code is the initialization. everytime you want to set things you need to do that
then you can achieve a random value with O(1) complexity
String getRandom(){
int i; /*random number between 0 to counter*/
return map.get(i);
}
Now to remove things you use map1 to achive it in constant time O(1);
void remove(String s){
if(!map1.containsKey(s))
return; //s doesn't exists
String val=map.get(counter); //value of the last
map.remove(counter) //removing the last element
int thisCounter= map1.get(s); //pointer to this
map1.remove(s); // remove from map1
map.remove(counter); //remove from map
map1.put(thisCounter,val); //the val of the last element with the current pointer
counter--; //reducing the counter by one
}
obviously the main issue here is to keep the synchronization ensured. but by carefully analyzing the code you should be able to do that.