Android Multi-row summation: Request for code shortening - android

I have a table with fifteen rows. Each row have three columns and a total column. I want to get the total per row, the grand total, and the overall average.
The user may not enter data for all rows, and the user may skip a row.
So the code checks if the user have entered data in one of three fields of each row.
If the row is blank, ignore it.
If some of the fields are filled-up, tell the user to fill up the rest of the row.
If all the fields in a row is filled up, sum all its fields and increment the divider.
I have only pasted the codes for Rows 1 & 2 for brevity, but it shows the gist of what I'm trying to achieve:
The code:
var a1 = 0
var a2 = 0
var total = 0
var divider = 0
// Row 1
if (b1p1.text.isNotEmpty() or b2p1.text.isNotEmpty() or b3p1.text.isNotEmpty()) {
var y = 0
listOf(b1p1, b2p1, b3p1).forEach {
if (it.text.isEmpty()) {
it.error = "Fill up empty fields!"
y = 1
}
}
if (y == 0) {
divider++
listOf(b1p1, b2p1, b3p1).forEach {
a1 += it.text.toString().toInt()
}
total1.text = a1.toString()
total += a1
e2 = 1
} else {
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show()
}
}
// Row 2
if (b1p2.text.isNotEmpty() or b2p2.text.isNotEmpty() or b3p2.text.isNotEmpty()) {
var y = 0
listOf(b1p2, b2p2, b3p2).forEach {
if (it.text.isEmpty()) {
it.error = "Fill up empty fields!"
y = 1
}
}
if (y == 0) {
divider++
listOf(b1p2, b2p2, b3p2).forEach {
a2 += it.text.toString().toInt()
}
total2.text = a2.toString()
total += a2
} else {
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show()
}
}
if (e2 == 1) {
grandTotalTextView.text = total.toString()
average = total.toDouble()/divider
val decimalFormatter = DecimalFormat("#,###.##")
averageTextView.text = decimalFormatter.format(average).toString()
cyeSingleton.anct3b = decimalFormatter.format(average).toString()
} else {
Toast.makeText(activity, "Error 2", Toast.LENGTH_SHORT).show()
}
The table:
This is the best I could come up with. Should there be no other suggestion, I will settle for this.
Thanks in advance!
**EDIT: Thanks to ** https://stackoverflow.com/users/3736955/jemshit-iskenderov
data class TotalResult(val divider:Int, val allTotal:Int, val showError:Boolean)
private fun calculateTotalResult(allTextViews:List<List<TextView>>, totalTextViews:List<TextView>): TotalResult {
var divider = 0
var allTotal = 0
var showError=false
allTextViews.forEachIndexed{index, rowTextViews->
val rowResult = calculateRowResult(rowTextViews as List<EditText>, totalTextViews[index])
if(!rowResult.ignoreRow){
if(rowResult.allFieldsFilled){
divider+=1
allTotal+=rowResult.rowTotal
}else{
showError = true
}
}
}
Toast.makeText(
activity,
"$divider, $allTotal, $showError", Toast.LENGTH_SHORT)
.show()
return TotalResult(divider, allTotal, showError)
}
data class RowResult(val ignoreRow:Boolean, val allFieldsFilled:Boolean, val rowTotal:Int)
private fun calculateRowResult(rowTextViews:List<EditText>, totalTextView:TextView): RowResult {
val ignore = rowTextViews.filter{it.text.isBlank()}.count() == rowTextViews.size
if(ignore)
return RowResult(true, false, 0)
var emptyFieldCount = 0
var total = 0
rowTextViews.forEach {textView ->
if (textView.text.isEmpty()) {
textView.error = "Fill up empty fields!"
emptyFieldCount +=1
}else{
val fieldValue:Int? = textView.text.toString().toIntOrNull() // or toIntOrElse{0}
if(fieldValue!=null) total+=fieldValue
}
}
if(emptyFieldCount==0)
totalTextView.text = total.toString()
return RowResult(false, emptyFieldCount==0, total)
}

