Combining two items (recipe-like) - actionscript-3

I'd like a user to be able to combine two items and if compatible will yield a new item. In this example, the item IDs will be saved as Strings.
I was wondering what the most efficient way to do this would be, while making sure that swapped order will always yield the same result, so the user could input the order:
item X + item Y = item Z
item Y + item X = item Z
I've tried using Dictionaries and Objects, but I just haven't been able to get anything to work. I've also tried some various libraries that include HashMap/HashSet but nothing is working. here's some pseduo-code:
itemRecipe1:HashSet = new HashSet();
itemRecipe1.add("2");//Add item with ID of 2
itemRecipe1.add("3");//Add item with ID of 3
inputRecipe:HashSet = new HashSet();
inputRecipe.add("3");//Add item with ID of 3 (swapped)
inputRecipe.add("2");//Add item with ID of 2 (swapped)
recipeList:HashMap = new HashMap();
receipeList.put(itemRecipe1, "11");//Recipe has been added, the result of the recipe should be item 11
//This should output as TRUE since the composition of itemRecipe1 and inputRecipe are the same, despite a different input order.
trace(receipeList.containsKey(inputRecipe));
If anyone has a solution for this issue, please elt me know as I am willing to implement any design I can get working. I just don't see how a Dictionary could work as the key order matters.

