kotlin firebase multiple loop - android

when I add multiple loop to retrieve data from firebase only the first loop works, why is that happening and how can I make all the loops work
val children = dataSnapshot!!.children
children.forEach {
if( it.child("Date").getValue().toString().equals(Data.date) && it.child("Time").getValue().toString().equals(Data.time) && it.child("location").getValue().toString().equals(items.get(0).toString())){
//
}
}
children.forEach {
if( it.child("Date").getValue().toString().equals(Data.date) && it.child("Time").getValue().toString().equals(Data.time) && it.child("location").getValue().toString().equals(items.get(1).toString())){
//
}
}
children.forEach {
if( it.child("Date").getValue().toString().equals(Data.date) && it.child("Time").getValue().toString().equals(Data.time) && it.child("location").getValue().toString().equals(items.get(2).toString())){
//
}
}

At first glance the 3 loops look identical, but they differ at the last 3d of the condition. Each one checks this:
it.child("location").getValue().toString().equals(items.get(x).toString())
where x is 0, 1 or 2.
So they are not the same as to be surprised why the last 2 don't work as you say.
Maybe the condition works only for:
items.get(0).toString()
Anyway you can simplify your code and add some debugging code so to be sure what's happening:
(0..2).forEach { i ->
children.forEach {
val dateOk = it.child("Date").getValue().toString().equals(Data.date)
val timeOk = it.child("Time").getValue().toString().equals(Data.time)
val itemOk = it.child("location").getValue().toString().equals(items.get(i).toString())
Log.d("Loop", "at $i: dateOk = $dateOk, timeOk = $timeOk, itemOk = $itemOk")
if( dateOk && timeOk && itemOk){
when (i) {
0 -> //
1 -> //
2 -> //
}
}
}
}

Related

I am trying to make TicTacToe Application