fun main(){
val totalResult = calculateTotalResult(
allTextViews = listOf(
listOf(t11,t12,t13),
listOf(t21,t22,t23)
),
totalTextViews = listOf(totalView1, totalView2)
)
// single Toast error
if(totalResult.showError){
// showToast(error)
}
// use totalResult.divider, totalResult.allTotal
}
data class TotalResult(val divider:Int, val allTotal:Int, val showError:Boolean)
fun calculateTotalResult(allTextViews:List<List<TextView>>, totalTextViews:List<TextView>){
var divider = 0
var allTotal = 0
var showError=false
allTextViews.forEachIndexed{index, rowTextViews->
val rowResult = calculateRowResult(rowTextViews, totalTextViews[index])
if(!rowResult.ignore){
if(rowResult.allFieldsFilled){
divider+=1
allTotal+=rowResult.rowTotal
}else{
showError = true
}
}
}
return TotalResult(divider, allTotal, showError)
}
data class RowResult(val ignoreRow:Boolean, val allFieldsFilled:Boolean, val rowTotal:Int)
fun calculateRowResult(rowTextViews:List<TextView>, totalTextView:TextView): RowResult {
val ignore = rowTextViews.filter{it.isBlank()}.count() == rowTextViews.size
if(ignore)
return RowResult(true, false, 0)
var emptyFieldCount = 0
var total = 0
rowTextViews.forEach {textView ->
if (textView.text.isEmpty()) {
textView.error = "Fill up empty fields!"
emptyFieldCount +=1
}else{
val fieldValue:Int? = textView.text.toString().toIntOrNull() // or toIntOrElse{0}
if(fieldValue!=null) total+=fieldValue
}
}
if(emptyFieldCount==0)
totalTextView.text = total.toString()
return RowResult(false, emptyFieldCount==0, total)
}
Extracted calculateTotalResult() and calculateRowResult() so multiple rows and columns do not need to repeat same code.
calculateRowResult() processes singlet row of TextViews. I had to iterate rowTextViews twice, one to calculate ignore, the other to show error on TextView if not ignore. We don't show Toast Error here yet.
calculateTotalResult() iterates through all rows and gets total result. We show only one Toast Error (if required) after this step.
Code is pseudo-code, not tested.

Related

Kotlin Big Decimal division returning inaccurate results