So you're trying to associate two or more objects with each other. The first thing you need is some primitive data you can use to represent each item uniquely, typically an ID. This should give you something like the following to begin with:
class Item {
public var _id:int;
public function Item(id:int) {
_id = id;
}
public function get id():int { return _id; }
}
Now you need some piece of data that establishes a relationship between multiple Items using this ID. That could be as simple as the following, with a little extra functionality thrown in to see if an input list of these IDs matches the relationship:
class ItemRelationship {
private var _items:Vector.<Item>;
public function ItemRelationship(items:Vector.<Item>) {
_items = items;
}
public function matches(ids:Vector.<int>):Boolean {
if (_items.length !== ids.length) {
return false;
}
for each (var item:Item in _items) {
var found:Boolean = false;
for each (var id:int in ids) {
if (item.id === id) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
public function get items():Vector.<Item> { return _items; }
}
This lets us do something like this, assuming we have a bunch of items (item1, item2, ...) with IDs.
var rel:ItemRelationship = new ItemRelationship(new <Item>[item1, item2]);
And then:
trace(rel.matches(new <int>[1,2])); // true
trace(rel.matches(new <int>[2,1])); // true
trace(rel.matches(new <int>[3,4])); // false
Now all we need is something that stores all of these relationships and lets us fetch one based on a list of input IDs:
class RelationshipCollection {
private var _relationships:Vector.<ItemRelationship>;
public function RelationshipCollection(relationships:Vector.<ItemRelationship>) {
_relationships = relationships;
}
public function find(ids:Vector.<int>):ItemRelationship {
for each(var relationship:ItemRelationship in _relationships) {
if (relationship.matches(ids)) return relationship;
}
return null;
}
}
Put a load of relationships in there:
var collection:RelationshipCollection = new RelationshipCollection(new <ItemRelationship>[
new ItemRelationship(new <Item>[item1, item4]),
new ItemRelationship(new <Item>[item2, item3])
]);
And give it a whirl:
trace(collection.find(new <int>[1, 3])); // null (no match)
trace(collection.find(new <int>[1, 4])); // works
trace(collection.find(new <int>[3, 2])); // works
trace(collection.find(new <int>[2, 3])); // works
Of course for the sake of readability you can rename each class to something more appropriate for its application e.g. Item => Potion, ItemRelationship => Recipe, RelationshipCollection => RecipeBook.

so the user could input the order
The first step is to limit the possible input. If you allow any type of input, you have to parse that input and things get complicated very quickly.
Create an input method that only allows the user to put two items together, say for example via drag and drop of the items to only 2 slots.
I just don't see how a Dictionary could work as the key order matters.
The important part is to design the keys well.
As #George Profenza pointed out in the comments, you could change your IDs to a different format. Instead of having 1, 2, 3, ... n you could use 1, 2, 4, ... 2^n. The advantage is that you can combine any two IDs uniquely via bitwise or operator (|). In the following example, two such IDs are combined (binary notation):
00001
| 10000
--------
10001
As you can see, each ID occupies a separate position in binary: the 1st position and the 5th. Combining both via or operator means that now both 1st and 5th position are 1. The order doesn't matter. If you use such IDs in the form of powers of 2 you can combine them regardless of the order to form pairs, which can then be used as keys to a dictionary.
Another solution is to simply sort the pair of IDs.
The combination 3-2 becomes 2-3 and the combination 2-3 stays 2-3. Both 2-3 and 3-2 lead to the same result.
You can then build your data structure accordingly, that is: the outer data structure is for the lower ID number and the nested, inner one is for the bigger ID number. Here's some pseudo code with generic objects:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
To access that, you'd do something like:
trace(map[Math.min(ID1, ID2)][Math.max(ID1, ID2)])
There's also the brute force way of doing it by storing both possible combinations in the data structure. The code for that could roughly look like that:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
map["3"] = {"2":"combination 2-3"};
Now both
trace(map[ID1][ID2]);
and
trace(map[ID2][ID1]);
Should yield the same result.

Related

Using objects instead of arrays

I've spent nearly 1 week to learn working with objects instead of arrays. I had thought it was easy to call them and created some objects and set their properties. However I can't access them now, I tried this:
function onBoxClick(event:MouseEvent):void {
var str:String = event.currentTarget.name;
trace(str);
str = str.substring(str.indexOf("_") + 1);
trace(getChildByName("copy_" + str)); // trying to trace an object by name
}
My question is if there's a practical way of dealing with objects, otherwise what's the purpose of using them.
Edit: Here's my function that I use to create movieclips and other things:
function addBoxes(isUpdate:Boolean):void {
var copyOne:Object = getReadOnlyValues();
copyOne.name = "copy_" + num;
// Set default mc1 settings
var settings1:Object = copyOne.mc1Settings;
for(var num2:String in settings1) {
copyOne.mc1[num2] = settings1[num2];
}
// Set default mc1text settings
var settings2:Object = copyOne.mc1TextSettings;
for(var num3:String in settings2) {
copyOne.mc1Text[num3] = settings2[num3];
}
copyOne.mc1.x = nextXpos;
copyOne.mc1.name = "captionBox_" + num;
addChild(copyOne.mc1);
copyOne.mc1.addEventListener(MouseEvent.CLICK, onCaptionClick);
copyOne.mc1Text.name = "captionBoxText_" + num;
copyOne.mc1.addChild(copyOne.mc1Text);
// ---------------------------------------------------------------
// Set default mc2 settings
var settings4:Object = copyOne.mc2Settings;
for(var num4:String in settings4) {
copyOne.mc2[num4] = settings4[num4];
}
// Set default mc2text settings
var settings5:Object = copyOne.mc2TextSettings;
for(var num5:String in settings5) {
copyOne.mc2Text[num5] = settings5[num5];
}
copyOne.mc2.x = nextXpos;
copyOne.mc2.y = copyOne.mc1.height;
copyOne.mc2.name = "box2_" + num;
addChild(copyOne.mc2);
copyOne.mc2Text.name = "box2BoxText_" + num;
copyOne.mc2.addChild(copyOne.mc2Text);
copyOne.mc2.addEventListener(MouseEvent.CLICK, onBoxClick);
if (num / subunits is int) {
trace (num);
// createMc("normalBox", true);
}
nextXpos = nextXpos + copyOne.mc2.width;
// traceObj(copyOne);
// traceObj(getReadOnlyValues());
}
I called this function in a loop so I created many movieclips. Now I can't access objects' properties and their childen (e.g textfield).
Objects I have on stage: Movieclips and textfields
Where they come from: The function above
What I'm trying to do with them: Tracing movieclips and textfields (that are holded by objects) to change their children (textfield) text
What happens instead of what I expect: Trace code outputs undefined instead of giving me object type trace(getChildByName("copy_" + str)); // trying to trace an object by name
Is there a practical way of accessing an object whose name is "copy_1" and its property whose name is "box2_1" (movieclip)?
One problem I see is the "copyOne" object has been created within the scope of "addBoxes", so it will no longer exist outside of this function.
Another is you're trying to access an Object via getChildByName, which only addresses displayObjects of the displayObjectContainer you are calling from.
If you want to loosely keep track of variables with things like Objects or MovieClips (which are both dynamic-style objects that let you add properties to them as you wish), just use MovieClips to house your values. The movieClips, being on the stage, will be retained in memory until removed from the displayList (stage).
Also, check out the Dictionary, a sort of key/value based way of storing collections of objects.
Better yet, if you use strongly-typed custom objects (creating your own classes to extend MCs, and adding your own public or private methods and values), there are benefits such as using Vectors (fancy, fast arrays that are compatible with any Object type you choose).
I don't really know if I understood your question or not, but as #ozmachine said in his answer, you can not use getChildByName, instead I think that you can take a look on this, may be it can help :
var container:DisplayObjectContainer = this;
function getReadOnlyValues():Object {
return {
mc1: new box(),
mc1: {
name: 'mc1_',
alpha: 1,
x: 0,
y: 0,
width: 30,
height: 25
},
mc1Text: new TextField(),
mc1Text: {
text: 'test',
x: 0,
y: 0,
selectable: false,
multiline: false,
wordWrap: false
}
}
};
// create 5 objects
for(var i=0; i<5; i++){
container['copy_'+i] = getReadOnlyValues();
var obj:Object = getObjectByName('copy_'+i);
obj.mc1.alpha = 1;
obj.mc1.x = 0;
obj.mc1.y = 50 * i;
obj.mc1.width = 100;
obj.mc1.addChild(obj.mc1Text);
obj.mc1Text.text = 'test_' + i;
addChild(obj.mc1);
}
// get object by name
function getObjectByName(name:String):Object {
return container[name];
}
// change the text of the 4th button
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
var obj:Object = getObjectByName('copy_3');
obj.mc1Text.text = 'new text';
})
Array and Object are both data structures.
Data means some form of information.
Data structure means some form of information being stored in a certain way.
Array and Object are two different ways to store information.
Arrays identify data with integer numbers.
An integer number to identify a single element of an array is called an index
Arrays are ideal to represent a list of similar things that belong to each other.
var names:Array = ["John", "Paul", "George", "Ringo"];
This often means that the elements of an array are of the same type, like in the example above.
But they don't have to:
var numbers:Array = [42, "twenty-five", "XIIV"];
For the above examples it's easy to answer the questions "What are the names of the four beatles?", "What different representations of numbers did you stumble upon during your trip through the historic town?". Other questions are harder or impossible to answer. "What Roman numerals did you stumble upon in the historic town?"
Objects identify data with names.
A name to identify a single element of an object is called a property
Objects are ideal to represent a list of dissimilar things that belong to each other.
var paula:Object = {age:37, name:"Paula", hairColor:0x123456};
This often means that the elements of an object are of different type, like in the example above.
But they don't have to:
var car:Object = {manufacturer:"Porsche", color:"red", sound:"wroooooom", soundOfDriver:"weeeeeeeeeeee"};
Considering this, let's take a look at your code and see how it applies.
The big picture is that you have a function addBoxes that you call multiple times. As one function should have one purpose, this function will do something similar every time it is executed. Uh-Oh: "similar". Whatever the result of this function is, it should go into an array. Each call to that function would be an element of the array. You can see this clearly on your use of "num" to identify whatever is happening in your current run of the function.
What data is present in your function?
copyOne
mc1
mc1Text
mc2
mc2Text
copyOne is a troublemaker here and what causes your confusion. It's trying to do everything at once and therefore you are not able to think clearly about when to use a Array and when Object. One would call it a god object. And that's not a good object to have around.
Your choice for variable names is very bad.
You choose super generic names like "mcX" only to later add a name property to it that describes what it truly is.
But even that doesn't hold true for whatever "Box2" is supposed to be.
Choose names so that it'S easy to understand what something in your code is.
It looks like you created all or parts of this structure jsut for this question and therefore lacked meaningful names.
I highly recommend that you do not learn by such made up projects. But from the real world.
I will therefore impose the following goal:
mc1 and mc1Text represent a caption
mc2 and mc2Text represent a content
With all this, I ask again:
What data is present in your function?
captionBox
captionText
contentBox
contentText
Both caption and content consist of a box and a text.
These are different things, so caption and content are each an object with properties "box" and "text"
One could think that due to this similarity, they both should go into an array.
But I beg to differ. A caption and a text are not the same thing. You deal with captions and texts differently. Walking on the streets you might catch a big caption in the news quickly, but not a lengthy text. That's why each of them should be a property of the object that's created in the function.
Here's somewhat of a conclusion:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var boxes:Object = {};
//the box consists of caption & content, both bying of the same type, but are containing different data
boxes.caption = {box:{}, text:{}}; //caption
boxes.content = {box:{}, text:{}}; //content
allBoxes.push(boxes);
}
This is it. That's how and why I would model your data with objects and arrays.
But it doesn't end here. My conclusion lacks a lot of the code you posted.
While the above is mostly language independent, the missing code is specific to Actionscript and not just on how to model data. It's as follows...
As3 is object oriented.
This is good, because the above conclusion has a lot of objects in it.
To define how some object is/does/moves/farts/etc, one creates classes.
The following changes take place (for reasons out of the scope of this answer):
createBoxes (formerly known as addBoxes) calls the constructor of
a class "CaptionAndContent" that extends Sprite.
There's no more need to explicitely create an object "boxes" as the constructor does exactly that.
The caption and content will not have a property "box", because
they can be the box themselves. This is exactly how it's done in the
code of the question. The default settings are set in the constructors of their classes.
Here's reduced snippet of code that hopefully illustrates how the classes could look like.
Each class should be in its own file, with the necessary imports, package block and the additional functionality that you did not specify in your question.
public class CaptionAndContent extends Sprite
{
private var caption:Caption;
private var content:Content;
public function CaptionAndContent(captionText:String = "", contentText:String = "")
{
caption = new Caption(captionText);
addChild(caption);
content = new Content(contentText);
content.y = caption.height;
addChild(content);
}
}
public class ClickableBoxWithText extends Sprite
{
protected var textField:TextField;
public function ClickableBoxWithText(text:String = "")
{
textField = new TextField();
textField.text = text;
addChild(textField);
addEventListener(MouseEvent.CLICK, onClick);
}
protected function onClick(mouseEvent:MouseEvent):void
{
//override this in a sublclass
}
}
public class Caption extends ClickableBoxWithText
{
public function Caption(text:String = "")
{
super(text);
// apply all the default settings of caption here.
}
}
public class Content extends ClickableBoxWithText
{
public function Content(text:String = "")
{
super(text);
// apply all the default settings of content here.
}
}
Using them would look something like this:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var captionAndContent:CaptionAndContent = new CaptionAndContent("This is the caption...", "...for this content");
captionAndContent.x = nextXpos;
addChild(captionAndContent);
allBoxes.push(captionAndContent);
}
Last but not least, the identification problem in the click handler.
Your question already contains the answer:
event.currentTarget
That's the reference to the object that was clicked on.
In my code it would be
mouseEvent.currentTarget
This identifies the object already. It's pointless to look up one of its properties (its name for example) in order to search all the objects for that name, just to identify the same object that you already had to identify (without a name) in order to get the name.
You aren't identifying the objects by name anyway. What differs between the names and what supposedly makes them unique is a number at their end. As pointed out in this answer, this is what's called an index and the thing you are trying to identify with it should go into an array. In my example codes, this is allBoxes.

getting a random element from an array of movieclips(or labels in a timeline) in Flash CC . Actionscript 3

I am making a pretty neat quiz-game in flashCC right now and I definitely need your help.
My skills are more on the design then the programming side. So to many of you this might seem a baby question (and asked many times before) but from all the answers I saw so far, I couldn't get any results for my project.
So here is the thing :
I need the EXACT script for creating an array (with movieclips inside? or instance names of mcs? How does this even work?)
and a method, to pick a random element of this array without repeats until the "game is over".
Paul
The easiest way to pick a random element from an array without repeating is to first sort the array with a "random" function, then pop or shift items out of it until the array is empty.
Let's say you have an array of items which can be filled with either instances or instance names, you've chosen instance names: :
var FirstArray:Array = ["blau", "orange", "green"];
Now, you'll need a random sort function:
// you do not need to modify this function in any way.
// the Array.sort method accepts a function that takes in 2 objects and returns an int
// this function has been written to comply with that
function randomSort(a:Object, b:Object):int
{
return Math.random() > .5 ? -1 : 1;
}
The way a sort function normally works is it compares two objects and returns -1 if the first item precedes the second item, 1 if the opposite is true, and 0 if they are the same.
So what we're doing in the function above is returning -1 or 1 randomly. This should get the array all jumbled up when you call:
FirstArray.sort(randomSort);
Now that the array is randomly sorted, you can begin pulling items from it like so:
if(FirstArray.length) // make sure there's at least one item in there
{
// since you are using instance names, you'll need to use that to grab a reference to the actual instance:
var currentQuizItem:MovieClip = this[FirstArray.pop()];
// if you had filled your array with the actual instances instead, you would just be assigning FirstArray.pop() to currentQuizItem
// every time you call pop on an array, you're removing the last item
// this will ensure that you won't repeat any items
// do what you need to do with your MovieClip here
}
else
{
// if there aren't any items left, the game is over
}
When strung together, the above code should be enough to get you up and running.
You could try something like:
var array:Array = [1, 2, 3, 4, 5];
var shuffledArray:Array = [];
while (array.length > 0)
{
shuffledArray.push(array.splice(Math.round(Math.random() * (array.length - 1)), 1)[0]);
}
trace('shuffledArray: ', shuffledArray, '\nrandom item: ', shuffledArray[0]);

