Godot 3.1 Invalid get'index '16' (on base:Array) - arrays

Invalid get'index '16' (on base:Array).
Hi Im getting the above message when the player attempts to moves outside of the
array size (tile size).
The error occurs on line 54:
grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER
Im stuck on how to fix it.
regards
Jason
extends TileMap
var tile_size = get_cell_size()
var half_tile_size = tile_size / 2
enum ENTITY_TYPES {PLAYER, OBSTACLE, COLLECTIBLE}
var grid_size = Vector2(16,16)
var grid = []
onready var Obstacle = preload("res://scenes/Obstacle.tscn")
func _ready():
# Creates grid array of grid_size
for x in range(grid_size.x):
grid.append([])
for y in range(grid_size.y):
grid[x].append(null)
print(ENTITY_TYPES)
# Create obstacle positions array
var positions = []
# create 5 obstacles
for n in range(5):
# random positions constrained to grid_size
var grid_pos = Vector2(randi() % int(grid_size.x),randi() % int(grid_size.y))
#check random posisitions not already in array before adding new one
if not grid_pos in positions:
positions.append(grid_pos)
for pos in positions:
var new_obstacle = Obstacle.instance()
new_obstacle.position = (map_to_world(pos) + half_tile_size)
grid[pos.x][pos.y] = ENTITY_TYPES.OBSTACLE
add_child(new_obstacle)
func is_cell_vacant(pos, direction):
# Return true if cell is vaccant, else false
var grid_pos = world_to_map(pos) + direction
# world Boundaries
if grid.pos.x < grid_size.x and grid_pos.x >= 0:
if grid.pos.y < grid_size.y and grid_pos.y >= 0:
#return true if grid[grid_pos.x][grid_pos.y] == null else false
return grid[grid_pos.x][grid_pos.y] == null
return false
func update_child_pos(child_node):
# Move a child to a new position in the grid array
# Returns the new target world position of the child
var grid_pos = world_to_map(child_node.position)
grid[grid_pos.x][grid_pos.y] = null
var new_grid_pos = grid_pos + child_node.direction
grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER
var target_pos = (map_to_world(new_grid_pos) + half_tile_size)
return target_pos
pass

You are receiving the error because you are exceeding the arrays elements.
To avoid it, either make the grid bigger or make it so that the player cannot leave the grid.
If you want the player to be able to leave the grid, then you will probably have to create an if condition:
if player_in_grid: grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER.

Related

Kotlin: initialize 2D array

I am in a loop, reading 2 columns from a file. I read R, T combinations, 50 times. I want R and T to be in an array so I can look up the Nth pair of R, T later in a function. How do I put the R, T pairs in an array and look up the, say, 25th entry later in a function?
For example:
for (nsection in 1 until NS+1) {
val list: List<String> = lines[nsection + 1].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
}
Would like to pull radius and twist pairs from a table in a function later. NS goes up to 50 so far.
You can use map() on your range iterator to produce a List of what you want.
val radiusTwistPairs: List<Pair<Float, Float>> = (1..NS).map { nsection ->
val list = lines[nsection + 1].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
radius to twist
}
Or use an Array constructor:
val radiusTwistPairs: Array<Pair<Float, Float>> = Array(NS) { i ->
val list = lines[i + 2].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
radius to twist
}

Loop through array and get row number for each element

I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];

Push every new match from regEx in array

