diff --git a/app/src/main/java/com/example/mindrover/GameFragment.kt b/app/src/main/java/com/example/mindrover/GameFragment.kt index 8830406e00b58b0c35bcd3920ccd729214e3a442..ebb771c817cacbff0a68b0a2652324e31b1cb873 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 0bc7f89da262d0dc8182055846ffd11f93195ab0..c1733ce791d70d7c1cfcf183e9220cde650b0a63 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 15d016460539beb6c3bdb7426afe69d405e0352c..7f80460936925892fce12b4defb9080ebd1bdfe0 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 b6180b1ac76a9d5581862a391dfae400265c5f76..ad0b5ba27971f1eb26f970b594531cd314cbf5d7 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 65776f1570d8ddad702f5e914cafbe75d0f2c8f7..e842d214537b5ba6db7a2af33bf910e79a1ef426 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