26 Commits
Author SHA1 Message Date
me c82fdd28cf Merge pull request '1.1.2' (#3) from dev into main
Reviewed-on: #3
2026-11-01 10:34:50 -07:00
me 169d30f81f changelog, add historic data from Releases page. 2026-11-01 10:33:58 -07:00
me 7799ce100c changelog, add file. 2026-11-01 10:31:41 -07:00
me 0935d7da52 main, fix app sometimes being underneath home row buttons (home, back, recent). 2026-11-01 10:27:35 -07:00
me b7a7be8a60 build, update version. 2026-11-01 10:27:08 -07:00
me c63416489c icon, fix Android Studio's screw up of the background color, color picker is bugged and fixing it in the XML afterwards did not do any sort of reapply. 2026-11-01 10:11:20 -07:00
me 4a237c8268 Merge pull request '1.1.1' (#2) from dev into main
Reviewed-on: #2
2026-11-01 09:58:58 -07:00
me bb8cc12fb7 icon, import via Android Studio so that it works on all versions of Android. 2026-11-01 09:55:54 -07:00
me b6d95f9268 Update versions and migrate to Kotlin Compose so that app compiles successfully, otherwise was in a stuck failed state due to deprecations. 2026-11-01 09:55:32 -07:00
me cbfa94131b Update Gradle. 2026-10-22 17:31:52 -07:00
me ab8959c3f4 fdroid, add specifier to email and put the field in the app-specific section. 2026-09-29 07:16:39 -07:00
me a1b7f180a2 Add more fdroid details while refactoring the file. 2026-07-04 15:00:56 -07:00
me c984624895 Update issue tracker to be proper HTTP link, use contact page. Change website page to go directly to the app. 2026-07-04 10:45:40 -07:00
me 6f68bc1b04 Add manifest file for fdroid server. 2026-07-03 17:34:51 -07:00
me e7b377bdb9 Merge pull request 'v1.1.0 - Update Android Target; Release Old Commits' (#1) from dev into main
Reviewed-on: #1
2025-08-17 09:35:20 -07:00
me 54dadb1f25 Run AGP Upgrade Assistant. 2025-08-17 09:18:07 -07:00
me f2ede2767d Remove extra whitespace. 2025-07-23 07:47:29 -07:00
me 59af3a2485 Fix location of app and its downloads. 2025-07-23 05:26:05 -07:00
me 5f40507a7d Upgrade gradle version. 2025-07-23 05:25:54 -07:00
me 920ee0d54c Upgrade minor versions since this release will include unreleased game changes. 2025-07-23 05:25:46 -07:00
me f992d25d29 AGP Upgrade Assistant. 2025-01-02 15:34:05 -07:00
me 6eb2811814 Update the GitHub button due to my migration off of there. ;) 2025-01-02 15:21:17 -07:00
me f552cc77a8 Increment the version before making any changes. 2025-01-02 15:20:27 -07:00
me 07cefd2776 Studio upgraded the gradle version. 2024-07-01 15:03:14 -07:00
me 59082be0cf Make the AI a little more consistent by using += instead of =. 2024-04-04 12:13:39 -07:00
me 31703cffb9 Fix UI being too tall for some devices. 2024-04-04 12:06:00 -07:00
42 changed files with 304 additions and 194 deletions

No files matched your search

+2 -2
View File
@@ -8,9 +8,9 @@ and maybe even make the game mad. 🐇🥚
## Download ## Download
App is hosted at [Hyperling.com](https://hyperling.com/home/#tictactoe) where App is hosted at [git.hyperling.com](https://git.hyperling.com/me/android-tictactoe) where
it is also available for it is also available for
[Direct Download](https://hyperling.com/files/apks/TicTacToe.apk). [Direct Download](https://git.hyperling.com/me/android-tictactoe/releases).
## TODO ## TODO
+28
View File
@@ -0,0 +1,28 @@
# Changelog
Update history of this app.
## 1.1.2
**More Fixes**
- Correctly apply background color 333333 to icons.
- Ensure activity sits above the navigation buttons on newer version of Android (if they exist).
## 1.1.0
**Fix App Icon**
- Fix app icon for some versions of Android.
- Update to the latest versions of internal plugins so that app can be compiled successfully.
- Now targets Android SDK 37.
## 1.1.0
**Update Android Target; Release Old Commits**
- Update to SDK 36.
- AI fixes and UI improvements.
- Correct download URL.
Note that this release uses a new key due to the old one not existing in the keystore.
+21 -14
View File
@@ -1,18 +1,19 @@
plugins { plugins {
alias(libs.plugins.androidApplication) alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid) //alias(libs.plugins.jetbrainsKotlinAndroid)
alias(libs.plugins.kotlinCompose)
} }
android { android {
namespace = "com.hyperling.tictactoe" namespace = "com.hyperling.tictactoe"
compileSdk = 34 compileSdk = 37
defaultConfig { defaultConfig {
applicationId = "com.hyperling.tictactoe" applicationId = "com.hyperling.tictactoe"
minSdk = 21 minSdk = 23
targetSdk = 34 targetSdk = 37
versionCode = 1 versionCode = 6
versionName = "1.0" versionName = "1.1.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
@@ -22,16 +23,17 @@ android {
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "1.8"
} }
buildFeatures { buildFeatures {
compose = true compose = true
@@ -47,7 +49,6 @@ android {
} }
dependencies { dependencies {
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)
@@ -63,4 +64,10 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4) androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
// 2026-11-01 - Fix for "unresolved reference" on these in MainActivity:
//import androidx.compose.material.icons.Icons
//import androidx.compose.material.icons.rounded.Close
implementation("androidx.compose.material:material-icons-core")
implementation("androidx.compose.material:material-icons-extended")
} }
+1 -2
View File
@@ -10,8 +10,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_icon_ttt" android:roundIcon="@mipmap/ic_icon_ttt"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.TicTacToe" android:theme="@style/Theme.TicTacToe">
tools:targetApi="31">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -7,6 +7,7 @@ import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -28,14 +29,20 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent { setContent {
TicTacToeTheme { TicTacToeTheme {
Surface { Box(Modifier.fillMaxSize().systemBarsPadding()) {
Game() Surface {
Game()
}
} }
} }
} }
@@ -194,8 +201,8 @@ fun Game() {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
, verticalArrangement = Arrangement.Center , verticalArrangement = Arrangement.Center
, modifier = Modifier //, modifier = Modifier
.fillMaxSize() // .fillMaxSize()
) { ) {
Spacer(modifier = Modifier.weight(0.1f)) Spacer(modifier = Modifier.weight(0.1f))
@@ -346,95 +353,112 @@ fun Game() {
fontSize = 16.sp fontSize = 16.sp
) )
Spacer(modifier = Modifier.size(5.dp)) Spacer(modifier = Modifier.size(5.dp))
Row (
Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { horizontalArrangement = Arrangement.SpaceEvenly
opponentHuman = setRadiosFalse() ) {
Column (
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.Top
) {
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentHuman = setRadiosFalse()
}
){
RadioButton(
selected = opponentHuman,
onClick = { opponentHuman = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_human),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentHard = setRadiosFalse()
}
){
RadioButton(
selected = opponentHard,
onClick = { opponentHard = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_hard),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentAnnoying = setRadiosFalse()
}
){
RadioButton(
selected = opponentAnnoying,
onClick = { opponentAnnoying = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_annoying),
fontSize = 16.sp
)
}
} }
){
RadioButton( Column (
selected = opponentHuman, horizontalAlignment = Alignment.Start,
onClick = { opponentHuman = setRadiosFalse() }, verticalArrangement = Arrangement.Bottom
) ) {
Text( Row (
text = stringResource(id = R.string.opponent_human), verticalAlignment = Alignment.CenterVertically,
fontSize = 16.sp modifier = Modifier.clickable {
) opponentRandom = setRadiosFalse()
} }
Row ( ){
verticalAlignment = Alignment.CenterVertically, RadioButton(
modifier = Modifier.clickable { selected = opponentRandom,
opponentRandom = setRadiosFalse() onClick = { opponentRandom = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_random),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentEasy = setRadiosFalse()
}
){
RadioButton(
selected = opponentEasy,
onClick = { opponentEasy = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_easy),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentShy = setRadiosFalse()
}
){
RadioButton(
selected = opponentShy,
onClick = { opponentShy = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_shy),
fontSize = 16.sp
)
}
} }
){
RadioButton(
selected = opponentRandom,
onClick = { opponentRandom = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_random),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentHard = setRadiosFalse()
}
){
RadioButton(
selected = opponentHard,
onClick = { opponentHard = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_hard),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentEasy = setRadiosFalse()
}
){
RadioButton(
selected = opponentEasy,
onClick = { opponentEasy = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_easy),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentAnnoying = setRadiosFalse()
}
){
RadioButton(
selected = opponentAnnoying,
onClick = { opponentAnnoying = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_annoying),
fontSize = 16.sp
)
}
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
opponentShy = setRadiosFalse()
}
){
RadioButton(
selected = opponentShy,
onClick = { opponentShy = setRadiosFalse() },
)
Text(
text = stringResource(id = R.string.opponent_shy),
fontSize = 16.sp
)
} }
} }
Spacer(modifier = Modifier.weight(.05f)) Spacer(modifier = Modifier.weight(.05f))
@@ -632,10 +656,10 @@ fun playWeightedMove(grid: MutableList<String>, behavior: Int, piece: String) :
// Easy, does not prevent human from winning and may try to win. // Easy, does not prevent human from winning and may try to win.
0 -> { 0 -> {
causeWin = 100 causeWin = 100
preventLoss = -1 preventLoss = -25
middle = 1 middle = 0
corner = 1 corner = 0
side = 1 side = 0
} }
// Hard, will try to win for itself and prevent the human from winning. // Hard, will try to win for itself and prevent the human from winning.
1 -> { 1 -> {
@@ -647,7 +671,7 @@ fun playWeightedMove(grid: MutableList<String>, behavior: Int, piece: String) :
} }
// Annoying / stubborn, will not let you win but also will not try to win. // Annoying / stubborn, will not let you win but also will not try to win.
2 -> { 2 -> {
causeWin = 99 causeWin = -25
preventLoss = 100 preventLoss = 100
middle = 4 middle = 4
corner = 3 corner = 3
@@ -655,11 +679,11 @@ fun playWeightedMove(grid: MutableList<String>, behavior: Int, piece: String) :
} }
// Shy, refuses to complete the game unless it's the only move left. // Shy, refuses to complete the game unless it's the only move left.
3 -> { 3 -> {
causeWin = -1 causeWin = -25
preventLoss = -1 preventLoss = -25
middle = 1 middle = 4
corner = 1 corner = 3
side = 1 side = 2
} }
// Random! No need for the other function anymore. ;) // Random! No need for the other function anymore. ;)
else -> { else -> {
@@ -680,132 +704,131 @@ fun playWeightedMove(grid: MutableList<String>, behavior: Int, piece: String) :
// Top Row, Win Conditions // Top Row, Win Conditions
if (grid[0] == piece && grid[1] == piece && grid[2].isBlank()) if (grid[0] == piece && grid[1] == piece && grid[2].isBlank())
weights[2] = causeWin weights[2] += causeWin
if (grid[0] == piece && grid[1].isBlank() && grid[2] == piece) if (grid[0] == piece && grid[1].isBlank() && grid[2] == piece)
weights[1] = causeWin weights[1] += causeWin
if (grid[0].isBlank() && grid[1] == piece && grid[2] == piece) if (grid[0].isBlank() && grid[1] == piece && grid[2] == piece)
weights[0] = causeWin weights[0] += causeWin
// Top Row, Lose Conditions // Top Row, Lose Conditions
if (grid[0] == human && grid[1] == human && grid[2].isBlank()) if (grid[0] == human && grid[1] == human && grid[2].isBlank())
weights[2] = preventLoss weights[2] += preventLoss
if (grid[0] == human && grid[1].isBlank() && grid[2] == human) if (grid[0] == human && grid[1].isBlank() && grid[2] == human)
weights[1] = preventLoss weights[1] += preventLoss
if (grid[0].isBlank() && grid[1] == human && grid[2] == human) if (grid[0].isBlank() && grid[1] == human && grid[2] == human)
weights[0] = preventLoss weights[0] += preventLoss
// Middle Row, Win Conditions // Middle Row, Win Conditions
if (grid[3] == piece && grid[4] == piece && grid[5].isBlank()) if (grid[3] == piece && grid[4] == piece && grid[5].isBlank())
weights[5] = causeWin weights[5] += causeWin
if (grid[3] == piece && grid[4].isBlank() && grid[5] == piece) if (grid[3] == piece && grid[4].isBlank() && grid[5] == piece)
weights[4] = causeWin weights[4] += causeWin
if (grid[3].isBlank() && grid[4] == piece && grid[5] == piece) if (grid[3].isBlank() && grid[4] == piece && grid[5] == piece)
weights[3] = causeWin weights[3] += causeWin
// Middle Row, Lose Conditions // Middle Row, Lose Conditions
if (grid[3] == human && grid[4] == human && grid[5].isBlank()) if (grid[3] == human && grid[4] == human && grid[5].isBlank())
weights[5] = preventLoss weights[5] += preventLoss
if (grid[3] == human && grid[4].isBlank() && grid[5] == human) if (grid[3] == human && grid[4].isBlank() && grid[5] == human)
weights[4] = preventLoss weights[4] += preventLoss
if (grid[3].isBlank() && grid[4] == human && grid[5] == human) if (grid[3].isBlank() && grid[4] == human && grid[5] == human)
weights[3] = preventLoss weights[3] += preventLoss
// Bottom Row, Win Conditions // Bottom Row, Win Conditions
if (grid[6] == piece && grid[7] == piece && grid[8].isBlank()) if (grid[6] == piece && grid[7] == piece && grid[8].isBlank())
weights[8] = causeWin weights[8] += causeWin
if (grid[6] == piece && grid[7].isBlank() && grid[8] == piece) if (grid[6] == piece && grid[7].isBlank() && grid[8] == piece)
weights[7] = causeWin weights[7] += causeWin
if (grid[6].isBlank() && grid[7] == piece && grid[8] == piece) if (grid[6].isBlank() && grid[7] == piece && grid[8] == piece)
weights[6] = causeWin weights[6] += causeWin
// Bottom Row, Lose Conditions // Bottom Row, Lose Conditions
if (grid[6] == human && grid[7] == human && grid[8].isBlank()) if (grid[6] == human && grid[7] == human && grid[8].isBlank())
weights[8] = preventLoss weights[8] += preventLoss
if (grid[6] == human && grid[7].isBlank() && grid[8] == human) if (grid[6] == human && grid[7].isBlank() && grid[8] == human)
weights[7] = preventLoss weights[7] += preventLoss
if (grid[6].isBlank() && grid[7] == human && grid[8] == human) if (grid[6].isBlank() && grid[7] == human && grid[8] == human)
weights[6] = preventLoss weights[6] += preventLoss
// Left Column, Win Conditions // Left Column, Win Conditions
if (grid[0] == piece && grid[3] == piece && grid[6].isBlank()) if (grid[0] == piece && grid[3] == piece && grid[6].isBlank())
weights[6] = causeWin weights[6] += causeWin
if (grid[0] == piece && grid[3].isBlank() && grid[6] == piece) if (grid[0] == piece && grid[3].isBlank() && grid[6] == piece)
weights[3] = causeWin weights[3] += causeWin
if (grid[0].isBlank() && grid[3] == piece && grid[6] == piece) if (grid[0].isBlank() && grid[3] == piece && grid[6] == piece)
weights[0] = causeWin weights[0] += causeWin
// Left Column, Lose Conditions // Left Column, Lose Conditions
if (grid[0] == human && grid[3] == human && grid[6].isBlank()) if (grid[0] == human && grid[3] == human && grid[6].isBlank())
weights[6] = preventLoss weights[6] += preventLoss
if (grid[0] == human && grid[3].isBlank() && grid[6] == human) if (grid[0] == human && grid[3].isBlank() && grid[6] == human)
weights[3] = preventLoss weights[3] += preventLoss
if (grid[0].isBlank() && grid[3] == human && grid[6] == human) if (grid[0].isBlank() && grid[3] == human && grid[6] == human)
weights[0] = preventLoss weights[0] += preventLoss
// Middle Column, Win Conditions // Middle Column, Win Conditions
if (grid[1] == piece && grid[4] == piece && grid[7].isBlank()) if (grid[1] == piece && grid[4] == piece && grid[7].isBlank())
weights[7] = causeWin weights[7] += causeWin
if (grid[1] == piece && grid[4].isBlank() && grid[7] == piece) if (grid[1] == piece && grid[4].isBlank() && grid[7] == piece)
weights[4] = causeWin weights[4] += causeWin
if (grid[1].isBlank() && grid[4] == piece && grid[7] == piece) if (grid[1].isBlank() && grid[4] == piece && grid[7] == piece)
weights[1] = causeWin weights[1] += causeWin
// Middle Column, Lose Conditions // Middle Column, Lose Conditions
if (grid[1] == human && grid[4] == human && grid[7].isBlank()) if (grid[1] == human && grid[4] == human && grid[7].isBlank())
weights[7] = preventLoss weights[7] += preventLoss
if (grid[1] == human && grid[4].isBlank() && grid[7] == human) if (grid[1] == human && grid[4].isBlank() && grid[7] == human)
weights[4] = preventLoss weights[4] += preventLoss
if (grid[1].isBlank() && grid[4] == human && grid[7] == human) if (grid[1].isBlank() && grid[4] == human && grid[7] == human)
weights[1] = preventLoss weights[1] += preventLoss
// Right Column, Win Conditions // Right Column, Win Conditions
if (grid[2] == piece && grid[5] == piece && grid[8].isBlank()) if (grid[2] == piece && grid[5] == piece && grid[8].isBlank())
weights[8] = causeWin weights[8] += causeWin
if (grid[2] == piece && grid[5].isBlank() && grid[8] == piece) if (grid[2] == piece && grid[5].isBlank() && grid[8] == piece)
weights[5] = causeWin weights[5] += causeWin
if (grid[2].isBlank() && grid[5] == piece && grid[8] == piece) if (grid[2].isBlank() && grid[5] == piece && grid[8] == piece)
weights[2] = causeWin weights[2] += causeWin
// Right Column, Lose Conditions // Right Column, Lose Conditions
if (grid[2] == human && grid[5] == human && grid[8].isBlank()) if (grid[2] == human && grid[5] == human && grid[8].isBlank())
weights[8] = preventLoss weights[8] += preventLoss
if (grid[2] == human && grid[5].isBlank() && grid[8] == human) if (grid[2] == human && grid[5].isBlank() && grid[8] == human)
weights[5] = preventLoss weights[5] += preventLoss
if (grid[2].isBlank() && grid[5] == human && grid[8] == human) if (grid[2].isBlank() && grid[5] == human && grid[8] == human)
weights[2] = preventLoss weights[2] += preventLoss
// Top Left Diagonal, Win Conditions // Top Left Diagonal, Win Conditions
if (grid[0] == piece && grid[4] == piece && grid[8].isBlank()) if (grid[0] == piece && grid[4] == piece && grid[8].isBlank())
weights[8] = causeWin weights[8] += causeWin
if (grid[0] == piece && grid[4].isBlank() && grid[8] == piece) if (grid[0] == piece && grid[4].isBlank() && grid[8] == piece)
weights[4] = causeWin weights[4] += causeWin
if (grid[0].isBlank() && grid[4] == piece && grid[8] == piece) if (grid[0].isBlank() && grid[4] == piece && grid[8] == piece)
weights[0] = causeWin weights[0] += causeWin
// Top Left Diagonal, Lose Conditions // Top Left Diagonal, Lose Conditions
if (grid[0] == human && grid[4] == human && grid[8].isBlank()) if (grid[0] == human && grid[4] == human && grid[8].isBlank())
weights[8] = preventLoss weights[8] += preventLoss
if (grid[0] == human && grid[4].isBlank() && grid[8] == human) if (grid[0] == human && grid[4].isBlank() && grid[8] == human)
weights[4] = preventLoss weights[4] += preventLoss
if (grid[0].isBlank() && grid[4] == human && grid[8] == human) if (grid[0].isBlank() && grid[4] == human && grid[8] == human)
weights[0] = preventLoss weights[0] += preventLoss
// Top Right Diagonal, Win Conditions // Top Right Diagonal, Win Conditions
if (grid[2] == piece && grid[4] == piece && grid[6].isBlank()) if (grid[2] == piece && grid[4] == piece && grid[6].isBlank())
weights[6] = causeWin weights[6] += causeWin
if (grid[2] == piece && grid[4].isBlank() && grid[6] == piece) if (grid[2] == piece && grid[4].isBlank() && grid[6] == piece)
weights[4] = causeWin weights[4] += causeWin
if (grid[2].isBlank() && grid[4] == piece && grid[6] == piece) if (grid[2].isBlank() && grid[4] == piece && grid[6] == piece)
weights[2] = causeWin weights[2] += causeWin
// Top Right Diagonal, Lose Conditions // Top Right Diagonal, Lose Conditions
if (grid[2] == human && grid[4] == human && grid[6].isBlank()) if (grid[2] == human && grid[4] == human && grid[6].isBlank())
weights[6] = preventLoss weights[6] += preventLoss
if (grid[2] == human && grid[4].isBlank() && grid[6] == human) if (grid[2] == human && grid[4].isBlank() && grid[6] == human)
weights[4] = preventLoss weights[4] += preventLoss
if (grid[2].isBlank() && grid[4] == human && grid[6] == human) if (grid[2].isBlank() && grid[4] == human && grid[6] == human)
weights[2] = preventLoss weights[2] += preventLoss
// */ // */
// Set all the played pieces to a very low number. // Set all the played pieces to a very low number.
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="273"
android:viewportHeight="168.75">
<group android:scaleX="0.46"
android:scaleY="0.28434065"
android:translateX="73.71"
android:translateY="60.38376">
<group android:translateY="133.59375">
<path android:pathData="M57.375,-102.375L57.375,-0L32.703125,-0L32.703125,-102.375L57.375,-102.375ZM88.171875,-102.375L88.171875,-83.328125L2.609375,-83.328125L2.609375,-102.375L88.171875,-102.375Z"
android:fillColor="#333333"/>
<path android:pathData="M148.375,-102.375L148.375,0L123.703125,0L123.703125,-102.375L148.375,-102.375ZM179.17188,-102.375L179.17188,-83.328125L93.609375,-83.328125L93.609375,-102.375L179.17188,-102.375Z"
android:fillColor="#333333"/>
<path android:pathData="M239.375,-102.375L239.375,0L214.70312,0L214.70312,-102.375L239.375,-102.375ZM270.17188,-102.375L270.17188,-83.328125L184.60938,-83.328125L184.60938,-102.375L270.17188,-102.375Z"
android:fillColor="#333333"/>
</group>
</group>
</vector>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" /> <monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" /> <monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#333333</color>
</resources>
+8 -8
View File
@@ -2,15 +2,15 @@
<string name="app_name">Tic-Tac-Toe</string> <string name="app_name">Tic-Tac-Toe</string>
<string name="opponent_header">Choose your opponent:</string> <string name="opponent_header">Choose your opponent:</string>
<string name="opponent_human">Human - Someone next to you.</string> <string name="opponent_human">Human</string>
<string name="opponent_random">AI : Random - Fills any open spot.</string> <string name="opponent_random">AI : Random</string>
<string name="opponent_hard">AI : Hard - Your typical try-hard.</string> <string name="opponent_hard">AI : Hard</string>
<string name="opponent_easy">AI : Easy - Opportunist, may try to win.</string> <string name="opponent_easy">AI : Easy</string>
<string name="opponent_annoying">AI : Stubborn - Won\'t let you win.</string> <string name="opponent_annoying">AI : Stubborn</string>
<string name="opponent_shy">AI : Shy - Too scared to win.</string> <string name="opponent_shy">AI : Shy</string>
<string name="link1_text">Website</string> <string name="link1_text">Website</string>
<string name="link1_uri">https://hyperling.com</string> <string name="link1_uri">https://hyperling.com</string>
<string name="link2_text">GitHub</string> <string name="link2_text">Source Code</string>
<string name="link2_uri">https://github.com/Hyperling/TicTacToeAndroid</string> <string name="link2_uri">https://git.hyperling.com/me/android-tictactoe</string>
</resources> </resources>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+2 -1
View File
@@ -1,5 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
alias(libs.plugins.androidApplication) apply false alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false //alias(libs.plugins.jetbrainsKotlinAndroid) apply false
alias(libs.plugins.kotlinCompose) apply false
} }
+16
View File
@@ -0,0 +1,16 @@
AuthorName: 'Chad Michael "Hyperling" Greenwood'
AuthorWebSite: 'https://hyperling.com/about/'
Donate: 'https://hyperling.com/donate/'
Liberapay: 'HyperVegan'
Bitcoin: 'bc1qsfe8dkvry3d34kztz449gkq67wq8fu2nkgfkh0'
Litecoin: 'ltc1qavmpu5d6ljntxsd6jj548m4yys83zwscl0dzkx'
IssueTracker: 'https://hyperling.com/contact/'
Categories:
- fdroid
- hyperling
- games
Name: Tic-Tac-Toe
AuthorEmail: 'me+tictactoe@hyperling.com'
Summary: 'Play against a friend or a range of AIs. Written to practice Kotlin/Compose.'
SourceCode: 'https://git.hyperling.com/me/android-tictactoe/'
WebSite: 'https://hyperling.com/apps/#tictactoe'
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c2dd35c9d0aaf0ba6ad0791320f99dfc/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/e5810bd7fd1f8a586644409d395a7e55/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7b3c4877c0749019e6805bb61e421497/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d76df094a9cbbabd3b08251f9e61444a/redirect
toolchainVersion=25
+10 -10
View File
@@ -1,13 +1,13 @@
[versions] [versions]
agp = "8.3.1" agp = "9.5.0"
kotlin = "1.9.0" kotlin = "2.4.21"
coreKtx = "1.10.1" coreKtx = "1.19.1"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.1.5" junitVersion = "1.3.0"
espressoCore = "3.5.1" espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.6.1" lifecycleRuntimeKtx = "2.11.0"
activityCompose = "1.7.0" activityCompose = "1.13.0"
composeBom = "2023.08.00" composeBom = "2026.09.00"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -27,5 +27,5 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
[plugins] [plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" } androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } #jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlinCompose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+2 -2
View File
@@ -1,6 +1,6 @@
#Sat Mar 30 12:28:25 MST 2024 #Sun Nov 01 08:44:00 MST 2026
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists