Logical Error - 2D array using ArrayList in Kotlin - arrays

I am making a simpel tic tac toe game while learning Kotlin, following a tutorial.
When I input and combination as my turn in the game, let's say 1, 3 : The X appears in all places of that column. I have spent almost 3 hours finding the erorr but I think it's somthing to do with Arraylist making. Kinldy help me. Code is shown below.
var board = arrayListOf<ArrayList<String>>()
fun main(args: Array<String>) {
for (i in 0..2){
val row = arrayListOf<String>()
for (j in 0..2){
row.add("")
board.add(row)
}
}
printBoard()
var continueGame = true
do{
println("Please enter a position. (e.g: 1, 3)")
val input = readLine()?:""
var x = 0
var y = 0
try {
val positions = input.split(",")
x = positions[0].trim().toInt()
y = positions[1].trim().toInt()
println("x is $x")
println("x is $y")
if(board[x-1][y-1] != "") {
println("position already taken")
}else{
board[x-1][y-1] ="X"
printBoard()
}
}catch (e: Exception){
println("Invalid input, please try again")
}
}while(continueGame)
}
fun printBoard(){
println("----------------")
for (i in 0..2){
for (j in 0..2){
when (board[i][j]){
"X" -> print("| X ")
"O" -> print("| O ")
else -> print("| ")
}
}
println("|")
println("----------------")
}
}

