diff --git a/app/build.gradle b/app/build.gradle index 9c95df5..1c232ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,7 +24,7 @@ android { defaultConfig { applicationId "atorch.statspuzzles" - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 35 versionCode 32 versionName "4.0" @@ -51,18 +51,18 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'org.mariuszgromada.math:MathParser.org-mXparser:6.1.0' - implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.9.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.navigation:navigation-fragment:2.5.3' - implementation 'androidx.navigation:navigation-ui:2.5.3' + implementation 'androidx.appcompat:appcompat:1.7.1' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.constraintlayout:constraintlayout:2.2.1' + implementation 'androidx.navigation:navigation-fragment:2.9.5' + implementation 'androidx.navigation:navigation-ui:2.9.5' implementation 'androidx.viewpager2:viewpager2:1.1.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1' implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: []) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20" } diff --git a/app/libs/mXparser-v.4.2.0-jdk.1.7.jar b/app/libs/mXparser-v.4.2.0-jdk.1.7.jar deleted file mode 100644 index db068df..0000000 Binary files a/app/libs/mXparser-v.4.2.0-jdk.1.7.jar and /dev/null differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d67dd7..7b09c05 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,7 +2,7 @@ Probability Puzzles This is version 4.0, released in October 2025 — now with over ninety puzzles, zero ads, and translations in Spanish, German, and Arabic. Enjoy! \n\nSome of the puzzles in this app will be difficult if you haven\'t studied probability. Need to brush up? Have a look at this\u00A0Dartmouth book and these\u00A0MIT notes. You could also read through some probability problems at\u00A0math.stackexchange.com. If you prefer to watch lectures on youtube, try\u00A0these or\u00A0these. - \n\nThis app is full of math puzzles, and uses Mariusz Gromada\'s mXparser version 4.2.0 to translate mathematical expressions to numbers: it\'ll understand .2, 0.2, 20\%, or 1/5. The parser also understands factorials and binomial coefficients: try typing 5!/(3!*2!) or\u00A0C(5,3) with a capital C for \"5 choose 3.\" You can also type lowercase e for the base of the natural logarithm. Visit\u00A0mathparser.org for more information. + \n\nThis app is full of math puzzles, and uses Mariusz Gromada\'s mXparser version 6.1.0 to translate mathematical expressions to numbers: it\'ll understand .2, 0.2, 20\%, or 1/5. The parser also understands factorials and binomial coefficients: try typing 5!/(3!*2!) or\u00A0C(5,3) with a capital C for \"5 choose 3.\" You can also type lowercase e for the base of the natural logarithm. Visit\u00A0mathparser.org for more information. \n\nIf you\'d like to contribute to the app (or peek at solutions), have a look at its\u00A0github repo! Challenge yourself with probability puzzles — install the app at https://play.google.com/store/apps/details?id=atorch.statspuzzles diff --git a/app/src/test/java/atorch/statspuzzles/AnswerCheckerTest.java b/app/src/test/java/atorch/statspuzzles/AnswerCheckerTest.java index a97c1de..b86f911 100644 --- a/app/src/test/java/atorch/statspuzzles/AnswerCheckerTest.java +++ b/app/src/test/java/atorch/statspuzzles/AnswerCheckerTest.java @@ -7,8 +7,8 @@ public class AnswerCheckerTest { @Test public void testCorrectAnswer() { - assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("2+2", "4")); - assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/2", "0.5")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("2 + 2", "4")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/ 2", "0.5")); assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("3!", "6.0")); assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/(3!)", "0.16666666")); // Note that we have a Result.INACCURATE version of this test as well @@ -16,6 +16,84 @@ public void testCorrectAnswer() { assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(5, 3)", "10")); } + @Test + public void testCombinations() { + // Test various combination expressions that users might enter + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(8, 6)", "28")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(10, 2)", "45")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(52, 5)", "2598960")); + } + + @Test + public void testEulersNumber() { + // Test expressions involving e + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/e", "0.36787944")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("e^2", "7.389056")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1-1/e", "0.63212056")); + } + + @Test + public void testNegativeExponents() { + // Test negative exponents that users might enter + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("4^-1", "0.25")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("2^-3", "0.125")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("10 ^ -2", "0.01")); + } + + @Test + public void testPercentages() { + // Test percentage expressions + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("50%", "0.5")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("25%", "0.25")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("100%", "1")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1%", "0.01")); + } + + @Test + public void testSpacingAndEquivalentExpressions() { + // Test that spacing variations and mathematically equivalent expressions are accepted + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(7,3)", "C(7, 3)")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(7, 3)", "C(7,4)")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("4!", "4 * 3!")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("12!/(4!*4!*4!)", "12! / ((4!)^3)")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/2 + (1/2)*49/99", "1/2+(49/2) * 1/99")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("(4/52)*(3/51)", "( 4 * 3 ) / (51 *52)")); + } + + @Test + public void testEquivalentFormats() { + // Test that the app accepts equivalent formats as documented in the intro + // .2, 0.2, 20%, and 1/5 should all be equivalent + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.2", ".2")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.2", "20%")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.2", "1/5")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("1/5", "20%")); + + // .4, 0.4, 40%, 4/10, and 2*1/5 should all be equivalent + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.4", ".4")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.4", "40%")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.4", "4/10")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("0.4", "2*1/5")); + + // Factorial equivalents: 4! = 4*3*2 = 24 + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("4!", "4*3*2")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("4!", "24")); + + // Combination equivalents: C(5,3) = 5!/(3!*2!) + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("C(5,3)", "5!/(3!*2!)")); + + // Exponent equivalents: .49^3 = .49*.49*.49 + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer(".49^3", ".49*.49*.49")); + } + + @Test + public void testPiConstant() { + // Test that pi constant works + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("pi", "3.14159265")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("pi / 4", "0.78539816")); + assertEquals(AnswerChecker.Result.CORRECT, AnswerChecker.checkAnswer("2*pi", "6.28318531")); + } + @Test public void testInaccurateAnswer() { assertEquals(AnswerChecker.Result.INACCURATE, AnswerChecker.checkAnswer("1/3", "0.333")); @@ -24,6 +102,7 @@ public void testInaccurateAnswer() { @Test public void testIncorrectAnswer() { assertEquals(AnswerChecker.Result.INCORRECT, AnswerChecker.checkAnswer("1", "2")); + assertEquals(AnswerChecker.Result.INCORRECT, AnswerChecker.checkAnswer("0.50", "0.49")); // The user's answer is not close enough to be considered merely inaccurate. assertEquals(AnswerChecker.Result.INCORRECT, AnswerChecker.checkAnswer("1/3", "0.33")); }