I am trying to make TicTacToe Application, I have already implemented the "player Vs player" part but I am having trouble with implementing the player Vs computer. I have a function called playgame. For update_player I am doing manually and for update computer, I am doing it using random, and I think this is causing the issue as I am checking if my boardStatus is already filled, if it's filled I am calling my function again. I read online that all the calculation should be done on thread, I tried implementing it but I think I am doing it wrong. Please Help!
Here's my code for reference:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import kotlinx.android.synthetic.main.activity_computer.*
import java.util.*
class ComputerActivity : AppCompatActivity() {
var player = true
var turnCount = 0
var boardStatus = Array(3) { IntArray(3) }
lateinit var board: Array<Array<Button>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_computer)
board = arrayOf(
arrayOf(First, Second, Third),
arrayOf(Fourth, Fifth, Sixth),
arrayOf(Seventh, Eighth, Ninth)
)
playGame()
}
private fun playGame(){
Status.text = "Player's Turn"
for (i in 0..2) {
var flag: Boolean = false
for (j in 0..2) {
if (player) {
Status.text = "Player's Turn"
update_player(player)
Thread.sleep(2000)
player = false
turnCount++
checkWinner()
if (turnCount == 9) {
Status.text = "Game Draw"
flag = true;
}
} else {
Status.text = "Computer's Turn"
update_computer(player)
Thread.sleep(2000)
player = true
turnCount++
checkWinner()
if (turnCount == 9){
Status.text = "Game Draw"
flag = true
}
}
}
if(flag == true)
break
}
changeBoard()
resetBtn.setOnClickListener{
player = true;
turnCount = 0
changeBoard()
}
}
private fun update_player(player:Boolean){
for(i in board){
for(button in i){
button.setOnClickListener{
when(it.id){
R.id.First->{
updateBoardStatus(row = 0, column = 0,player)
}
R.id.Second->{
updateBoardStatus(row = 0, column = 1,player)
}
R.id.Third->{
updateBoardStatus(row = 0, column = 2,player)
}
R.id.Fourth->{
updateBoardStatus(row = 1, column = 0,player)
}
R.id.Fifth->{
updateBoardStatus(row = 1, column = 1,player)
}
R.id.Sixth->{
updateBoardStatus(row = 1, column = 2,player)
}
R.id.Seventh->{
updateBoardStatus(row = 2, column = 0,player)
}
R.id.Eighth->{
updateBoardStatus(row = 2, column = 1,player)
}
R.id.Ninth->{
updateBoardStatus(row = 2, column = 2,player)
}
}
}
}
}
}
private fun update_computer(player:Boolean){
var row:Int = 0
var column:Int = 0
Thread {
row = (0..2).random()
column = (0..2).random()
}.start()
if(boardStatus[row][column] == 0 || boardStatus[row][column]==1)
update_computer(player)
else
updateBoardStatus(row, column, player)
}
private fun updateBoardStatus(row:Int, column:Int, player:Boolean){
val text = if (player) "X" else "0"
val value = if (player) 1 else 0
board[row][column].apply {
isEnabled = false
setText(text)
}
boardStatus[row][column] = value
}
private fun checkWinner(){
//Horizontal --- rows
for (i in 0..2) {
if (boardStatus[i][0] == boardStatus[i][1] && boardStatus[i][0] == boardStatus[i][2]) {
if (boardStatus[i][0] == 1) {
result("Player Won!!")
break
} else if (boardStatus[i][0] == 0) {
result("Computer Won")
break
}
}
}
//Vertical --- columns
for (i in 0..2) {
if (boardStatus[0][i] == boardStatus[1][i] && boardStatus[0][i] == boardStatus[2][i]) {
if (boardStatus[0][i] == 1) {
result("Player Won!!")
break
} else if (boardStatus[0][i] == 0) {
result("Computer Won!!")
break
}
}
}
//First diagonal
if (boardStatus[0][0] == boardStatus[1][1] && boardStatus[0][0] == boardStatus[2][2]) {
if (boardStatus[0][0] == 1) {
result("Player Won!!")
} else if (boardStatus[0][0] == 0) {
result("Computer won!!")
}
}
//Second diagonal
if (boardStatus[0][2] == boardStatus[1][1] && boardStatus[0][2] == boardStatus[2][0]) {
if (boardStatus[0][2] == 1) {
result("Player Won!!")
} else if (boardStatus[0][2] == 0) {
result("Computer Won!!")
}
}
}
private fun result(res:String){
Status.text = res
if(res.contains("Won")){
disableButton()
}
else{
}
}
private fun disableButton(){
for(i in board){
for(button in i){
button.isEnabled = false
}
}
}
private fun changeBoard(){
for (i in 0..2) {
for (j in 0..2) {
boardStatus[i][j] = -1
}
}
for (i in board) {
for (button in i) {
button.isEnabled = true
button.text = ""
}
}
}
}
Your code is trying to put the whole sequence of actions of the game in a function that is called once and then expects player button-presses to happen internally. Button listeners will fire some time in the future, after the function already returns. You need to think in terms of there being a function that is called each time a button is pressed to do the next stage of the game.
To fix this:
Remove the playGame() function.
Remove the player parameter from update_player() since it's always true. And change the function name to initializeButtons. Call it once in onCreate(). You only have to add listeners to the buttons one time and they will work repeatedly.
Also remove the player parameter from update_computer() for the same reason as above. And remove the threading so it looks like:
private fun update_computer() {
val row = (0..2).random()
val column = (0..2).random()
if (boardStatus[row][column] == 0 || boardStatus[row][column] == 1)
update_computer()
else
updateBoardStatus(row, column, player)
}
Then at the end of the updateBoardStatus function call checkWinner(). checkWinner() should return a Boolean, so in updateBoardStatus(), if no win condition has been found and player is true, it should call update_computer().
So what you have now instead of trying to run the game from one function, you set up button listeners one time to start the game. When a button is pressed, it takes the player turn, which then triggers updateBoardStatus, which then triggers the computer turn, which then triggers updateBoardStatus again, and then does nothing if no one won. All of that happens synchronously/instantly on the main thread, so now the game is back to waiting for a button press from the user to repeat the sequence of events.
Also, the status text view has limited usefulness. Since the computer takes its turns instantly, it's not possible to ever see the words "Computer's turn". If you want to do that, you'll have to create an artificial delay, so you would have to disable all the buttons and then do something like call postRunnable({ startPlayerTurn() }, 1000L), where the startPlayerTurn() re-enables the appropriate buttons and makes it say, "Player turn" again.

