21 Commits
Author SHA1 Message Date
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
41 changed files with 268 additions and 193 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
+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 = 5
versionName = "1.0" versionName = "1.1.1"
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")
} }
+2 -3
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"
@@ -27,4 +26,4 @@
</activity> </activity>
</application> </application>
</manifest> </manifest>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -194,8 +194,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 +346,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 +649,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 +664,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 +672,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 +697,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