Move board.add(row) outside your inner for loop (the for (j... loop). You are adding each row to the outer ArrayList three times, so when you start using the 2D list later and assume it only has three rows, all three of those rows are the same first row repeated, and you're ignoring the last six rows.
But actually, when you know that your collections will not ever change size, Arrays are a cleaner solution than Lists. You can create your 3x3 2D Array in one line like this:
val board = Array(3) { Array(3) { "" } }

Here's how I looked at the problem.
Debug printBoard()
I first looked at the printBoard() function. I put a breakpoint in, and saw that board already had 3 Xs in it.
So the problem is happening further up the chain.
Debugging the X assignment
There's only once place in your code where X's are added to the board, so let's take a look there.
board[x - 1][y - 1] = "X"
I put a breakpoint on that line, and ran the program in debug mode.
When I inspect the board object, I see it's an ArrayList with 9 elements. Each element is also an ArrayList, each with 3 elements.
In total that's 27 squares, and a tic-tac-toe board only has 9! board only needs 3 ArrayLists.
Debugging board creation
If we take a look at where board is created...
for (i in 0..2) {
val row = arrayListOf<String>()
for (j in 0..2) {
row.add("")
board.add(row) // hmmmm
}
}
board.add(row) is nested inside both for loops. That means it will be called 9 times in total.
The Fix
So, quick fix, move add to the outer loop.
for (i in 0..2) {
val row = arrayListOf<String>()
for (j in 0..2) {
row.add("")
}
board.add(row) // better!
}
The program now works!
Why were there 3 X's?
I think it's interesting to understand why the X was appearing on the board three times.
If we look at the two for loops, the row list is being created in the outer loop - which means only 3 rows will be created. But because board.add(row) was in the inner loop, it will add the same row 3 times!
We can actually see that in the debug inspection. ArrayList#1073 is a unique ID for a specific row object, and it appears 3 times. So do ArrayList#1074 and ArrayList#1075
board[0], board[1], and board[2] all fetch the same row object, so in the printBoard() function, it loops over the first 3 elements of board... which are all exactly the same object!
Preventing the problem
The next step is to think about how to stop this problem from happening in the first place. I think that the for loops were confusing - they're easy to get wrong, and have 'magic numbers'. Fortunately Kotlin has lots of useful tools we can use to write clearer code.
Kotlin's Array class has a constructor that accepts an size: Int and an initialising lambda, that is used to fill each element of the array.
Here's a demo:
println(
Array(5) { i -> "I'm element $i" }.joinToString()
)
// output:
// I'm element 0, I'm element 1, I'm element 2, I'm element 3, I'm element 4
Each element of the Array has a value, based on i (the index of the array). For the tic-tac-toe board we don't care about the index, so we can ignore it.
// var board = arrayListOf<ArrayList<String>>() // old
var board = Array(3) { Array(3) { "" } } // new!
Output:
----------------
| | | |
----------------
| | | |
----------------
| | | |
----------------
Please enter a position. (e.g: 1, 3)
There we go, a 3x3 board - nice and clear!
I hope this helps!

Related

Swift: Capture list

var array = [() -> ()]()
var count = 0
var index = 0
while index < 5 {
array.append {
print("count: \(count)")
print("index: \(index)")
}
count += 1
index += 1
}
array[0]()
array[4]()
Output:
count: 5
index: 5
count: 5
index: 5
Same case but with some changes:
var array = [() -> ()]()
var count = 0
for index in 0..<5 {
array.append {
print("count: \(count)")
print("index: \(index)")
}
count += 1
}
array[0]()
array[4]()
Output:
count: 5
index: 0
count: 5
index: 4
Count value would be the same in both the cases as we are not explicitly capturing it, i.e 5
In the first case global index variable is used and the result is the last incremented value i.e. 5 and 5
In the second case for loop's index is used and the value is 0 and 4 respectively.
What is the exact difference?
In the first example index is var declared and it is the same variable used each time, in the second it is let declared so in the second example it is a new instance of index that exists in the scope of the for loop for each iteration
I Debugged that code because it looked kinda weird but just let me tell you, the appending and increment line goes well, When you call array0 and array4, the debugger goes to the body of append{} and print those variables. and captures those variable from most easily accessible scope. so in first case, it will capture from the scope of function body which values are actually new 5 and 5 for both count and index.
in second case, it will try to capture if there is a variable count and index initialized, it will find count but wont find so it will check inside the body of array and there it will find the actual value which is 0 in first index and 4 in 5th index.
That's all i can explain, Sorry for bad english
Check Debugger Image Here

Search and replace string in 2D Array in Swift

Teaching myself swift, so complete noob here, but I'm far into a project and just know there must be an easier way to achieve something.
I have a 2D array:
var shopArray = [
["theme":"default","price":0,"owned":true,"active":true,"image":UIImage(named: "defaultImage")!,"title":"BUY NOW"],
["theme":"red","price":1000,"owned":false,"active":false,"image":UIImage(named: "redImage")!,"title":"BUY NOW"],
["theme":"blue","price":2000,"owned":false,"active":false,"image":UIImage(named: "blueImage")!,"title":"BUY NOW"],
["theme":"pool","price":3000,"owned":true,"active":false,"image":UIImage(named: "blueImage")!,"title":"BUY NOW"],
["theme":"line","price":4000,"owned":false,"active":false,"image":UIImage(named: "lineImage")!,"title":"BUY NOW"],
["theme":"neon","price":5000,"owned":false,"active":false,"image":UIImage(named: "lineImage")!,"title":"BUY NOW"]]
Where I simply want to create a function that runs and search for all the "owned" keys and make them all "false".
How do you search and replace in Arrays / 2D Arrays. More specifiaclly, what should the func look like?
Thank you!
You don't have a 2D array, you have an Array of Dictionaries.
You can set all of the values for the owned keys by iterating the indices of the Array and updating the values:
shopArray.indices.forEach { shopArray[$0]["owned"] = false }
That is the functional way to do it. You could also do the same operation with a for loop:
for idx in shopArray.indices {
shopArray[idx]["owned"] = false
}
You could do something like this to loopthrough the array replacing the approriate element.
var i = 0
for x in shopArray {
var y = x
y["owned"] = false
shopArray.remove(at: i)
shopArray.insert(y, at: i)
i = i + 1
}
or you could use a while loop to do the same with less code lines.
var y = 0
while y < shopArray.count {
shopArray[y].updateValue(false, forKey: "owned")
y += 1
}
There is proably somthing doable with .contains, but I'm not sure you need that toachive the result you mention above. Play around in a play ground in xcode and try a few different options without doing anything that might cause issues in your project.

Transpose a matrix(python 3)

I have a module wrote in python to input a matrix that looks like that:
matrix = []
loop = True
while loop:
line = input()
if not line: #the way it works is that you enter value separated by a space and enter a blank line to finish inputing the matrix
loop = False
values = line.split()
row = [int(value) for value in values]
matrix.append(row)
print('\n'.join([' '.join(map(str, row)) for row in matrix]))
The last line is just to print the matrix like this
1 2 3
4 5 6
I would like to be able to transpose the matrix in another module,I tried this so far:
def transpose_matrix(matrix):
zip(*matrix)
return matrix
But it actually doesnt work it doesnt have any effect on the actual matrix,the matrix stays the same,and I dont get it.
Thanks!
First, I would get the matrix in the following manner, to avoid the empty list in the end:
matrix = []
while True:
line = input()
if not line:
break
values = line.split()
row = [int(value) for value in values]
matrix.append(row)
as for transposing it, the best way is to leave it to numpy:
import numpy as np
transposed_matrix = np.transpose(np.array(matrix))
if for any reason you would like to avoid numpy (which is not advisable), you can use:
transposed_matrix = []
for line in zip(*matrix):
transposed_matrix.append(line)

Vector search Algorithm

I have the following problem. Say I have a vector:
v = [1,2,3,4,5,1,2,3,4,...]
I want to sequentially sample points from the vector, that have an absolute maginute difference higher than a threshold from a previously sampled point. So say my threshold is 2.
I start at the index 1, and sample the first point 1. Then my condition is met at v[3], and I sample 3 (since 3-1 >= 2). Then 3, the new sampled point becomes the reference, that I check against. The next sampled point is 5 which is v[5] (5-3 >= 2). Then the next point is 1 which is v[6] (abs(1-5) >= 2).
Unfortunately my code in R, is taking too long. Basically I am scanning the array repeatedly and looking for matches. I think that this approach is naive though. I have a feeling that I can accomplish this task in a single pass through the array. I dont know how though. Any help appreciated. I guess the problem I am running into is that the location of the next sample point can be anywhere in the array, and I need to scan the array from the current point to the end to find it.
Thanks.
I don't see a way this can be done without a loop, so here is one:
my.sample <- function(x, thresh) {
out <- x
i <- 1
for (j in seq_along(x)[-1]) {
if (abs(x[i]-x[j]) >= thresh) {
i <- j
} else {
out[j] <- NA
}
}
out[!is.na(out)]
}
my.sample(x = c(1:5,1:4), thresh = 2)
# [1] 1 3 5 1 3
You can do this without a loop using a bit of recursion:
vsearch = function(v, x, fun=NULL) {
# v: input vector
# x: threshold level
if (!length(v) > 0) return(NULL)
y = v-rep(v[1], times=length(v))
if (!is.null(fun)) y = fun(y)
i = which(y >= x)
if (!length(i) > 0) return(NULL)
i = i[1]
return(c(v[i], vsearch(v[-(1:(i-1))], x, fun=fun)))
}
With your vector above:
> vsearch(c(1,2,3,4,5,1,2,3,4), 2, abs)
[1] 3 5 1 3

Efficient way to convert Scala Array to Unique Sorted List

Can anybody optimize following statement in Scala:
// maybe large
val someArray = Array(9, 1, 6, 2, 1, 9, 4, 5, 1, 6, 5, 0, 6)
// output a sorted list which contains unique element from the array without 0
val newList=(someArray filter (_>0)).toList.distinct.sort((e1, e2) => (e1 > e2))
Since the performance is critical, is there a better way?
Thank you.
This simple line is one of the fastest codes so far:
someArray.toList.filter (_ > 0).sortWith (_ > _).distinct
but the clear winner so far is - due to my measurement - Jed Wesley-Smith. Maybe if Rex' code is fixed, it looks different.
Typical disclaimer 1 + 2:
I modified the codes to accept an Array and return an List.
Typical benchmark considerations:
This was random data, equally distributed. For 1 Million elements, I created an Array of 1 Million ints between 0 and 1 Million. So with more or less zeros, and more or less duplicates, it might vary.
It might depend on the machine etc.. I used a single core CPU, Intel-Linux-32bit, jdk-1.6, scala 2.9.0.1
Here is the underlying benchcoat-code and the concrete code to produce the graph (gnuplot). Y-axis: time in seconds. X-axis: 100 000 to 1 000 000 elements in Array.
update:
After finding the problem with Rex' code, his code is as fast as Jed's code, but the last operation is a transformation of his Array to a List (to fullfill my benchmark-interface). Using a var result = List [Int], and result = someArray (i) :: result speeds his code up, so that it is about twice as fast as the Jed-Code.
Another, maybe interesting, finding is: If I rearrange my code in the order of filter/sort/distinct (fsd) => (dsf, dfs, fsd, ...), all 6 possibilities don't differ significantly.
I haven't measured, but I'm with Duncan, sort in place then use something like:
util.Sorting.quickSort(array)
array.foldRight(List.empty[Int]){
case (a, b) =>
if (!b.isEmpty && b(0) == a)
b
else
a :: b
}
In theory this should be pretty efficient.
Without benchmarking I can't be sure, but I imagine the following is pretty efficient:
val list = collection.SortedSet(someArray.filter(_>0) :_*).toList
Also try adding .par after someArray in your version. It's not guaranteed to be quicker, bit it might be. You should run a benchmark and experiment.
sort is deprecated. Use .sortWith(_ > _) instead.
Boxing primitives is going to give you a 10-30x performance penalty. Therefore if you really are performance limited, you're going to want to work off of raw primitive arrays:
def arrayDistinctInts(someArray: Array[Int]) = {
java.util.Arrays.sort(someArray)
var overzero = 0
var ndiff = 0
var last = 0
var i = 0
while (i < someArray.length) {
if (someArray(i)<=0) overzero = i+1
else if (someArray(i)>last) {
last = someArray(i)
ndiff += 1
}
i += 1
}
val result = new Array[Int](ndiff)
var j = 0
i = overzero
last = 0
while (i < someArray.length) {
if (someArray(i) > last) {
result(j) = someArray(i)
last = someArray(i)
j += 1
}
i += 1
}
result
}
You can get slightly better than this if you're careful (and be warned, I typed this off the top of my head; I might have typoed something, but this is the style to use), but if you find the existing version too slow, this should be at least 5x faster and possibly a lot more.
Edit (in addition to fixing up the previous code so it actually works):
If you insist on ending with a list, then you can build the list as you go. You could do this recursively, but I don't think in this case it's any clearer than the iterative version, so:
def listDistinctInts(someArray: Array[Int]): List[Int] = {
if (someArray.length == 0 || someArray(someArray.length-1) <= 0) List[Int]()
else {
java.util.Arrays.sort(someArray)
var last = someArray(someArray.length-1)
var list = last :: Nil
var i = someArray.length-2
while (i >= 0) {
if (someArray(i) < last) {
last = someArray(i)
if (last <= 0) return list;
list = last :: list
}
i -= 1
}
list
}
}
Also, if you may not destroy the original array by sorting, you are by far best off if you duplicate the array and destroy the copy (array copies of primitives are really fast).
And keep in mind that there are special-case solutions that are far faster yet depending on the nature of the data. For example, if you know that you have a long array, but the numbers will be in a small range (e.g. -100 to 100), then you can use a bitset to track which ones you've encountered.
For efficiency, depending on your value of large:
val a = someArray.toSet.filter(_>0).toArray
java.util.Arrays.sort(a) // quicksort, mutable data structures bad :-)
res15: Array[Int] = Array(1, 2, 4, 5, 6, 9)
Note that this does the sort using qsort on an unboxed array.
I'm not in a position to measure, but some more suggestions...
Sorting the array in place before converting to a list might well be more efficient, and you might look at removing dups from the sorted list manually, as they will be grouped together. The cost of removing 0's before or after the sort will also depend on their ratio to the other entries.
How about adding everything to a sorted set?
val a = scala.collection.immutable.SortedSet(someArray filter (0 !=): _*)
Of course, you should benchmark the code to check what is faster, and, more importantly, that this is truly a hot spot.

Resources