Duplicate Files on phone's storage (Android)

Hope you are fine what I am trying to achieve is to get all the duplications from the internal storage, for that, I am already using a method I don't know what I am doing wrong please have a look,
private fun getDuplicateItems() {
var tempDuplicateItem: DuplicateItemModel
GlobalScope.launch(Dispatchers.IO) {
for (i in 0 until listOfAllFiles.size) {
for (j in i until listOfAllFiles.size) {
if(!File(listOfAllFiles[i].directoryPath).isDirectory && !File(listOfAllFiles[j].directoryPath).isDirectory ){
if (listOfAllFiles[i].fileName == listOfAllFiles[j].fileName && listOfAllFiles[i].fileSize == listOfAllFiles[j].fileSize &&
!listOfAllFiles[i].fileName.endsWith(".tmp") && !listOfAllFiles[j].fileName.endsWith(".tmp") &&
!listOfAllFiles[i].fileName.endsWith(".chck") && !listOfAllFiles[j].fileName.endsWith(".chck") &&
!listOfAllFiles[i].fileName.startsWith(".") && !listOfAllFiles[j].fileName.startsWith(".")
) {
tempDuplicateItem = DuplicateItemModel(
"$i${listOfAllFiles[i].fileName}",
listOfAllFiles[i].fileName,
listOfAllFiles[i].absolutePath,
listOfAllFiles[i].fileModificationDateAndTime,
File(listOfAllFiles[i].directoryPath).length(),
false,
false,
)
tempArrayListOfDuplicateItemsSingle.add(
DuplicateItemModel(
"$i${listOfAllFiles[i].fileName}",
listOfAllFiles[j].fileName,
listOfAllFiles[j].absolutePath,
listOfAllFiles[j].fileModificationDateAndTime,
File(listOfAllFiles[j].directoryPath).length(),
true,
true,
)
)
tempArrayListOfDuplicateItems.add(
DuplicateItemArrayListItem(
tempDuplicateItem,
tempArrayListOfDuplicateItemsSingle
)
)
}
}
}
}
}.invokeOnCompletion {
var tempTotalDuplicateSize: Double = 0.0
GlobalScope.launch(Dispatchers.Main) {
progressBarDuplicateFiles.visibility = View.INVISIBLE
imageViewNextDuplicateFiles.visibility = View.VISIBLE
for (x in 0 until tempArrayListOfDuplicateItems.size) {
tempArrayListOfDuplicateItems[x].listOfDuplicationSubItems.forEach { duplicateItem ->
tempTotalDuplicateSize += duplicateItem.fileSize
}
}
//UI Stuff
textViewTotalSizeOfDuplications.text = "total Size of Duplicate Files (${HelperClass.readableFileSize(tempTotalDuplicateSize.toLong())})"
textViewTotalFolderFilesDuplicateItem.text = "${tempArrayListOfDuplicateItems.size} Item(s)"
relativeLayoutDuplicateItem.isClickable = true
}
}
}
I am using MediaLoader, a library which gives me all the files on internal storage, and through those files, I am checking the data if the data is equal or not but getting the stream of data which I don't know is correct or not,
This should help you get started:
File f = new File("your_relevant_path");
File[] files = f.listFiles();
HashSet<String> mHashSet = new HashSet<>();
for (File currFile :
files) {
if (!mHashSet.add(currFile.getName()))
{
// Here there is a duplication of a file
}
}

Generate the same maze with a seed