Randomly selecting an object property

I guess a step back is in order. My original question is at the bottom of this post for reference.
I am writing a word guessing game and wanted a way to:
1. Given a word length of 2 - 10 characters, randomly generate a valid english word to guess
2.given a 2 - 10 character guess, ensure that it is a valid english word.
I created a vector of 9 objects, one for each word length and dynamically created 172000
property/ value pairs using the words from a word list to name the properties and setting their value to true. The inner loop is:
for (i = 0; i < _WordCount[wordLength] - 2; i)
{
_WordsList[wordLength]["" + _WordsVector[wordLength][i++]] = true;
}
To validate a word , the following lookup returns true if valid:
function Validate(key:String):Boolean
{
return _WordsList[key.length - 2][key]
}
I transferred them from a vector to objects to take advantage of the hash take lookup of the properties. Haven't looked at how much memory this all takes but it's been a useful learning exercise.
I just wasn't sure how best to randomly choose a property from one of the objects. I was thinking of validating whatever method I chose by generating 1000 000 words and analyzing the statistics of the distribution.
So I suppose my question should really first be am I better off using some other approach such as keeping the lists in vectors and doing a search each time ?
Original question
Newbie first question:
I read a thread that said that traversal order in a for.. in is determined by a hash table and appears random.
I'm looking for a good way to randomly select a property in an object. Would the first element in a for .. in traversing the properties, or perhaps the random nth element in the iteration be truly random. I'd like to ensure that there is approximately an equal probability of accessing a given property. The Objects have between approximately 100 and 20000 properties. Other approaches ?
thanks.
Looking at the scenario you described in your edited question, I'd suggest using a Vector.<String> and your map object.
You can store all your keys in the vector and map them in the object, then you can select a random numeric key in the vector and use the result as a key in the map object.
To make it clear, take a look at this simple example:
var keys:Vector.<String> = new Vector.<String>();
var map:Object = { };
function add(key:String, value:*):void
{
keys.push(key);
map[key] = value;
}
function getRandom():*
{
var randomKey = keys[int(Math.random() * keys.length)];
return map[randomKey];
}
And you can use it like this:
add("a", "x");
add("b", "y");
add("c", "z");
var radomValue:* = getRandom();
Using Object instead of String
Instead of storing the strings you can store objects that have the string inside of them,
something like:
public class Word
{
public var value:String;
public var length:int;
public function Word(value:String)
{
this.value = value;
this.length = value.length;
}
}
Use this object as value instead of the string, but you need to change your map object to be a Dictionary:
var map:Dictionary = new Dictionary();
function add(key:Word, value:*):void
{
keys.push(key);
map[key] = value;
}
This way you won't duplicate every word (but will have a little class overhead).