I am building a calculator with Kotlin and android studio (my first project). All equations were working properly until recent tweaks with decimal format. Now large division operations returns inaccurate results.
For example 99,999,999 / 9% (0.09) = 1.11111110000E9
But 9% / 99,999,999 = 0 when it should = 9.0000000009E-10
Is this because the current DecimalFormat cannot return the negative exponent?
EDIT: after more testing I've found that changing division method to
doubleNum = doubleNum.divide(numBigDecimal, 10, BigDecimal.ROUND_HALF_UP).stripTrailingZeros()
running the same equation will return 9E-10 before formatting. After decimal format the result shows as "." only with no digits
// enum class and class properties
enum class LogicTypes {
None,Add,Subtract,Multiply,Divide
}
class MainActivity : AppCompatActivity() {
private var logicActive = false
private var currentLogic = LogicTypes.None
private var currentNum = BigDecimal.ZERO
private var displayNum = ""
private var memoryNum = BigDecimal.ZERO
// add num function - buttons 0-9 send indices to num arg
fun addNum(num: BigDecimal) {
val inputNum = num.toString()
if (displayNum == "0" && inputNum == "0") {
return
}
if (displayNum.contains(".")) {
val stringForm = displayNum.substring(displayNum.indexOf('.'), displayNum.length)
if (stringForm.length > 10) {
clearCalc()
Toast.makeText(this, "Only 10 digits after decimal point allowed.", Toast.LENGTH_SHORT).show()
return
}
}
if (displayNum.length >= 15 && !displayNum.contains(".")) {
clearCalc()
Toast.makeText(this, "Maximum of 15 digits allowed.", Toast.LENGTH_SHORT).show()
return
}
if (inputNum == "0" && currentNum.toDouble() == 0.0 && displayNum.contains(".")) {
if (displayNum.length > 11) {
clearCalc()
Toast.makeText(this, "Only 10 digits after decimal point allowed.", Toast.LENGTH_SHORT).show()
return
}
displayNum = "$displayNum$inputNum"
textView.text = displayNum
return
}
if (logicActive) {
logicActive = false
displayNum = "0"
}
displayNum = "$displayNum$inputNum"
updateDisplayNum()
}
// set currentNum and send to numFormat function to update textView
fun updateDisplayNum() {
if (currentNum.toString().length > 15) {
clearCalc()
Toast.makeText(this, "Maximum of 15 digits allowed.", Toast.LENGTH_SHORT).show()
return
}
val numBigDecimal = displayNum.toBigDecimal()
if(currentLogic == LogicTypes.None) {
if(displayNum.contains("-") && currentNum == BigDecimal.ZERO) {
textView.text = displayNum
return
} else {
currentNum = numBigDecimal
}
}
numFormat()
}
// format decimal and integers and update textview with exponent
fun numFormat() {
val numBigDecimal = displayNum.toBigDecimal()
if(displayNum.contains(".")) {
val stringForm = displayNum.substring(displayNum.indexOf('.'), displayNum.length)
var numFormat = "#,##0."
if(stringForm.length > 1) {
for (num in stringForm.indices-1) {
numFormat += "0"
}
}
if (displayNum.length > 16 || stringForm.length > 9) {
// stringform length > 9 works for division result - anything higher returns trailing zeros.
// anything under 11 for stringform condition results in inaccurate input -
// adding decimal through addNum() will return Exponential notation before logic
// I only want E notation on result only- have yet to test other equations -
// this can also make it impossible to take the result and conduct another logic operation as the result appends E0
// and thus the trailing digits after decimal is greater than 10
numFormat = "0.0000000000E0"
}
val df = DecimalFormat(numFormat)
textView.text = df.format(numBigDecimal)
return
}
var df = DecimalFormat("#,###")
if (displayNum.length > 15) {
df = DecimalFormat("0.0000000000E0")
}
textView.text = df.format(numBigDecimal)
}
// change logic to enum mode when button operator pressed
fun changeLogic(mode: LogicTypes) {
currentLogic = mode
logicActive = true
}
// calculate function
fun calculate() {
if (logicActive || currentLogic == LogicTypes.Divide && displayNum.toBigDecimal() == BigDecimal.ZERO
|| currentNum == BigDecimal.ZERO) {
Log.i(LOG_TAG, "caught the zero")
return
}
val numBigDecimal = displayNum.toBigDecimal()
var doubleNum = currentNum
val currentNumString = doubleNum.stripTrailingZeros().toPlainString()
val numBigDecimalString = numBigDecimal.stripTrailingZeros().toPlainString()
val addMsg = getString(R.string.calc_message, currentNumString, "+", numBigDecimalString)
val subMsg = getString(R.string.calc_message, currentNumString, "-", numBigDecimalString)
val multiMsg = getString(R.string.calc_message, currentNumString, "*", numBigDecimalString)
val divMsg = getString(R.string.calc_message, currentNumString, "/", numBigDecimalString)
when(currentLogic) {
LogicTypes.Add -> {
hintView.text = addMsg
doubleNum += numBigDecimal
doubleNum = doubleNum.stripTrailingZeros()
}
LogicTypes.Subtract -> {
hintView.text = subMsg
doubleNum -= numBigDecimal
doubleNum = doubleNum.stripTrailingZeros()
}
LogicTypes.Multiply -> {
hintView.text = multiMsg
doubleNum *= numBigDecimal
doubleNum = doubleNum.stripTrailingZeros()
}
LogicTypes.Divide -> {
hintView.text = divMsg
doubleNum /= numBigDecimal
doubleNum = doubleNum.stripTrailingZeros()
}
LogicTypes.None -> return
}
currentLogic = LogicTypes.None
displayNum = doubleNum.toString()
updateDisplayNum()
logicActive = true
}
Ok the issue was that I was using this in the calculate function.
displayNum = doubleNum.toString()
Changing to .toPlainString() gives correct notations. There are still issues with formatting but I'll see if I can work those out on my own
EDIT: I solved the formatting issue in the numFormat by creating a boolean property, setting it to true in the calculation function, and passing it to the numFormat condition:
if (displayNum.length > 16 || stringForm.length > 9 && resultActive) {
numFormat = "0.0000000000E0"
resultActive = false
}
This way the format only applies to calculated numbers
I also passed it to the addNum function for calculations made after the first calculation
if(resultActive) {
resultActive = false
}

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.

Getting Issue in xAxis.setValueFormatter with Dynamic value :

I am getting some issue Bar Graph with Dynamic values in X-Axis values setValueFormatter:
I checked with a list view, recycler view and view inflation but always getting issues in the values in X-Axis Formatter that it doesn't work with value when list size is 3 or less than 3.
With View Inflation:
Requirement: I want to set the values in a graph with a set of 8. Like, If my list size is 14,
So the graph view inflates 2 times like:
If my list size is 10, it will inflate 2 times, first with 8 values of bar graph and the second graph only with 2 values. It works for the same when the list size is 9, 8 values for the first graph and 1 value for the second graph.
But the issue is that when the remaining value for the last graph is less than 4 like:
when the list size is 11, the remaining value is 3
when the list size is 25, the remaining value is 1 for the fourth graph
It gives the repeated or duplicated value in the x Axis like this:
Here is the issue:
xAxis.setValueFormatter(object : IAxisValueFormatter {
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
var size : String = ""
try {
if(value>=0&&!mMonths[value.toInt()/10 % mMonths.size].equals("")&&value<mMonths.size*10) {
size = mMonths[0 / 10 % mMonths.size]
}
}catch (e : IndexOutOfBoundsException){
xAxis.isGranularityEnabled=false
}
return size
}
})
Note: This will work fine when mMonths list size is greater than 3 as you can see in the first screenshot but it gives issues for list size 1, 2 or 3.
Source code:
private fun setBarChart(mList:ArrayList) {
var calender_size: Float = 0.0f
if(mList.
size>0){
if(mList.size>8){
if(mList.size/8==0){
calender_size = (mList.size / 8).toFloat()
}else{
calender_size = (mList.size / 8).toFloat() + 1
}
}else{
calender_size = 1f
}
}
var section_variable: Int = 0
var tillvalue: Int = 0
var list_size: Int = 1
allGraphs.clear()
multiplegraphviewtmp.removeAllViews()
for (i in 0 until Math.round(calender_size)) {
val newLayout = layoutInflater.inflate(R.layout.new_functionalgraph, null, false)
multiplegraphviewtmp.addView(newLayout)
allGraphs.add(newLayout)
newLayout.tv_categoryname.setText(mList[0].description)
val entriesnew = ArrayList<BarEntry>()
entriesnew.clear()
var mMonths : ArrayList<String> = ArrayList()
mMonths.clear()
if(mList.size>8){
if (i > 0) {
if (mList.size / 8 == 0) {
list_size = (i + 1) * 8
} else {
val temp = mList.size % 8
if ((i + 1) * 8 < mList.size) {
list_size = (i + 1) * 8
} else {
// section_variable = section_variable + temp
list_size = list_size + temp
}
}
} else {
list_size = 8
}
for (j in section_variable until list_size) {
entriesnew.add(BarEntry((tillvalue * 10).toFloat(), mList[j].percentage.toFloat()))
mMonths.add(mList[j].itemName)
section_variable++
tillvalue++
}
tillvalue = 0
}else{
list_size=1
for (j in 0 until mList.size) {
entriesnew.add(BarEntry((tillvalue * 10).toFloat(), mList[j].percentage.toFloat()))
mMonths.add(mList[j].itemName)
//section_variable++
tillvalue++
}
tillvalue = 0
}
newLayout.barChartmore.legend.isEnabled = false
newLayout.barChartmore.description.isEnabled = false
var leftAxisfornewgraphs = newLayout.barChartmore.getAxisLeft()
leftAxisfornewgraphs.setAxisMaxValue(100f)
leftAxisfornewgraphs.setAxisMinValue(0f)
leftAxisfornewgraphs.setStartAtZero(true)
leftAxisfornewgraphs.setAxisLineWidth(0f)
leftAxisfornewgraphs.setLabelCount(11, true)
leftAxisfornewgraphs.setDrawGridLines(true)
leftAxisfornewgraphs.axisLineColor = activity!!.resources.getColor(R.color.graph_textColor)
leftAxisfornewgraphs.textColor = activity!!.resources.getColor(R.color.graph_textColor)
leftAxisfornewgraphs.typeface = Typeface.DEFAULT_BOLD
leftAxisfornewgraphs.textSize = 12f
leftAxisfornewgraphs.gridColor = activity!!.resources.getColor(R.color.view)
leftAxisfornewgraphs.axisLineColor = activity!!.resources.getColor(R.color.view)
// leftAxisfornewgraphs.setValueFormatter(MyYAxisValueFormatter()) //////////to set labels in %
//////////////////to change Right line/////////////////
var rightAxis = newLayout.barChartmore.axisRight
rightAxis.setDrawGridLines(false)
rightAxis.setDrawLabels(false)
rightAxis.setLabelCount(40, true)
rightAxis.axisLineColor = activity!!.resources.getColor(R.color.view)
var xAxis = newLayout.barChartmore.getXAxis()
xAxis.textSize = 9f
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM)
xAxis.setLabelRotationAngle(-90f)
xAxis.textColor = activity!!.resources.getColor(R.color.graph_textColor)
xAxis.typeface = Typeface.DEFAULT_BOLD
xAxis.gridColor = activity!!.resources.getColor(R.color.view)
xAxis.axisLineColor = activity!!.resources.getColor(R.color.view)
xAxis.granularity=1f
newLayout.barChartmore.setPinchZoom(false)
newLayout.barChartmore.getLegend().setWordWrapEnabled(true)
newLayout.barChartmore.setScaleEnabled(false)
newLayout.barChartmore.isDoubleTapToZoomEnabled=false
val labels = ArrayList<String>()
labels.clear()
for (i in 0 until mMonths.size){
labels.add("18-Jan")
}
xAxis.setValueFormatter(object : IAxisValueFormatter {
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
var size : String = ""
try {
if(value>=0&&!mMonths[value.toInt()/10 % mMonths.size].equals("")&&value<mMonths.size*10) {
size = mMonths[0 / 10 % mMonths.size]
mTotalvalues++
}
}catch (e : IndexOutOfBoundsException){
xAxis.isGranularityEnabled=false
}
return size
}
})
xAxis.spaceMin = 6f
xAxis.spaceMax = 6f
val barDataSet = BarDataSet(entriesnew, "Cells")
barDataSet.setDrawValues(false)
val list: ArrayList<Int> = ArrayList<Int>()
list.clear()
list.add(activity!!.resources.getColor(R.color.graph_skyblue))
list.add(activity!!.resources.getColor(R.color.graph_orange))
list.add(activity!!.resources.getColor(R.color.graph_navyBlue))
barDataSet.setColors(list)
val data = BarData(barDataSet);
if(mMonths.size<2){
data.barWidth= 1f
}else{
data.barWidth= 5f
}
newLayout.barChartmore.data = data
newLayout.barChartmore.invalidate()
newLayout.export_single.setOnClickListener(View.OnClickListener {
Commonclass.createPdf(activity, newLayout.barChartmore.chartBitmap)
})
//newLayout.barChartmore.clear()
}
}
Same Issue getting with recycler view and Listview. please help:
I am getting some issue Bar Graph with Dynamic values in XAxis values setValueFormatter

Placing dynamically added buttons below each other

I'm building a calculator app and in it there's a ScrollView, used to show and switch the buttons for operators and units whenever the user switches between modes.
The problem is that I didn't want to create a XML layout for each mode, so I thought of adding those buttons programmatically (which now, for me, seems pretty hard to accomplish). Here's the code that's supposed to add them:
// For each text in texts (which represents the modes), a Button is created and, if its id (represented by the index of its respective text in the list) is greater than 0, it is positioned below the previous one.
fun ScrollView.add(context: Context, input: EditText, texts: List<String>) {
removeAllViews()
val container = ConstraintLayout(context).apply {
layoutParams = ConstraintLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
topToTop = this#add.top
startToStart = this#add.left
endToEnd = this#add.right
}
}
val buttons: MutableList<Button> = mutableListOf()
texts.forEach { text ->
val button = Button(context)
val originalWidth = 60
val width = originalWidth.toDimension(context, COMPLEX_UNIT_DIP)
val originalHeight = 60
val height = originalHeight.toDimension(context, COMPLEX_UNIT_DIP)
with(button) {
layoutParams = ConstraintLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
id = texts.indexOf(text)
val previous = try { buttons[id - 1] } catch (exception: Exception) { this }
setWidth(width)
setHeight(height)
with(layoutParams as ConstraintLayout.LayoutParams) {
if (id == 0)
topToTop = this#add.top
else if (id > 0) {
layoutParams = RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
(layoutParams as RelativeLayout.LayoutParams).addRule(BELOW, previous.id)
}
}
left = this#add.left
right = this#add.right
button.text = text
isAllCaps = false
textSize = 25f
while (text().contains(System.getProperty("line.separator").toString())) textSize -= 5
setOnClickListener { input.input((it as Button).text()) }
setBackgroundResource(0)
container.addView(this)
buttons.add(this)
val buttonAdded = "[Dynamic List] Button $id added as \"$text\""
println(if (id == 0) "$buttonAdded." else "$buttonAdded. The button was positioned below \"${previous.text}\" (${previous.id}).")
}
}
addView(container)
}
And here's the code I implemented using the method above:
// Each calculator mode is represented by an Int within the list.
val modes = listOf("calculator" to 1, "length" to 2, "temperature" to 3, "time" to 4)
fun mode(context: Context, button: Button, input: EditText, view: ScrollView) {
var counter = 0
val operators = listOf("+", "-", times.toString(), division.toString())
val length = with(context) { listOf(getString(R.string.light_year), context.getString(R.string.kilometer), context.getString(R.string.hectometer), context.getString(R.string.decameter), context.getString(R.string.mile), context.getString(R.string.meter), context.getString(R.string.centimeter), context.getString(R.string.millimeter), context.getString(R.string.micrometer)) }
val temperature = with(context) { listOf(getString(R.string.celsius), context.getString(R.string.fahrenheit), context.getString(R.string.kevin), context.getString(R.string.rankine), context.getString(R.string.reaumur)) }
val time = with(context) { listOf(getString(R.string.year), context.getString(R.string.month), context.getString(R.string.day), context.getString(R.string.hour), context.getString(R.string.minute), context.getString(R.string.second), context.getString(R.string.millisecond)) }
with(button) {
setOnClickListener {
if (counter < modes.size - 1) counter++ else counter = 0
with(view) {
val mode: Pair<String, Int>? = modes[counter]
when (mode?.first) {
"calculator" -> add(context, input, operators)
"length" -> add(context, input, length)
"temperature" -> add(context, input, temperature)
"time" -> add(context, input, time)
}
text = with(context) {
with(resources) { getString(identify(context, mode?.first, "string")) }
}
}
}
}
}
Well, the problem is when I run it, the UI ends up looking like this, with all the buttons positioned at the same place:

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.

Categories

Resources