From f6ee4b7704fca66b88b98cd1850d21176b35765a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adolf=20Andr=C3=A1s?= <adolf.andras@itk.ppke.hu>
Date: Fri, 7 Jun 2024 17:31:55 +0200
Subject: [PATCH] Game updated

---
 .../com/example/mindrover/GameFragment.kt     |  58 +++++++++-
 .../com/example/mindrover/MainActivity.kt     |   2 +-
 .../mindrover/model/EEGDataListener.kt        | 105 +++++-------------
 .../example/mindrover/model/GameManager.kt    |  97 ++++++++++++++--
 app/src/main/res/layout/fragment_game.xml     |  13 +++
 5 files changed, 187 insertions(+), 88 deletions(-)

diff --git a/app/src/main/java/com/example/mindrover/GameFragment.kt b/app/src/main/java/com/example/mindrover/GameFragment.kt
index 8830406..ebb771c 100644
--- a/app/src/main/java/com/example/mindrover/GameFragment.kt
+++ b/app/src/main/java/com/example/mindrover/GameFragment.kt
@@ -1,5 +1,6 @@
 package com.example.mindrover
 
+import android.graphics.Color
 import android.os.Bundle
 import android.util.Log
 import androidx.fragment.app.Fragment
@@ -9,6 +10,8 @@ import android.view.ViewGroup
 import androidx.fragment.app.activityViewModels
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.Observer
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.viewModelScope
 import androidx.navigation.fragment.findNavController
 import com.example.mindrover.databinding.FragmentGameBinding
 import com.example.mindrover.databinding.FragmentTrainBinding
@@ -18,6 +21,10 @@ import com.example.mindrover.model.ExperimentNavigator
 import com.example.mindrover.model.ExperimentState
 import com.example.mindrover.model.GameCommand
 import com.example.mindrover.model.GameManager
+import com.example.mindrover.model.Question
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 
 // TODO: Rename parameter arguments, choose names that match
 // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
@@ -83,16 +90,63 @@ class GameFragment : Fragment() {
                     if (choiceNum < 0) {
                         choiceNum = 3
                     }
+                } else if (state == GameCommand.CHOOSE) {
+                    binding.button6.callOnClick()
+                    gameManager.answerQuestion(choiceNum)
+                } else if (state == GameCommand.PAUSE) {
+//                    gameManager.pauseGame()
+//                    binding.radioGroup.checkedRadioButtonId
+//                    binding.radioGroup.
+//                    binding.radioButton3.setTextColor(Color.GREEN)
+                    var color = Color.RED
+
+                    if (gameManager.correctAnswer)
+                        color = Color.GREEN
+
+
+                    when (binding.radioGroup.checkedRadioButtonId) {
+                        binding.radioButton3.id -> binding.radioButton3.setTextColor(color)
+                        binding.radioButton4.id -> binding.radioButton4.setTextColor(color)
+                        binding.radioButton5.id -> binding.radioButton5.setTextColor(color)
+                        binding.radioButton6.id -> binding.radioButton6.setTextColor(color)
+                    }
+//
+                } else if (state == GameCommand.REST) {
+                        binding.radioButton3.setTextColor(Color.WHITE)
+                        binding.radioButton4.setTextColor(Color.WHITE)
+                        binding.radioButton5.setTextColor(Color.WHITE)
+                        binding.radioButton6.setTextColor(Color.WHITE)
+//                        choiceNum = 0
+
                 }
 
                 binding.radioGroup.check(radioGroupArray[choiceNum])
 
+
+
+
                 Log.d("Observer", "Observed:${state.name}")
             }
         }
 //        eegDataListener.actualCommand.observe(viewLifecycleOwner, commandObserver)
         gameManager.actualCommand.observe(viewLifecycleOwner, commandObserver)
 
+        val questionObserver = Observer<Question> { state ->
+            binding.textView2.setText(state.question)
+            binding.radioButton3.setText(state.answers[0])
+            binding.radioButton4.setText(state.answers[1])
+            binding.radioButton5.setText(state.answers[2])
+            binding.radioButton6.setText(state.answers[3])
+        }
+
+        gameManager.actualQuestion.observe(viewLifecycleOwner, questionObserver)
+
+        val pointObserver = Observer<Int> { state ->
+            binding.points.setText("Points: ${state}")
+        }
+
+        gameManager.points.observe(viewLifecycleOwner, pointObserver)
+
 //        val accelerationObserver = Observer<Array<Int>> {
 //
 //            binding.radioButton4.setText(it[0].toString())