I try to parse some xml file, with this code:
function parseXml() {
var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var xml = UrlFetchApp.fetch(url).getContentText();
var parseregexp = new RegExp (/.*em><no>(\d+)<\/no><title>(.+?)<\/title><price vat="\w+">(\d+.\d+|\d+)<\/price><unit>(.+?)<\/unit><free>(\d+)<\/free>(.|\s)*?<it/g)
var parsedData = '$1 $2 $3 $4 $5 '
var rangeRegex = [];
var Pdata = xml.replace(parseregexp,parsedData)
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
ss.getRange(1, 1).setValue(Pdata)
}
And here is xml fragment:
<item><no>48514</no><title>The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC"</title><price vat="yes">154.58</price><unit>Pcs</unit><free>59</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item><item><no>48515</no><title>The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC"</title><price vat="Yes">198.24</price><unit>pcs</unit><free>32</free><remarks>Used to make an axial tool.
Hardness HRC64-66</remarks><img thumbnail="http://www.inpo.ru/index/I:48528/THUMBNAIL:0.jpg">http://www.inpo.ru/index/I: 48528 / PREVIEW: 0.jpg</img></item>
And result in Pdata is:
48514 The workpiece is the rod d 8x150mm P6AM5 HRC 64-66" CNIC" 154.58 Pcs 59 48515 The workpiece is the rod d 8x200mm P6AM5 HRC 64-66"CNIC" 198.24 pcs 32
In this example in Pdata I have 1 long string from all regex matches. How I can make an array with 5 columns from all matches? I think to push every match to array with "for" cycle, but dont know how it's mades. Would be pleasefull for any help
Alternate Solution:
Since you are trying to access xml data you can use XMLservice.parser
However there seems to a problem in the fetch call, I was unable to get the whole data (fetch gives a truncated file, perhaps it is timing out, 16mb file) , so I downloaded the data file and uploaded it into google drive.
This file could be used to parse XML data like so:
function parseXml() {
var file = DriveApp.getFileById("Xml File ID") //Get the id of the uploaded file and replace it for "Xml File ID"
var xml = file.getBlob().getDataAsString()
// The below code gave a error for XML parser
/*var url = 'http://www.inpo.ru/documents/pricelists/pricelist.xml';
var options = {
'method' : 'get',
'contentType': 'application/xml',
}
var xml = UrlFetchApp.fetch(url,options).getBlob().getDataAsString()
Logger.log(xml)*/
// End of code with gave an error
var arrayItems = []
var XmlElem = ["no","title","price","unit","free"] //Elements to look for
var document = XmlService.parse(xml);
var RCounter = 0
var groups = document.getRootElement().getChildren(); //GetGroup Element
for(var k = 0; k< groups.length; k++){ // Loop through each group element
var main = groups[k].getChildren() // Get sub groups in each group
for (var j=0 ; j < main.length; j++){ // Loop through each subGroups
var mainChilds = main[j].getChildren() //Get items in each subGroups
for (var l = 0 ; l < mainChilds.length; l++){ // Loop through each items
var items = mainChilds[l].getChildren(); // Get elemetns like "no","title","price","units","free" in each item
arrayItems[RCounter] = []
var total = 0;
for (var i = 0; i < items.length; i++) {
// Logger.log(items[i].getName())
var index = XmlElem.indexOf(items[i].getName()) //Look for items and place the value at corresponding index
if(index != -1)
arrayItems[RCounter][index] = items[i].getValue()
} //End Loope for elements
if(arrayItems[RCounter].length > 0) //in case the array is empty, reuse it
RCounter++
} // End loop for items
} // End loop for sub Groups
} // End loop for Groups
Logger.log(arrayItems)
}
Hope that helps!

Swift: Array map or reduce, enumerate with index