Im followed a tutorial to create a maze with Recursive Backtracking and it works great.
Im trying to create a game where people get on the same maze, and if someone wins, it creates a new maze and everyones current maze gets updated.
So what i was thinking is to have a seed to create the same maze and pass that seed to all the players so they can have the same maze.
Is there a way to modify it so i can give the maze a seed and it creates always the same maze?
This is what i have now:
It uses a Cell class (posx,posy)
class Cell(var col:Int = 0, var row: Int = 0){
var topWall = true
var leftWall = true
var bottomWall = true
var rightWall = true
var visited = false
}
fun createMaze(){
var stack = Stack<Cell>()
var current:Cell
var next:Cell?
for(x in 0 until COLS){
for(y in 0 until ROWS){
cells[x][y] = Cell(x,y)
}
}
player = cells[0][0]
exit = cells [COLS-1][ROWS-1]
current = cells[0][0]
current.visited = true
do{
next = getNeighbour(current)
if(next != null) {
removeWall(current, next)
stack.push(current)
current = next
current.visited = true
}else{
current = stack.pop()
}
}while (!stack.empty())
}
fun getNeighbour(cell:Cell): Cell? {
var vecinos: ArrayList<Cell> = ArrayList()
//vecino izquierda
if(cell.col > 0) {
if (!cells[cell.col - 1][cell.row].visited) {
vecinos.add(cells[cell.col - 1][cell.row])
}
}
//vecino derecha
if(cell.col < COLS - 1) {
if (!cells[cell.col + 1][cell.row].visited) {
vecinos.add(cells[cell.col + 1][cell.row])
}
}
//vecino arriba
if(cell.row > 0) {
if (!cells[cell.col][cell.row - 1].visited) {
vecinos.add(cells[cell.col ][cell.row - 1])
}
}
//vecino abajo
if(cell.row < ROWS - 1) {
if (!cells[cell.col][cell.row + 1].visited) {
vecinos.add(cells[cell.col][cell.row + 1])
}
}
if (vecinos.size > 0) {
var index = random.nextInt(vecinos.size)
return vecinos[index]
}else {
return null
}
}
fun removeWall(current:Cell,next:Cell){
if (current.col == next.col && current.row == next.row +1){
current.topWall = false
next.bottomWall = false
}
if (current.col == next.col && current.row == next.row -1){
current.bottomWall = false
next.topWall = false
}
if (current.col == next.col + 1 && current.row == next.row){
current.leftWall = false
next.rightWall = false
}
if (current.col == next.col - 1 && current.row == next.row){
current.rightWall = false
next.leftWall = false
}
}
If you want to pass a seed to create the maze, then you have to make sure that all of the players are using the same random number generator. Which means you have to supply your own random number generator implementation.
The application would seed the random number generator with the value you pass, and then it should deterministically generate the same sequence of random numbers for each client.
Note also that you can't ever change the random number generator implementation unless you can prove that the new implementation will generate exactly the same sequence of numbers that the original did.

Remove data from list while iterating kotlin

