Related
I have a nested table in my lua code that I want to pass to C++ so the native code can manipulate it:
-- Some persistent data in my game
local data = {
{ 44, 34, 0, 7, },
{ 4, 4, 1, 3, },
}
-- Pass it into a C++ function that can modify the input data.
TimelineEditor(data)
How do I write my C++ code to read the nested table and modify its values?
Reading Lua nested tables in C++ and lua c read nested tables both describe how I can read from nested tables, but not how to write to them.
Short answer
Lua uses a stack to get values in and out of tables. To modify table values you'll need to push the table you want to modify with lua_rawgeti, push a value you want to insert with lua_pushinteger, and then set the value in the table with lua_rawseti.
When writing this, it's important to visualize the stack to ensure you use the right indexes:
lua_rawgeti()
stack:
table
lua_rawgeti()
stack:
number <-- top of the stack
table
lua_tonumber()
stack:
number
table
lua_pop()
stack:
table
lua_pushinteger()
stack:
number
table
lua_rawseti()
stack:
table
Negative indexes are stack positions and positive indexes are argument positions. So we'll often pass -1 to access the table at the stack. When calling lua_rawseti to write to the table, we'll pass -2 since the table is under the value we're writing.
Example
I'll add inspect.lua to the lua code to print out the table values so we can see that the values are modified.
local inspect = require "inspect"
local data = {
{ 44, 34, 0, 7, },
{ 4, 4, 1, 3, },
}
print("BEFORE =", inspect(data, { depth = 5, }))
TimelineEditor(data)
print("AFTER =", inspect(data, { depth = 5, }))
Assuming you've figured out BindingCodeToLua, you can implement the function like so:
// Replace LOG with whatever you use for logging or use this:
#define LOG(...) printf(__VA_ARGS__); printf("\n")
// I bound with Lunar. I don't think it makes a difference for this example.
int TimelineEditor(lua_State* L)
{
LOG("Read the values and print them out to show that it's working.");
{
int entries_table_idx = 1;
luaL_checktype(L, entries_table_idx, LUA_TTABLE);
int n_entries = static_cast<int>(lua_rawlen(L, entries_table_idx));
LOG("%d entries", n_entries);
for (int i = 1; i <= n_entries; ++i)
{
// Push inner table onto stack.
lua_rawgeti(L, entries_table_idx, i);
int item_table_idx = 1;
luaL_checktype(L, -1, LUA_TTABLE);
int n_items = static_cast<int>(lua_rawlen(L, -1));
LOG("%d items", n_items);
for (int i = 1; i <= n_items; ++i)
{
// Push value from table onto stack.
lua_rawgeti(L, -1, i);
int is_number = 0;
// Read value
int x = static_cast<int>(lua_tonumberx(L, -1, &is_number));
if (!is_number)
{
// fire an error
luaL_checktype(L, -1, LUA_TNUMBER);
}
LOG("Got: %d", x);
// pop value off stack
lua_pop(L, 1);
}
// pop table off stack
lua_pop(L, 1);
}
}
LOG("Overwrite the values");
{
int entries_table_idx = 1;
luaL_checktype(L, entries_table_idx, LUA_TTABLE);
int n_entries = static_cast<int>(lua_rawlen(L, entries_table_idx));
LOG("%d entries", n_entries);
for (int i = 1; i <= n_entries; ++i)
{
// Push inner table onto stack.
lua_rawgeti(L, entries_table_idx, i);
int item_table_idx = 1;
luaL_checktype(L, -1, LUA_TTABLE);
int n_items = static_cast<int>(lua_rawlen(L, -1));
LOG("%d items", n_items);
for (int j = 1; j <= n_items; ++j)
{
int x = j + 10;
// Push new value onto stack.
lua_pushinteger(L, x);
// rawseti pops the value off. Need to go -2 to get to the
// table because the value is on top.
lua_rawseti(L, -2, j);
LOG("Wrote: %d", x);
}
// pop table off stack
lua_pop(L, 1);
}
}
// No return values
return 0;
}
Output:
BEFORE = { { 44, 34, 0, 7 }, { 4, 4, 1, 3 } }
Read the values and print them out to show that it's working.
2 entries
4 items
Got: 44
Got: 34
Got: 0
Got: 7
4 items
Got: 4
Got: 4
Got: 1
Got: 3
Overwrite the values
2 entries
4 items
Wrote: 11
Wrote: 12
Wrote: 13
Wrote: 14
4 items
Wrote: 11
Wrote: 12
Wrote: 13
Wrote: 14
AFTER = { { 11, 12, 13, 14 }, { 11, 12, 13, 14 } }
My problem is : i gave a series of queries, and a series of references, and i want to count the number of occurance of said keys between them, but only if they have matching keys. I choose to have an LUT because i think it will help me efficiently, but im not sure if there are better ways, or the way im using LUT is not efficient enough.
i have the following data structures.
unordered_map <int, set<int>> Reference_map1, Reference_map2, ... , Reference_mapM;
// to story all the reference maps by their neightas
unordered_map <string, unordered_map <int, set<int>>> ReferenceMaps;
unordered_map <int, set<string>> LUT // look up table
// N is significantly greater than M
unordered_map <int, set<int>> query_map1, query_map2, ... , query_mapN;
Example of Reference_mapi and query_mapj
Reference_map1[111] = {0, 1, 2};
Reference_map1[333] = {1, 2, 3};
Reference_map1[888] = {2, 8, 0};
Reference_map2[111] = {1, 5, 9};
Reference_map2[999] = {0, 7, 4};
ReferenceMaps['Reference_map1']=Reference_map1;
ReferenceMaps['Reference_map2']=Reference_map2;
query_map1[111] = {8, 2, 6};
query_map1[333] = {4, 7, 3};
query_map2[222] = {3, 6, 8};
query_map2[999] = {2, 3, 5};
How i store my look up table LUT
This is so that for whatever keys i get from 'query_mapj', i only get the necessary Reference_mapis
LUT[111] = {'Reference_map1', 'Reference_map2'}
LUT[333] = {'Reference_map1'}
LUT[888] = {'Reference_map1'}
LUT[999] = {'Reference_map2'}
For example 111 from query_map1 gives both 'Reference_map1', 'Reference_map2' as they have the key 111.
On the other hand, 999 from query_map2 only gives 'Reference_map2' as only it have the key 999.
So it will go like this:
unordered_map<string, int> MakeCounter(
unordered_map <int, set<int>> &query_map,
unordered_map <string, unordered_map <int, set<int>>> &ReferenceMaps
){
unordered_map<string, int> RefName_Counter;
set<string> ReferenceNameSet;
// Update the RefName_Counter
for (const auto &key2nameset:query_map) {
// Check if this hash is in the LUT
if (LUT.count(key2nameset.first) <= 0){ continue; }
// Update Counter
ReferenceNameSet = LUT[key2nameset.first];
for (const auto &it : ReferenceNameSet){
if (RefName_Counter.count(it) > 0)
RefName_Counter[it]++;
else
RefName_Counter[it] = 1;
}
}
return RefName_Counter;
}
// The results should be like this
Counter1 = MakeCounter(query_map1, ReferenceMaps);
/*
Counter1['Reference_map1'] = 2; // because they share keys : 111 and 333
Counter1['Reference_map2'] = 1; // because they share keys : 111
*/
Counter2 = MakeCounter(query_map2, ReferenceMaps);
/*
Counter1['Reference_map2'] = 1; // because they share keys : 999
*/
Is there a better way to get Counteri for each respective query_mapi ?
Considering my comment above, here is what I got.
Adjusted to keep original data, but this feels like an extra credit :)
unordered_map<int,int> MakeCounter(const unordered_map <int, set<int>>& qs,
const vector<unordered_map <int, set<int>>>& refs)
{
unordered_map<int, int> counters;
for (size_t i = 0; i < refs.size(); ++i)
{
for (auto q : qs)
{
if (refs[i].find(q.first) != refs[i].end())
counters[i]++;
}
}
return counters;
}
int main()
{
vector<unordered_map <int, set<int>>> References = {
{ {111, { 0, 1, 2 } },
{333, { 1, 2, 3 } },
{888, { 2, 8, 0 } },
},
{ {111, { 1, 5, 9 } },
{999, { 0, 7, 4 } },
}
};
vector<unordered_map <int, set<int>>> Queries = {
{ {111, { 8, 2, 6 } },
{333, { 4, 7, 3 } },
},
{ {222, { 3, 6, 8 } },
{999, { 2, 3, 5 } },
}
};
unordered_map<int, int> m0 = MakeCounter(Queries[0], References);
unordered_map<int, int> m1 = MakeCounter(Queries[1], References);
}
This is rather a comment; I am using "answer" to properly format code fragments.
This searches your LUT twice:
// Check if this hash is in the LUT
if (LUT.count(key2nameset.first) <= 0){ continue; }
// Update Counter
ReferenceNameSet = LUT[key2nameset.first];
It also makes a copy of the set for no reason.
I believe that indexing a non-existing element in the map inserts that element, so
if (RefName_Counter.count(it) > 0)
RefName_Counter[it]++;
else
RefName_Counter[it] = 1;
is effectively:
RefName_Counter[it]++;
So your outer for loop becomes:
for (const auto &key2nameset:query_map) {
// Check if this hash is in the LUT
auto iter = LUT.find(key2nameset.first);
if(iter == LUT.end()) { continue; }
// Update Counter
for (const auto &it : *iter){
RefName_Counter[it]++;
}
I have a series of structs:
const struct weapon Dagger = { 1, 40, 5, 20, 30, "Dagger" };
const struct weapon Sword = { 2, 35, 25, 40, 60, "Sword" };
const struct weapon Axe = { 4, 50, 10, 70, 80, "Axe" };
const struct ...
I want to arrange them so I can access each one by integer. I am trying to build a function that takes int x and int y as arguments, and returns the indexed struct's data. For example, if the function takes 2 and 3, respectively, the value 35 from the weapon struct will be returned. Intuitively, I imagined the function body looking something like return weapon[x].y, although this does not work.
I do not know how to do this. The best alternative I can see is to use arrays instead of structs. Should I do this instead?
If you are only after the numeric data, then you could use two arrays: one for the data itself, and one for accessor function pointers:
struct weapon
{
int val;
int hp;
int foo;
// ...
std::string name;
};
const weapon w[] = {
{ 1, 40, 5, 20, 30, "Dagger" },
{ 2, 35, 25, 40, 60, "Sword" },
{ 4, 50, 10, 70, 80, "Axe" },
};
using accessor = int weapon::*;
const accessor acc[] = {
&weapon::val,
&weapon::hp,
&weapon::foo,
// ...
};
Now to look up property j in weapon i (both zero-indexed), you could say:
w[i].*acc[j]
Alternatively, you could perhaps represent your data as an array of pairs:
std::pair<const char*, std::array<int, 5>> w_alt[] = {
{ "Dagger", { 1, 40, 5, 20, 30 } },
{ "Sword", { 2, 35, 25, 40, 60 } },
{ "Axe", { 4, 50, 10, 70, 80 } },
};
Now the ith weapon's anme is w_alt[i].first, and its jth property is w_alt[i].second[j].
If you want a container that has indexed access, you probably want std::vector. Something like:
std::vector<weapon> WeaponVector;
For the first part of your question (selecting weapon based on index), using an array is a simple option, e.g.:
std::array<weapon, 3> const weapons =
{ { 1, 40, 5, 20, 30, "Dagger" }
, { 2, 35, 25, 40, 60, "Sword" }
, { 4, 50, 10, 70, 80, "Axe" }
};
Then, if you want, you can make specific references:
weapon const &Sword = weapons[1];
or make indices which you'll use to access the array:
enum weapon_id { Dagger, Sword, Axe };
// ...
do_something( weapons[Sword] );
Using std::array instead of a C-style array weapon const weapons[] =
has a drawback that you can't deduce the dimension, but it has other benefits that make up for this.
For the second part, you may add a function that looks up the weapon properties by index. For example:
int weapon_lookup_number(weapon const &w, int index)
{
switch(index)
{
case 0: return w.id;
case 1: return w.power;
// etc.
}
}
with another function for looking up the string.
Using template specialization it'd be possible to have a function that looks up the member by index and evaluates to the correct type, however that would only work in the case of the index being known at compile-time.
If your struct becomes:
struct weapon {
int val;
int hp;
int foo;
// ...
std::string name;
};
You could use a std::vector<weapon> Weapons to store the structs, sort it using:
std::sort(Weapons.begin(), Weapons.end(),
[](const Weapons& w1,const Weapons& w2) -> bool { return w1.val > w2.val; }))
and access them using the vector indexes like: weapons[some_num].hp;, where some_num will correspond to the wanted val.
This is my code
std::ifstream infile("/home/alexander/MyCompany/MyGame/Resources/res/puzzles(copia).json");
std::string line;
std::ofstream ofs("/home/alexander/MyCompany/MyGame/Resources/res/temporal.json", std::ofstream::out);
Document d;
while (std::getline(infile, line))
{
d.Parse(line.c_str());
if (d.HasParseError()) CCLOG("GetParseError %s\n", d.GetParseError());
if (d.IsObject() && d.HasMember("Lados"))
{
rapidjson::Value& a = d["Lados"]; // Using a reference for consecutive access is handy and faster.
rapidjson::Document::AllocatorType& allocator = d.GetAllocator();
assert(a.IsArray()); // explotar si no es un arreglo
a.PushBack(4, allocator).PushBack(8, allocator).PushBack(15, allocator).PushBack(16, allocator).PushBack(23, allocator).PushBack(42, allocator);
}
// Convertir JSON a string e Insertar en archivo
StringBuffer strbuf;
Writer<StringBuffer> writer(strbuf);
d.Accept(writer);
ofs << strbuf.GetString() << "\n";
}
ofs.close();
infile.close();
// ACTUALIZA ARCHIVO PRINCIPAL & LIMPIA TEMPORAL
std::ifstream src("/home/alexander/MyCompany/MyGame/Resources/res/puzzles(copia).json");
std::ofstream dst("/home/alexander/MyCompany/MyGame/Resources/res/temporal.json");
dst << src.rdbuf();
src.close();
dst.close();
if (remove("/home/alexander/MyCompany/MyGame/Resources/res/temporal.json") != 0) CCLOG("Error deleting file");
CCLOG("save");
As you can see I'm creating a new file called temporal in which'll put my modified file, then pass it back to the original file.
the problem is that when I do that the file does not change,it is created and properly cleared but the file orginal is not modify and don't know why?.
I am using cocos2d-x, c ++ and rapidjson.
not if I need to give permission for my program to modififque arhivos or something like that
JSON has several lines in this format:
{ "N" : 5, "Rotacion" : 42, "Igual" : 20, "Inverso" : 0, "RotacionE" : 47, "Espejo" : 22, "Puntuacion" : 0, "_id" : "563b7b4756ab632f47fe6d7f" , "Lados" : [], "Camino" : [ 6, 5, 4, 21, 22, 7, 2, 3, 20, 23, 8, 1, 18, 19, 24, 9, 0, 17, 16, 15, 10, 11, 12, 13, 14 ], "__v" : 0 }
as I can see your code is ok, what you have to do is reverse the direction of your files .json right now you have it like so:
std::ifstream src("/home/alexander/MyCompany/MyGame/Resources/res/puzzles(copia).json");
std::ofstream dst("/home/alexander/MyCompany/MyGame/Resources/res/temporal.json");
but you have to put it like this :
std::ifstream src("/home/alexander/MyCompany/MyGame/Resources/res/temporal.json");
std::ofstream dst("/home/alexander/MyCompany/MyGame/Resources/res/puzzles(copia).json");
I seem to have an issue with my CheckBet() method for a Slot Machine I'm making.
Basically, I check the users bet before I spin the Machines wheels.
For some reason CheckBet() is returning true. I'm unsure what I'm doing incorrectly.
The Problem is, the "SETUP CODE" will ALWAYS run.
SETUP CODE
validbet = CheckBet(Player_Bet, Player_Chips);
if(validbet);
{
Player_Chips = DeductChips(Player_Bet, Player_Chips);
RedrawStatistics(Player_Chips, Winning_Chips, Player_Bet);
//Winning_Chips = CheckResult(SpinChamber(40, 11, 2), SpinChamber(39, 11, 1), SpinChamber(38, 11, 0), Player_Bet);
}
CHECKBET
inline bool CheckBet(int Player_Bet, int Player_Chips)
{
bool validbet = true;
if (Player_Bet <= 0)
{
Draw_String(26, 17, "You Must Bet at least 20 Chips");
validbet = false;
}
else if (Player_Bet > Player_Chips)
{
Draw_String(26, 17, "You don't own that many chips!");
validbet = false;
}
return validbet;
}
This is the problem:
if(validbet);
Your if statement isn't doing anything!
Then this block of code gets executed always - it's not related to the if:
{
Player_Chips = DeductChips(Player_Bet, Player_Chips);
RedrawStatistics(Player_Chips, Winning_Chips, Player_Bet);
//Winning_Chips = CheckResult(SpinChamber(40, 11, 2), SpinChamber(39, 11, 1), SpinChamber(38, 11, 0), Player_Bet);
}
remove the ; after the if statement so that the block is the statement that the if applies to:
if(validbet)
{
Player_Chips = DeductChips(Player_Bet, Player_Chips);
RedrawStatistics(Player_Chips, Winning_Chips, Player_Bet);
//Winning_Chips = CheckResult(SpinChamber(40, 11, 2), SpinChamber(39, 11, 1), SpinChamber(38, 11, 0), Player_Bet);
}