LINQ to SQL, in memory lists and anonymous types

I am joining a table to an in memory list and wanting to create an anonymous type from the results. I have joined the 2 data sources together ok, but I'm not sure of the syntax required to use a property from the in memory list in the anonymous type.
Here's my code
public DataKeys(IEnumerable<Element> elements)
{
var defsource = new DefinitionSource();
var items = from def in defsource.Definitions
where elements.Select(el=> el.Value).Contains(def.Name)
select new { def.Key };
...
}
(Obviously "elements" is an in-memory list of element and "DefinitionSource" is a wrapper around a table.) This works fine, but as you can see there is no property from the in-memory list of elements. I've tried this
var items = from def in defsource.Definitions
where elements.Select(el=> el.Value).Contains(def.Name)
from el in elements
where el.Value.Equals(def.Name)
select new { el.NodeType, def.Key };
but at run time it gens a "{"Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator."}"
So what is the syntax I need to do this?
Many thx IA
Simon
This might help:
var def=defsource.Definitions
.Where(a=>elements.Select(el=>el.Value).Contains(a.Name))
.ToList();
var items = from d in def
from el in elements
.Where(a=>a.Value==d.Name)
select new { el.NodeType, d.Key };
To query over two data sources both of them needs to be in memory are both of them should be in database. you can do the following to achieve the results you want
var query = (from def in defsource.Definitions
where elements.Select(el=> el.Value).Contains(def.Name)
).ToList();//bring filtered result in memory
var Items = from def in query //Definitions are already filtered no need to re-apply where
from el in elements.Where(a=>a.Value == def.Name)
select new {el.NodeType, def.Key};

AdvancedDataGrid total sum of branch nodes

Introduction:
I have an AdvancedDataGrid displaying hierarchical data illustrated by the image below:
The branch nodes "Prosjekt" and "Tiltak" display the sum of the leaf nodes below.
Problem: I want the root node "Tavle" to display the total sum of the branch nodes below. When i attempted to do this by adding the same SummaryRow the sum of the root node was not calculcated correctly(Every node's sum was calculated twice).
dg_Teknikktavles = new AutoSizingAdvancedDataGrid();
dg_Teknikktavles.sortExpertMode="true";
dg_Teknikktavles.headerHeight = 50;
dg_Teknikktavles.variableRowHeight = true;
dg_Teknikktavles.addEventListener(ListEvent.ITEM_CLICK,dg_TeknikktavlesItemClicked);
dg_Teknikktavles.editable="false";
dg_Teknikktavles.percentWidth=100;
dg_Teknikktavles.minColumnWidth =0.8;
dg_Teknikktavles.height = 1000;
var sumFieldArray:Array = new Array(context.brukerList.length);
for(var i:int = 0; i < context.brukerList.length; i++)
{
var sumField:SummaryField2 = new SummaryField2();
sumField.dataField = Ressurstavle.ressursKey + i;
sumField.summaryOperation = "SUM";
sumFieldArray[i] = sumField;
}
var summaryRow:SummaryRow = new SummaryRow();
summaryRow.summaryPlacement = "group";
summaryRow.fields = sumFieldArray;
var summaryRow2:SummaryRow = new SummaryRow();
summaryRow2.summaryPlacement = "group";
summaryRow2.fields = sumFieldArray;
var groupField1:GroupingField = new GroupingField();
groupField1.name = "tavle";
//groupField1.summaries = [summaryRow2];
var groupField2:GroupingField = new GroupingField();
groupField2.name = "kategori";
groupField2.summaries = [summaryRow];
var group:Grouping = new Grouping();
group.fields = [groupField1, groupField2];
var groupCol:GroupingCollection2 = new GroupingCollection2();
groupCol.source = ressursTavle;
groupCol.grouping = group;
groupCol.refresh();
Main Question: How do i get my AdvancedDataGrid's (dg_Teknikktavles) root node "Tavle" to correctly display the sum of the two branch nodes below?
Side Question: How do i add a red color to the numbers of the root node's summary row that exceed 5? E.g the column displaying 8 will exceed 5 in the root node's summary row, and should therefore be marked red
Thanks in advance!
This is a general answer, without code examples, but I had to do the same just couple of days ago, so my memory is still fresh :) Here's what I did:
Created a class A to represent an item renderer data, extended it from Proxy (I had field names defined at run time), and let it contain a collection of values as it's data member. Once accessed through flash_proxy::getPropery(fieldName) it would find a corresponding value in the data member containing the values and return it. Special note: implement IUID, just do it, it'll save you couple of days of frustration.
Extended A in B, added a children property containing ArrayCollection of A (don't try to experiment with other collection types, unless you want to find yourself examining tons of framework code, trust me, it's ugly and is impossible to identify as interesting). Let B override flash_proxy::getPropery - depending of your compiler this may, or may not be possible, if not possible - call some function from A.flash_proxy::getPropery() that you can override in B. Let this function query every instance of A, which is a child of B, asking the same thing, as DataGrid itself would, when building item renderers - this way you would get the total.
When creating a data provider. Create an ArrayCollection of B (again, don't try to experiment with other collections--unless you are ready for lots of frustration). Create Hierarchical data that uses this array collection as a source.
Colors - that's what you use item renderers for, just look up any tutorial on using item renderers, that must be pretty basic.
In case someone else has the same problem:
The initial problem that everything was summed twice, was the result of using the same Array of SummaryField2 (sumFieldArray in the code) for both grouping fields(GropingField2 tavle and kategori)
The Solution to the main question: was to create a new array of summaryfields for the root node(in my intial for loop):
//Summary fields for root node
var sumFieldRoot:SummaryField2 = new SummaryField2();
sumFieldRoot.dataField = Ressurstavle.ressursKey + i;
sumFieldRoot.summaryOperation = "SUM";
sumFieldArrayRoot[i] = sumFieldRoot;
Answer to the side question:
This was pretty much as easy as pointed out by wvxyw. Code for this solution below:
private function summary_styleFunction(data:Object, col:AdvancedDataGridColumn):Object
{
var output:Object;
var field:String = col.dataField;
if ( data.children != null )
{
if(data[field] >5){
output = {color:0xFF0000, fontWeight:"bold"}
}
else {
output = {color:0x006633, fontWeight:"bold"}
}
//output = {color:0x081EA6, fontWeight:"bold", fontSize:14}
}
return output;
}