I am new to kotlin programming. What I want is that I want to remove a particular data from a list while iterating through it, but when I am doing that my app is crashing.
for ((pos, i) in listTotal!!.withIndex()) {
if (pos != 0 && pos != listTotal!!.size - 1) {
if (paymentsAndTagsModel.tagName == i.header) {
//listTotal!!.removeAt(pos)
listTotal!!.remove(i)
}
}
}
OR
for ((pos,i) in listTotal!!.listIterator().withIndex()){
if (i.header == paymentsAndTagsModel.tagName){
listTotal!!.listIterator(pos).remove()
}
}
The exception which I am getting
java.lang.IllegalStateException
use removeAll
pushList?.removeAll { TimeUnit.MILLISECONDS.toMinutes(
System.currentTimeMillis() - it.date) > THRESHOLD }
val numbers = mutableListOf(1,2,3,4,5,6)
val numberIterator = numbers.iterator()
while (numberIterator.hasNext()) {
val integer = numberIterator.next()
if (integer < 3) {
numberIterator.remove()
}
}
It's forbidden to modify a collection through its interface while iterating over it. The only way to mutate the collection contents is to use Iterator.remove.
However using Iterators can be unwieldy and in vast majority of cases it's better to treat the collections as immutable which Kotlin encourages. You can use a filter to create a new collections like so:
listTotal = listTotal.filterIndexed { ix, element ->
ix != 0 && ix != listTotal.lastIndex && element.header == paymentsAndTagsModel.tagName
}
The answer by miensol seems perfect.
However, I don't understand the context for using the withIndex function or filteredIndex. You can use the filter function just by itself.
You don't need access to the index the list is at, if you're using
lists.
Also, I'd strongly recommend working with a data class if you already aren't. Your code would look something like this
Data Class
data class Event(
var eventCode : String,
var header : String
)
Filtering Logic
fun main(args:Array<String>){
val eventList : MutableList<Event> = mutableListOf(
Event(eventCode = "123",header = "One"),
Event(eventCode = "456",header = "Two"),
Event(eventCode = "789",header = "Three")
)
val filteredList = eventList.filter { !it.header.equals("Two") }
}
The following code works for me:
val iterator = listTotal.iterator()
for(i in iterator){
if(i.haer== paymentsAndTagsModel.tagName){
iterator.remove()
}
}
You can also read this article.
People didn't break iteration in previous posts dont know why. It can be simple but also with extensions and also for Map:
fun <T> MutableCollection<T>.removeFirst(filter: (T) -> Boolean) =
iterator().removeIf(filter)
fun <K, V> MutableMap<K, V>.removeFirst(filter: (K, V) -> Boolean) =
iterator().removeIf { filter(it.key, it.value) }
fun <T> MutableIterator<T>.removeFirst(filter: (T) -> Boolean): Boolean {
for (item in this) if (filter.invoke(item)) {
remove()
return true
}
return false
}
Use a while loop, here is the kotlin extension function:
fun <E> MutableList<E>.removeIfMatch(isMatchConsumer: (existingItem: E) -> Boolean) {
var index = 0
var lastIndex = this.size -1
while(index <= lastIndex && lastIndex >= 0){
when {
isMatchConsumer.invoke(this[index]) -> {
this.removeAt(index)
lastIndex-- // max is decreased by 1
}
else -> index++ // only increment if we do not remove
}
}
}
Typically you can use:
yourMutableCollection.removeIf { someLogic == true }
However, I'm working with an Android app that must support APIs older than 24.
In this case removeIf can't be used.
Here's a solution that is nearly identical to that implemented in Kotlin Collections that doesn't rely on Predicate.test - which is why API 24+ is required in the first place
//This function is in Kotlin Collections but only for Android API 24+
fun <E> MutableCollection<E>.removeIff(filter: (E) -> Boolean): Boolean {
var removed = false
val iterator: MutableIterator<E> = this.iterator()
while (iterator.hasNext()) {
val value = iterator.next()
if (filter.invoke(value)) {
iterator.remove()
removed = true
}
}
return removed
}
Another solution that will suit small collections. For example set of listeners in some controller.
inline fun <T> MutableCollection<T>.forEachSafe(action: (T) -> Unit) {
val listCopy = ArrayList<T>(this)
for (element: T in listCopy) {
if (this.contains(element)) {
action(element)
}
}
}
It makes sure that elements of collection can be removed safely even from outside code.

Android - Kotlin - stop for in middle of process

Is there is any way to stop for loop in Kotlin in middle of process without using a break ?
Example :
for (item in items) {
for (item2 in arrRealmTemp ) {
if (item.MKT == item2.MKT && item.UPC == item2.UPC ) {
// I want to stop this (the inner for only ) here
}
}
}
You can use label in following way.
loop# for (i in 1..100) {
for (j in 1..100) {
if (...) break#loop
}
}
In Kotlin you can use labels and continue to be sure to continue with the next iteration of a for loop:
loop# for (item in items) {
for (item2 in arrRealmTemp ) {
if (item.MKT == item2.MKT && item.UPC == item2.UPC ) {
continue#loop
}
}
}

Categories

Resources