I have board for game tic-tac-toe. When I'm tryna add new board to list of boards it's always overwrites
fun String.replaceUnusualSymbols() =
replace(", ", "").replace("[", "").replace("]", "")
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>) = indices.forEach {
println("|${board[it].contentToString().replaceUnusualSymbols()}|")
}
fun main() {
var board = Array(3) { Array(3) { ' ' } }
val game: ArrayList<Array<Array<Char>>> = arrayListOf()
board[0][0] = 'X'
game.add(board) // add first board
board[1][1] = 'X'
game.add(board) // add second board
println(game.size)
game.forEach {
it.printBoard(board) // but outputs always second board
}
}
How to fix this?
There are two problems.
Array is a mutable collection. Since you only created one var board, there's only once instance - which is mutated every time you do board[0][0] = 'X' or board[0][1] = '0'.
it.printBoard(board) isn't printing each board, it's only printing the same board.
Copying the mutable Array
You can try copying the board every time you want to add the current board state to game.
Note that because board is a nested array, just doing board.copyOf() isn't enough - this won't copy recursively. So we have to specifically copy each row of board as well.
Because map {} returns a List and board is an Array, we have to convert the copied result using toTypedArray().
board[0][0] = 'X'
game.add(board.map { row -> row.copyOf() }.toTypedArray()) // add first board
board[1][1] = '0'
game.add(board.map { row -> row.copyOf() }.toTypedArray()) // add second board
What we end up with is something that's pretty clunky and verbose. We can try making an extension function for the copy, but then we'll still have the risk involved with mutable collections. What happens if at some point you forget to copy the board?
To keep this answer short and focused, I'll leave refactoring to use immutable collections as an exercise for the reader, with some hints:
How can you use a class to encapsulate the game logic?
Instead of using a List<List<Char>>, can you create a data class?
Can you create a function that both 1. adds a new symbol to the board, and 2. saves the current game state, in one go?
printBoard()
printBoard() is an extension function has both a receiver and an argument of type Array<Array<Char>>, which is unusual.
// receiver
// ↓
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>)
// ↑
// argument
This is causing one bug. When you call it.printBoard(board), it will use the indices of it, but it will print the values of board.
// the indices come from the receiver
// ↓
fun Array<Array<Char>>.printBoard(board: Array<Array<Char>>) = indices.forEach {
println("|${board[it].contentToString().replaceUnusualSymbols()}|")
} // ↑
// the values come from the argument
So when you use it in a loop like this
game.forEach {
// argument
// ↓
it.printBoard(board)
// ↑
// receiver
}
it won't print each board.
Here's a fixed version that will only print the receiver.
fun Array<Array<Char>>.printBoard() = indices.forEach {
println("|${this[it].contentToString().replaceUnusualSymbols()}|")
}
Replace replaceUnusualSymbols() with joinToString()
And I'll go one step further - we can get rid of contentToString() and replaceUnusualSymbols() and use the Kotlin stdlib function joinToString():
fun Array<Array<Char>>.printBoard() {
val boardString = joinToString(
separator = "\n",
prefix = "\n",
) { row ->
row.joinToString(" ", prefix = "|", postfix = "|")
}
println(boardString)
}
Related
I'm trying to make an editor app that allows you to undo/redo changes. I want to achieve that by storing the ui state in stacks (ArrayDeque) and pop them back once the user hits undo/redo. But every time I stored the state in stack, after I made change to the state, the value in the stack is changed as well.
Is there a way to snapshot a state that won't be affected by future changes in the state flow?
My code looks something like this:
Data Class
class Data () {
var number: Int = 0
fun foo()
}
State Class
data class UiState(
val dataList: MutableList<Data> = mutableListOf(),
)
ViewModel
class UiViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
private val undoStack: ArrayDeque<UiState> = ArrayDeque()
fun makeChangeToState() {
saveStateToUndoStack(_uiState.value)
Log.i("Test", undoStack.last().dataList[0].number) // 0
val dataList= _uiState.value.dataList.toMutableStateList()
dataList[0].number = 1
_uiState.update { currentState ->
currentState.copy(
dataList = dataList,
)
}
Log.i("Test", undoStack.last().dataList[0].number) // 1 because the _uiState changed
}
fun undo() {
val lastState = undoStack.last()
// Won't work because the data in lastState has already been updated with _uiState
_uiState.update { lastState }
}
}
Things I've tried:
Use _uiState.value.copy
Call saveStateToUndoStack(uiState: UiState) from Composable functions and pass in the viewModel.uiState.collectAsState()
Both doesn't seem to work, I play around for a few hours but don't have a clue.
The reason why the old value got updated is because all the objects in the list are references, not related to MutableStateFlow. I just need a deep copy of the list, see this post here:
https://www.baeldung.com/kotlin/deep-copy-data-class
Another thread worth reading: Deep copy of list with objects in Kotlin
I am making a game in Kotlin.Using Libgdx and Box2d
1.function creates bodies via Box2d and adds these bodies in bodyArrayList:ArrayList
2.function creates textures and adds these textures in textureArrayList
3.function is matching items of bodyArrayList with items of textureArrayList. The function has for loop.
4.function is removing bodies when crash a wall.
5.function is removing textures when crash a wall.
All functions are working in update() method.
All these are working perfectly. However because I cannot remove items of te ArrayLists while for loop works on these ArrayLists, items of ArrayList is increasing and the game is starting slowing downn 1 hour later. The ArrayLists' size is going up as you guess.
If I try to remove items of ArrayLists I am taking exceptions in matching() function as you guess.
My question is how can I remove these items from ArrayLists while "for loop" is working in a safe manner.
1.function creates bodies
var body = makeBody()
bodyArray.add(body)
2.function creates textures
var texture=makeTexture()
textureArray.add(texture)
3.function is matching items of bodyArrayList with items of textureArrayList
for (i in 0..bodyArray.size-1) {
textureArray[i].setPosition(bodyArray[i].position.x, bodyArray[i].position.y)
}
4.funtion is removing bodies when crash a wall.
override fun beginContact(contact: Contact?) {
val userDataA = contact!!.fixtureA.userData.toString()
val userDataB = contact.fixtureB.userData.toString()
if ((userDataA == "ball" && userDataB == "wall")){
val bodyA=contact.fixtureA.body
Gdx.app.postRunnable(Runnable(){
run(){
world.destroyBody(bodyA) } })
}
5.function is removing textures when crash a wall.
for (texture: MyTextures in MyTextures.getList(Ball::class.java.canonicalName)) {
if (ball.overlaps(wall)) {
ball.remove() }
}
You can use Iterator to remove items from Collections while iterating
val list = arrayListOf<Int>()
val listIterator = list.iterator()
while(listIterator.hasNext()){
//get item
val item = listIterator.next()
//items can be removed safely using
listIterator.remove()
}
if you are using badLogic Array class you can give your texture class to it and dispose every item of it in dispose method
private val texture = Texture("badlogic.jpg")
private val myArray = Array<Texture>()
fun dispose(){
myArray[i].dispose()
}
this is the link for more info on textures...
also you can dispose Screen Class
I am building simple application that will track a certain tabletop game of 2 players.
I have a view called MatchView
class MatchView : View() {
// data
private var currentRound = SimpleIntegerProperty(0)
private var currentTurn = SimpleIntegerProperty(0)
override val root = borderpane {
center = label(currentRound.stringBinding{ "Round %d".format(it) })
// other layout-related stuff
subscribe<EndTurnEvent> {
endPlayerTurn()
}
}
private fun endPlayerTurn() {
// increment turn
currentTurn.plus(1)
currentRound.plus(currentTurn.value % 2)
}
}
that is subscribed to EndTurnEvent - event emitted by one of the fragments used by view.
The called method is supposed to increment value of currentTurn and if needed currentRound (round increments after second player ends their turn)
However neither the value of currentRound nor the one of currentTurn are getting increased when i call .plus() method.
I have tried editting values differently :
private fun endPlayerTurn() {
// increment turn
currentTurn.value = currentTurn.value + 1
currentRound.value = currentTurn.value % 2
}
But this throws me java.lang.IllegalStateException: Not on FX application thread
I am aware that putting properties into views is anti-pattern, but since I just want to keep track of 2 properties, I thought I could put them directly into View
Platform.runLater(() -> {
// Update GUI from another Thread here
});
I'm working on a Swift 3 project that involves using some C APIs that I bridged from Objective-C.
Here is a sample snippet of the structure of the API:
typedef struct
{
StructMode mode;
StructLevel level;
} TargetStruct;
typedef struct
{
. . .
TargetStruct *targetStruct;
OtherStruct *otherStruct;
NonPointerStructA nonPointerStructA;
NonPointerStructB nonPointerStructB;
. . .
} InnerStruct;
typedef struct
{
InnerStruct innerStruct;
OtherStructB otherStructB;
} OuterStruct;
In my Swift code, my goal is to set a value of the TargetStruct from the OuterStruct, like the following:
// run function that returns an instance of TargetStruct
var targetStruct: TargetStruct = initializeTargetStruct()
// assign targetStruct to outerStruct
outerStruct.innerStruct.targetStruct = &targetStruct
However, I am getting the following error:
Cannot pass immutable value of TargetStruct as inout argument
If I set a value of a struct without the *, it will work fine:
var nonPointerStructA: NonPointerStructA = initializeNonPointerStructA()
outerStruct.innerStruct.nonPointerStructA = nonPointerStructA
I have tried setting the value of targetStruct like this, but for now I have no way to test it:
var targetStruct: TargetStruct = initializeTargetStruct()
outerStruct.innerStruct.targetStruct.initialize(from: &targetStruct, count: 0)
How to solve this problem? Thank you.
In Swift, prefix & is not an address-of operator. It is just needed to clarify that some expression is passed to an inout parameter. So, your first code is syntactically invalid in Swift.
Your C-structs are imported to Swift as follows:
struct TargetStruct {
var mode: StructMode
var level: StructLevel
//some auto generated initializers...
}
struct InnerStruct {
//...
var targetStruct: UnsafeMutablePointer<TargetStruct>!
var otherStruct: UnsafeMutablePointer<OtherStruct>!
var nonPointerStructA: NonPointerStructA
var nonPointerStructB: NonPointerStructB
//some auto generated initializers...
}
struct OuterStruct {
var innerStruct: InnerStruct
var otherStructB: OtherStructB
//some auto generated initializers...
}
(If something wrong, please tell me.)
As you see, targetStruct in your InnerStruct is a pointer, and initialize(from:count:) tries to write to the pointed region, but at the time you call initialize(from:count:), targetStruct holds its initial value nil, you know what happens when dereferencing null-pointer.
One way is to allocate a memory for the TargetStruct and use the pointer to the allocated region.
func allocateAndInitializeTargetStruct() -> UnsafeMutablePointer<TargetStruct> {
let targetStructRef = UnsafeMutablePointer<TargetStruct>.allocate(capacity: 1)
targetStructRef.initialize(to: initializeTargetStruct())
return targetStructRef
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
This is a more general way than below, but you need to explicitly deinitialize and deallocate the allocated region. That's sort of hard to manage.
If you can confine the usage of the outerStruct in a single code-block, you can write something like this:
var targetStruct = initializeTargetStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
//Use `outerStruct` only inside this code-block
//...
}
In this case, the pointer held in outerStruct.innerStruct.targetStruct (== targetStructPtr) is only valid inside the closure and you cannot use it outside of it.
If any of the codes above does not fit for your use case, you may need to provide more context to find the best solution.
An example of nested use of withUnsafeMutablePointer(to:_:):
var targetStruct = initializeTargetStruct()
var otherStruct = initializeOtherStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
withUnsafeMutablePointer(to: &otherStruct) {otherStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
outerStruct.innerStruct.otherStruct = otherStructPtr
//Use `outerStruct` only inside this code-block
//...
}
}
When you need more pointers to set, this nesting would be a mess, but it's the current limitation of Swift.
An example of deinitialize and deallocate:
extension InnerStruct {
func freeMemberStructs() {
if let targetStructRef = targetStruct {
targetStructRef.deinitialize()
targetStructRef.deallocate(capacity: 1)
targetStruct = nil
}
if let otherStructRef = otherStruct {
otherStructRef.deinitialize()
otherStructRef.deallocate(capacity: 1)
otherStruct = nil
}
}
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
outerStruct.innerStruct.otherStruct = allocateAndInitializeOtherStruct()
// Use `outerStruct`
//...
outerStruct.innerStruct.freeMemberStructs()
The code may not seem to be too complex (just a bunch of boilerplate codes), but it's hard to find when or where to do it. As your InnerStruct may be embedded in another struct which may need to be deinitilized and deallocated...
Hope you can find your best solution.
When looping over a slice of structs, the value I get is a reference (which is fine), however in some cases it's annoying to have to write var as (*var) in many places.
Is there a better way to avoid re-declaring the variable?
fn my_fn(slice: &[MyStruct]) {
for var in slice {
let var = *var; // <-- how to avoid this?
// Without the line above, errors in comments occur:
other_fn(var); // <-- expected struct `MyStruct`, found reference
if var != var.other {
// ^^ trait `&MyStruct: std::cmp::PartialEq<MyStruct>>` not satisfied
foo();
}
}
}
See: actual error output (more cryptic).
You can remove the reference by destructuring in the pattern:
// |
// v
for &var in slice {
other_fn(var);
}
However, this only works for Copy-types! If you have a type that doesn't implement Copy but does implement Clone, you could use the cloned() iterator adapter; see Chris Emerson's answer for more information.
In some cases you can iterate directly on values if you can consume the iterable, e.g. using Vec::into_iter().
With slices, you can use cloned or copied on the iterator:
fn main() {
let v = vec![1, 2, 3];
let slice = &v[..];
for u in slice.iter().cloned() {
let u: usize = u; // prove it's really usize, not &usize
println!("{}", u);
}
}
This relies on the item implementing Clone or Copy, but if it doesn't you probably do want references after all.