I have an array of values [CGFloat] and array of days [CGFloat] with which each value is associated (the time is also important so the days array is a decimal value).
Each day has between 0 and n values. (n typically less than 5 or 6)
I want to find the mean value for each day, so after the calculations I would like to have an array of means [CGFloat] and an array of days [CGFloat], or a dictionary of the two combined or an array of [CGPoint]. I am fairly certain this can be done with either a mapping or reducing or filter function, but I'm having trouble doing so.
For instance
the third day might look like [2.45, 2.75, 2.9]
with associated values [145.0, 150.0, 160.0]
And I would like to end with day[2] = 2.7
and value[2] = 151.7
or
[CGPoint(2.7, 151.7)] or [2.7 : 151.7]
Can anyone offer guidance?
Some code:
let xValues : [CGFloat] = dates.map{round((CGFloat($0.timeIntervalSinceDate(dateZero))/(60*60*24))*100)/100}
let yValues : [CGFloat] = valueDoubles.map{CGFloat($0)}
//xValues and yValues are the same length
var dailyMeans = [CGFloat]()
var xVals = [CGFloat]()
let index = Int(ceil(xValues.last!))
for i in 0..<index{
let thisDay = xValues.enumerate().filter{$0.element >= CGFloat(i) && $0.element < CGFloat(i+1)}
if thisDay.count > 0{
var sum : CGFloat = 0
var day : CGFloat = 0
for i in thisDay{
sum += yValues[i.index]
day += xValues[i.index]
}
dailyMeans.append(sum/CGFloat(thisDay.count))
xVals.append(day/CGFloat(thisDay.count))
}
}
The above code works, but also has to do that enumerate.filter function values.count * days.last times. So for 40 days and 160 readings.. like 6500 times. And I'm already using way too much processing power as it is. Is there a better way to do this?
edit: forgot a line of code defining index as the ceiling of xValues.last
This has been seen 1000 times so I thought I would update with my final solution:
var daySets = [Int: [CGPoint]]()
// points is the full array of (x: dayTimeInDecimal, y: value)
for i in points {
let day = Int(i.x)
daySets[day] = (daySets[day] ?? []) + [i]
}
let meanPointsEachDay = daySets.map{ (key, value) -> CGPoint in
let count = CGFloat(value.count)
let sumPoint = value.reduce(CGPoint.zero, {CGPoint(x: $0.x + $1.x, y: $0.y + $1.y)})
return CGPoint(x: sumPoint.x/count, y: sumPoint.y/count)
}
// must be sorted by 'day'!!!
let arrA0 = [2.45, 2.75, 2.9, 3.1, 3.2, 3.3]
// associated values
let arrA1 = [145.0, 150.0, 160.0, 245.0, 250.0, 260.0]
let arr = Array(zip(arrA0, arrA1))
// now i have an array of tuples, where tuple.0 is key and tuple.1 etc. is associated value
// you can expand the tuple for as much associated values, as you want
print(arr)
// [(2.45, 145.0), (2.75, 150.0), (2.9, 160.0), (3.1, 245.0), (3.2, 250.0), (3.3, 260.0)]
// now i can perform my 'calculations' the most effective way
var res:[Int:(Double,Double)] = [:]
// sorted set of Int 'day' values
let set = Set(arr.map {Int($0.0)}).sort()
// for two int values the sort is redundant, but
// don't be depend on that!
print(set)
// [2, 3]
var g = 0
var j = 0
set.forEach { (i) -> () in
var sum1 = 0.0
var sum2 = 0.0
var t = true
while t && g < arr.count {
let v1 = arr[g].0
let v2 = arr[g].1
t = i == Int(v1)
if t {
g++
j++
} else {
break
}
sum1 += v1
sum2 += v2
}
res[i] = (sum1 / Double(j), sum2 / Double(j))
j = 0
}
print(res)
// [2: (2.7, 151.666666666667), 3: (3.2, 251.666666666667)]
see, that every element of your data is process only once in the 'calculation', independent from size of 'key' set size
use Swift's Double instead of CGFloat! this increase the speed too :-)
and finally what you are looking for
if let (day, value) = res[2] {
print(day, value) // 2.7 151.666666666667
}

Iterating through array to find occurrences of value

I have been trying to iterate through an array to check how many times two particular values occur. I came up with this code:
var paymentNum = 0
var creditNum = 0
for index in images {
if images.objectAtIndex(index) == 0 {
paymentNum = paymentNum + 1
} else {
creditNum = creditNum + 1
}
}
This doesn't seem to work though. I just get the error 'AnyObject' is not convertible to 'Int'.
Where am I going wrong?
I'm making some pretty huge assumptions because you don't have much detail about what's going on.
I'm assuming that images is an NSArray. NSArray in Objective-C translates into an [AnyObject] in swift.
When you have a for-each style loop like this
for value in array
{}
the loop will iterate through each value in the array. Value is the actual object in the array, not a counter as in a for(int i = 0; i < 10; i++) style loop
So what you're probably really expecting to do is
for item in images {
if item == 0 {
paymentNum++
} else {
creditNum++
}
}
you also might need to cast the loop from an [AnyObject] to an [Int] like this
let tmp = images as [Int]
for item in tmp
{...}
or, cast the value pulled out of the array like this
for item in images {
if (item as Int) == 0 {
paymentNum++
} else {
creditNum++
}
}
But the former is probably preferable
paste ina playground:
import Foundation
let images = [1, 0, 1, 1, 0, 0, 1, 0, 1, 1]
var paymentNum = 0
var creditNum = 0
for item in images {
println(item)
if item == 0 {
paymentNum = paymentNum + 1
} else {
creditNum = creditNum + 1
}
}
println(paymentNum) //4
println(creditNum) //6
There's a more compact way of achieving that, in just 2 lines of code.
It makes the assumption that an array element it's a credit if its value is 1, otherwise is 0.
That said, if you sum up all elements of array, you obtain the number of credits - the number of payments is the array size minus the number of credits.
To sum all elements of the array, the simplest way is using the reduce method (more info here)
var creditNum = images.reduce(0, combine: { $0 + $1 } )
var paymentNum = images.count - creditNum
If using values different than 0 or 1 to identify credits and payments, then the calculation can be modified to check for explicit values as follows:
var creditNum = images.reduce(0, combine: { $0 + ($1 == 1 ? 1 : 0) } )
Here it takes the previous count ($0) and add either 1 or 0, depending whether the element array ($1) is equal to 1 or not.

Resources