@@ -103,8 +157,10 @@ class GameFragment : Fragment() {
 
 //        eegDataListener.accelerations.observe(viewLifecycleOwner, accelerationObserver)
 
+
+
         gameManager.setEEGDataListener(eegDataListener)
-        gameManager.startGame(5)
+        gameManager.startGame(30)
 
     }
 
diff --git a/app/src/main/java/com/example/mindrover/MainActivity.kt b/app/src/main/java/com/example/mindrover/MainActivity.kt
index 0bc7f89..c1733ce 100644
--- a/app/src/main/java/com/example/mindrover/MainActivity.kt
+++ b/app/src/main/java/com/example/mindrover/MainActivity.kt
@@ -43,7 +43,7 @@ class MainActivity : AppCompatActivity() {
                     sensorData.channel6, sensorData.channel7, sensorData.channel8
                 )
             )
-//            eegListener.addGeolocation(sensorData.accelerationX, sensorData.accelerationY, sensorData.accelerationZ)
+            eegListener.addAcceleration(sensorData.accelerationX, sensorData.accelerationY, sensorData.accelerationZ)
 
         } else {
             eegListener.addImpedance(
diff --git a/app/src/main/java/com/example/mindrover/model/EEGDataListener.kt b/app/src/main/java/com/example/mindrover/model/EEGDataListener.kt
index 15d0164..7f80460 100644
--- a/app/src/main/java/com/example/mindrover/model/EEGDataListener.kt
+++ b/app/src/main/java/com/example/mindrover/model/EEGDataListener.kt
@@ -27,7 +27,8 @@ class EEGDataListener: ViewModel() {
     val impedances: LiveData<Array<Int>> = _impedances
 
 //    private val _accelerations = MutableLiveData<Array<Int>>()
-//    val accelerations: LiveData<Array<Int>> = _impedances
+//    val accelerations: LiveData<Array<Int>> = _accelerations
+    val accelerations: Array<Array<Int>> = arrayOf(arrayOf(), arrayOf(), arrayOf())
 //
     private val _connection = MutableLiveData<ConnectionState>()
     val connection: LiveData<ConnectionState> = _connection
@@ -48,78 +49,6 @@ class EEGDataListener: ViewModel() {
     val sharedFlow = _sharedFlow.asSharedFlow()
 
 
-//    val latestData: Flow<Array<Array<DataPoint>>> = flow {
-//
-//
-////    fun startStreaming() {
-//
-////        viewModelScope.launch {
-//
-//        var currentData = arrayOf<Array<DataPoint>>()
-//        for (i in 0 until numOfChannels) {
-//            wholeData = wholeData.plus(arrayOf<DataPoint>())
-//            currentData = currentData.plus(arrayOf<DataPoint>())
-//        }
-//
-//        _impedances.value = emptyArray()
-//
-////        repeat(numOfChannels) {
-////            _impedances.value = _impedances.value?.plus(Random.nextDouble() * 20 + 2)
-////        }
-//
-//
-//
-//        while (true) {
-//
-//            //Get last package of data
-//            for (i in 0..5) {
-//                time++
-//
-//                for (ch in 0 until numOfChannels) {
-//                    if ((time.toInt() % 4000) == 20) {
-//                        wholeData[ch] = wholeData[ch].plus(DataPoint(time, 20.0))
-//                    } else {
-//                        wholeData[ch] =
-//                            wholeData[ch].plus(DataPoint(time, Random.nextDouble() * 10))
-//                    }
-//                }
-//            }
-//
-//            //Update dataset
-////            var imps = _impedances.value!!
-////            for (i in 0 until numOfChannels) {
-////                imps[i] = imps[i] + (Random.nextDouble() - 0.5)
-////            }
-////            _impedances.value = imps
-//
-//            delay(100)
-//
-//            //Update impedances
-//            val size = minOf(100, wholeData[0].size)
-//
-//            for (ch in 0 until numOfChannels) {
-//                val data = wholeData[ch].takeLast(size).toTypedArray()
-//                for (i in 0 until size) {
-//                    data[i] = DataPoint(i.toDouble(), data[i].y)
-//                }
-//                currentData[ch] = data
-//            }
-//
-//            //Free memory with whole data
-//
-//            if (wholeData[0].size > MAXSTOREDPOINT * 2) {
-//                for (ch in 0 until numOfChannels) {
-//                    wholeData[ch] = wholeData[ch].takeLast(MAXSTOREDPOINT).toTypedArray()
-//                }
-//            }
-//
-//            _lastData.value = currentData
-//            emit(currentData)
-//
-//        }
-//        }
-//    }
-
     init {
 //        testCoroutine()
         _connection.value = ConnectionState.NO_CONNECTION
@@ -197,10 +126,34 @@ class EEGDataListener: ViewModel() {
         Log.d("Impedance arrived", "Impedance value 1: ${array[5]}")
     }
 
-//    fun addGeolocation(x: Int, y: Int, z: Int) {
-//        _accelerations.value = arrayOf(x, y, z)
-//    }
+    fun addAcceleration(x: Int, y: Int, z: Int) {
+        accelerations[0] = accelerations[0].plus(x)
+        accelerations[1] = accelerations[1].plus(y)
+        accelerations[2] = accelerations[2].plus(z)
+
+        accelerations[0] = accelerations[0].takeLast(MAXSTOREDPOINT).toTypedArray()
+        accelerations[1] = accelerations[1].takeLast(MAXSTOREDPOINT).toTypedArray()
+        accelerations[2] = accelerations[2].takeLast(MAXSTOREDPOINT).toTypedArray()
 
+//        for (i in 0..2) {
+//            if (accelerations[i].size > MAXSTOREDPOINT * 2) {
+//                accelerations[i] = accelerations[i].takeLast(MAXSTOREDPOINT).toTypedArray()
+//            }
+//        }
+
+    }
+    fun getLatestAcceleration(ms: Int): Array<Array<Int>>? {
+
+        if (accelerations[0].isEmpty() || accelerations[0].size < ms) {
+            Log.e("ERROR", "wholedata is shorter than expected")
+            return null
+        }
+        var data: Array<Array<Int>> = arrayOf()
+        for (ch in 0 until 3) {
+            data = data.plus(accelerations[ch].takeLast(ms).toTypedArray())
+        }
+        return data
+    }
 
 }
 
diff --git a/app/src/main/java/com/example/mindrover/model/GameManager.kt b/app/src/main/java/com/example/mindrover/model/GameManager.kt
index b6180b1..ad0b5ba 100644
--- a/app/src/main/java/com/example/mindrover/model/GameManager.kt
+++ b/app/src/main/java/com/example/mindrover/model/GameManager.kt
@@ -10,9 +10,25 @@ import kotlinx.coroutines.Delay
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import org.jetbrains.kotlinx.dl.dataset.Dataset
+import java.security.KeyStore.TrustedCertificateEntry
 
 enum class GameCommand {
-    CHOOSE, REST, GO_UP, GO_DOWN
+    CHOOSE, REST, GO_UP, GO_DOWN, PAUSE
+}
+
+data class Question(val question: String, val answers: Array<String>, val correctIdx: Int) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Question
+
+        return answers.contentEquals(other.answers)
+    }
+
+    override fun hashCode(): Int {
+        return answers.contentHashCode()
+    }
 }
 
 class GameManager(): ViewModel() {
@@ -23,43 +39,104 @@ class GameManager(): ViewModel() {
     private val _actualCommand = MutableLiveData<GameCommand>()
     val actualCommand: LiveData<GameCommand> = _actualCommand
 
+    private val _actualQuestion = MutableLiveData<Question>()
+    val actualQuestion: LiveData<Question> = _actualQuestion
+
+
+    var questions: Array<Question> = arrayOf()
+
+    var gameStarted = false
+
+    var correctAnswer = false
+
+    private val _points = MutableLiveData<Int>()
+    val points: LiveData<Int> = _points
+
+    var paused = false
+
     var debugNum = 1
 
 
-    fun nextCommand(eeg: Array<Array<Double>>, pos: Array<Array<Double>>) {
+    fun nextCommand(eeg: Array<Array<Double>>, pos: Array<Array<Int>>) {
 //        eegDataset = Dataset()
 //        network.predict(eeg)
-        debugNum += 1
-        if (debugNum%3 == 1) {
-            _actualCommand.value = GameCommand.GO_DOWN
-        } else if (debugNum%3 == 2) {
+//        debugNum += 1
+//        if (debugNum%3 == 1) {
+//            _actualCommand.value = GameCommand.GO_DOWN
+//        } else if (debugNum%3 == 2) {
+//            _actualCommand.value = GameCommand.GO_DOWN
+//        } else {
+//            _actualCommand.value = GameCommand.CHOOSE
+//        }
+
+        Log.d("NEXT position", "${pos[0].average()} - ${pos[1].average()} - ${pos[2].average()}")
+        val averageZ = pos[2].average()
+
+        if (averageZ > 5000) {
             _actualCommand.value = GameCommand.GO_DOWN
-        } else {
+        } else if (averageZ < -2000) {
             _actualCommand.value = GameCommand.CHOOSE
+        } else {
+            _actualCommand.value = GameCommand.REST
         }
+
     }
 
     fun setEEGDataListener(eegListener: EEGDataListener) {
         _eegDataListener = eegListener
     }
 
+    fun initQuestions() {
+        questions = questions.plus(Question("Mi a szösz?", arrayOf("Hello", "Bello", "Szia", "Szösz"), 3))
+        questions = questions.plus(Question("Miért?", arrayOf("Mert", "Bello", "Szia", "Szösz"), 0))
+        questions = questions.plus(Question("Hogyan?", arrayOf("Mert", "Így", "Szia", "Szösz"), 1))
+    }
+
+    fun answerQuestion(idx: Int): Boolean {
+        correctAnswer = actualQuestion.value?.correctIdx == idx
+        if (correctAnswer) {
+            _points.value = (_points.value?.plus(1))
+        }
+//        _actualCommand.value = GameCommand.CHOOSE
+        return correctAnswer
+    }
+
+    fun pauseGame() {
+        paused = true
+    }
+    fun continueGame() {
+        paused = false
+    }
+
     fun startGame(numOfQuestions: Int) {
+        if (!gameStarted) {
+            gameStarted = true
+            initQuestions()
+            _points.value = 0
+        } else {
+            return
+        }
 
         viewModelScope.launch {
 
             for (i in 0..numOfQuestions) {
                 _actualCommand.value = GameCommand.REST
+                _actualQuestion.value = questions[i%questions.size]
                 while (actualCommand.value != GameCommand.CHOOSE) {
+                    delay(1000)
 
-                    delay(500)
-                    var eeg = _eegDataListener?.getLatestData(50)
-                    var pos = _eegDataListener?.getLatestData(50)
+                    var eeg = _eegDataListener?.getLatestData(500)
+                    var pos = _eegDataListener?.getLatestAcceleration(500)
 
                     if (eeg != null && pos != null) {
                         nextCommand(eeg, pos)
                     }
                 }
+                _actualCommand.value = GameCommand.PAUSE
+                delay(1000)
+
             }
+            gameStarted = false
         }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_game.xml b/app/src/main/res/layout/fragment_game.xml
index 65776f1..e842d21 100644
--- a/app/src/main/res/layout/fragment_game.xml
+++ b/app/src/main/res/layout/fragment_game.xml
@@ -18,6 +18,16 @@
             android:id="@+id/textView2"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:textSize="30sp"
+            android:layout_margin="20sp"
+            android:text="TextView" />
+
+        <TextView
+            android:id="@+id/points"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewEnd"
+            android:layout_marginRight="20sp"
             android:text="TextView" />
 
         <Space
@@ -26,6 +36,7 @@
 
         <RadioGroup
             android:layout_width="match_parent"
+            android:layout_margin="20sp"
             android:layout_height="278dp"
             android:id="@+id/radioGroup">
 
@@ -63,11 +74,13 @@
             android:id="@+id/button6"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_margin="30sp"
             android:text="Button" />
 
         <Space
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
+
     </LinearLayout>
 
 </FrameLayout>
\ No newline at end of file
-- 
GitLab